Skip to content
Snippets Groups Projects
Commit 1f7fdcd1 authored by Daniel Stone's avatar Daniel Stone
Browse files

Bring burndown view under core projects


Instead of having Sprint as a separate app which duplicates the entirety
of Projects, bring it under the purview of the projects application.

Signed-off-by: Daniel Stone's avatarDaniel Stone <daniels@collabora.com>

Differential Revision: https://phabricator.collabora.co.uk/D511
parent 97c9d99f
No related branches found
No related tags found
No related merge requests found
Showing
with 41 additions and 996 deletions
......@@ -30,18 +30,15 @@ phutil_register_library_map(array(
'SprintConstants' => 'constants/SprintConstants.php',
'SprintController' => 'controller/SprintController.php',
'SprintControllerTest' => 'tests/SprintControllerTest.php',
'SprintCreateConduitAPIMethod' => 'conduit/SprintCreateConduitAPIMethod.php',
'SprintCustomFieldTest' => 'tests/SprintCustomFieldTest.php',
'SprintDAO' => 'storage/SprintDAO.php',
'SprintDataView' => 'view/burndown/SprintDataView.php',
'SprintDataViewController' => 'controller/SprintDataViewController.php',
'SprintDefaultViewCapability' => 'capability/SprintDefaultViewCapability.php',
'SprintEndDateField' => 'customfield/SprintEndDateField.php',
'SprintException' => 'exception/SprintException.php',
'SprintGetIsSprintConduitAPIMethod' => 'conduit/SprintGetIsSprintConduitAPIMethod.php',
'SprintGetStartEndDatesConduitAPIMethod' => 'conduit/SprintGetStartEndDatesConduitAPIMethod.php',
'SprintGetTaskProjectHistoryConduitAPIMethod' => 'conduit/SprintGetTaskProjectHistoryConduitAPIMethod.php',
'SprintHandleIconView' => 'view/SprintHandleIconView.php',
'SprintHistoryController' => 'controller/SprintHistoryController.php',
'SprintHistoryDataProvider' => 'storage/SprintHistoryDataProvider.php',
'SprintHistoryTableView' => 'view/reports/SprintHistoryTableView.php',
......@@ -53,11 +50,9 @@ phutil_register_library_map(array(
'SprintManiphestConduitAPIMethod' => 'conduit/SprintManiphestConduitAPIMethod.php',
'SprintManiphestQueryConduitAPIMethod' => 'conduit/SprintManiphestQueryConduitAPIMethod.php',
'SprintPoints' => 'util/SprintPoints.php',
'SprintProjectController' => 'controller/SprintProjectController.php',
'SprintProjectBoardController' => 'controller/SprintProjectBoardController.php',
'SprintProjectCustomField' => 'customfield/SprintProjectCustomField.php',
'SprintProjectProfileController' => 'controller/SprintProjectProfileController.php',
'SprintProjectProfilePanel' => 'profilepanel/SprintProjectProfilePanel.php',
'SprintProjectProfilePanelEngine' => 'engine/SprintProjectProfilePanelEngine.php',
'SprintProjectViewController' => 'controller/SprintProjectViewController.php',
'SprintQuery' => 'query/SprintQuery.php',
'SprintQueryTest' => 'tests/SprintQueryTest.php',
......@@ -95,18 +90,15 @@ phutil_register_library_map(array(
'SprintConfigOptions' => 'PhabricatorApplicationConfigOptions',
'SprintController' => 'PhabricatorController',
'SprintControllerTest' => 'SprintTestCase',
'SprintCreateConduitAPIMethod' => 'SprintConduitAPIMethod',
'SprintCustomFieldTest' => 'SprintTestCase',
'SprintDAO' => 'PhabricatorLiskDAO',
'SprintDataView' => 'SprintView',
'SprintDataViewController' => 'SprintController',
'SprintDefaultViewCapability' => 'PhabricatorPolicyCapability',
'SprintEndDateField' => 'SprintProjectCustomField',
'SprintException' => 'AphrontException',
'SprintGetIsSprintConduitAPIMethod' => 'SprintConduitAPIMethod',
'SprintGetStartEndDatesConduitAPIMethod' => 'SprintConduitAPIMethod',
'SprintGetTaskProjectHistoryConduitAPIMethod' => 'SprintConduitAPIMethod',
'SprintHandleIconView' => 'AphrontTagView',
'SprintHistoryController' => 'SprintController',
'SprintHistoryTableView' => 'SprintView',
'SprintInfoConduitAPIMethod' => 'SprintManiphestConduitAPIMethod',
......@@ -116,14 +108,12 @@ phutil_register_library_map(array(
'SprintManiphestConduitAPIMethod' => 'ConduitAPIMethod',
'SprintManiphestQueryConduitAPIMethod' => 'SprintManiphestConduitAPIMethod',
'SprintPoints' => 'Phobject',
'SprintProjectController' => 'SprintController',
'SprintProjectBoardController' => 'SprintController',
'SprintProjectCustomField' => array(
'PhabricatorProjectCustomField',
'PhabricatorStandardCustomFieldInterface',
),
'SprintProjectProfileController' => 'SprintProjectController',
'SprintProjectProfilePanel' => 'PhabricatorProfilePanel',
'SprintProjectProfilePanelEngine' => 'PhabricatorProfilePanelEngine',
'SprintProjectViewController' => 'SprintController',
'SprintQuery' => 'SprintDAO',
'SprintQueryTest' => 'SprintTestCase',
......
......@@ -26,43 +26,19 @@ final class SprintApplication extends PhabricatorApplication {
public function getRoutes() {
return array(
// this is the default application route controller
'/project/sprint/' => array(
// redirects to core projects app
'' => 'SprintListController',
// these are native Sprint application controllers
'burn/(?P<id>\d+)/' => 'SprintDataViewController',
'profile/(?P<id>[1-9]\d*)/'
=> 'SprintProjectProfileController',
'board/(?P<id>\d+)/' => 'SprintProjectBoardController',
// still contained within Sprint all
'burn/(?P<id>\d+)/' => 'SprintDataViewController',
'view/(?P<id>\d+)/' => 'SprintDataViewController',
'report/list/' => 'SprintListController',
'report/history/' => 'SprintHistoryController',
'report/(?:(?P<view>\w+)/)?' => 'SprintReportController',
'view/(?P<id>\d+)/' => 'SprintDataViewController',
),
);
}
protected function getCustomCapabilities() {
return array(
SprintDefaultViewCapability::CAPABILITY => array(
'caption' => pht(
'Default view policy for newly created sprints.'),
),
ProjectCreateProjectsCapability::CAPABILITY => array(),
ProjectCanLockProjectsCapability::CAPABILITY => array(
'default' => PhabricatorPolicies::POLICY_ADMIN,
),
ManiphestDefaultViewCapability::CAPABILITY => array(
'caption' => pht('Default view policy for newly created tasks.'),
),
ManiphestDefaultEditCapability::CAPABILITY => array(
'caption' => pht('Default edit policy for newly created tasks.'),
),
ManiphestEditStatusCapability::CAPABILITY => array(),
ManiphestEditAssignCapability::CAPABILITY => array(),
ManiphestEditPoliciesCapability::CAPABILITY => array(),
ManiphestEditPriorityCapability::CAPABILITY => array(),
ManiphestEditProjectsCapability::CAPABILITY => array(),
ManiphestBulkEditCapability::CAPABILITY => array(),
);
}
}
<?php
final class SprintDefaultViewCapability
extends PhabricatorPolicyCapability {
const CAPABILITY = 'sprint.default.view';
public function getCapabilityName() {
return pht('Default View Policy');
}
public function shouldAllowPublicPolicySetting() {
return true;
}
}
<?php
final class SprintCreateConduitAPIMethod extends SprintConduitAPIMethod {
public function getAPIMethodName() {
return 'sprint.create';
}
public function getMethodDescription() {
return pht('Create a Sprint Project');
}
public function defineParamTypes() {
return array(
'name' => 'required string ("name")',
'members' => 'optional list ([<phid>]) - empty list enter []',
'startdate' => 'required string ("YYYY-MM-DD H:i")',
'enddate' => 'required string ("YYYY-MM-DD H:i")',
);
}
public function defineReturnType() {
return 'dict';
}
public function defineErrorTypes() {
return array();
}
protected function execute(ConduitAPIRequest $request) {
$user = $request->getUser();
$this->requireApplicationCapability(
ProjectCreateProjectsCapability::CAPABILITY,
$user);
$project = PhabricatorProject::initializeNewProject($user);
$type_name = PhabricatorProjectTransaction::TYPE_NAME;
$members = $request->getValue('members');
$xactions = array();
$xactions[] = id(new PhabricatorProjectTransaction())
->setTransactionType($type_name)
->setNewValue($request->getValue('name'));
$xactions[] = id(new PhabricatorProjectTransaction())
->setTransactionType(PhabricatorTransactions::TYPE_EDGE)
->setMetadataValue(
'edge:type',
PhabricatorProjectProjectHasMemberEdgeType::EDGECONST)
->setNewValue(
array(
'+' => array_fuse($members),
));
$xactions[] = id(new PhabricatorProjectTransaction())
->setTransactionType(PhabricatorProjectTransaction::TYPE_ICON)
->setNewValue('fa-calendar');
$xactions[] = id(new PhabricatorProjectTransaction())
->setTransactionType(PhabricatorProjectTransaction::TYPE_COLOR)
->setNewValue('green');
$xactions[] = id(new PhabricatorProjectTransaction())
->setTransactionType(PhabricatorTransactions::TYPE_CUSTOMFIELD)
->setMetadataValue('customfield:key', 'isdc:sprint:issprint')
->setOldValue(null)
->setNewValue(1);
$xactions[] = id(new PhabricatorProjectTransaction())
->setTransactionType(PhabricatorTransactions::TYPE_CUSTOMFIELD)
->setMetadataValue('customfield:key', 'isdc:sprint:startdate')
->setOldValue(null)
->setNewValue(strtotime($request->getValue('startdate')));
$xactions[] = id(new PhabricatorProjectTransaction())
->setTransactionType(PhabricatorTransactions::TYPE_CUSTOMFIELD)
->setMetadataValue('customfield:key', 'isdc:sprint:enddate')
->setOldValue(0)
->setNewValue(strtotime($request->getValue('enddate')));
$editor = id(new PhabricatorProjectTransactionEditor())
->setActor($user)
->setContinueOnNoEffect(true)
->setContentSource($request->newContentSource());
$editor->applyTransactions($project, $xactions);
return $this->buildProjectInfoDictionary($project);
}
}
......@@ -12,10 +12,6 @@ abstract class SprintController extends PhabricatorController {
return true;
}
public function getProjectsURI() {
return '/project/';
}
public function getUser() {
return $this->getRequest()->getUser();
}
......@@ -24,92 +20,6 @@ abstract class SprintController extends PhabricatorController {
return new PhutilURI($this->getApplicationURI());
}
public function buildApplicationMenu() {
return $this->buildSprintNavView($this->getUser(),
$this->setApplicationURI(), true)->getMenu();
}
public function buildNavMenu() {
$nav = id(new AphrontSideNavFilterView())
->setBaseURI(new PhutilURI($this->getApplicationURI().'report/'))
->addLabel(pht('Sprint Projects'))
->addFilter('list', pht('List'))
->addLabel(pht('Open Tasks'))
->addFilter('project', pht('By Project'))
->addFilter('user', pht('By User'))
->addLabel(pht('Burn Up'))
->addFilter('burn', pht('Burn Up Rate'))
->addFilter('history', pht('Task Project History'));
return $nav;
}
/**
* @param PhutilURI $uri
*/
public function buildSprintNavView($viewer, $uri, $for_app = false) {
$request = $this->getRequest();
$id = $request->getURIData('id');
$slug = $request->getURIData('slug');
if ($slug) {
$id = $this->getProjectIDfromSlug($slug, $viewer);
}
$nav = new AphrontSideNavFilterView();
$nav->setBaseURI($uri);
if ($for_app) {
if ($id) {
$nav->addFilter("profile/{$id}/", pht('Profile'));
$nav->addFilter("board/{$id}/", pht('Workboard'));
$nav->addFilter("members/{$id}/", pht('Members'));
$nav->addFilter("feed/{$id}/", pht('Feed'));
$nav->addFilter("details/{$id}/", pht('Edit Details'));
}
$nav->addFilter('create', pht('Create Project'));
}
id(new PhabricatorProjectSearchEngine())
->setViewer($viewer)
->addNavigationItems($nav->getMenu());
if ($viewer->isLoggedIn()) {
$nav->addLabel(pht('Sprints'));
$nav->addFilter('report/list', pht('Sprint List'));
}
$nav->selectFilter(null);
return $nav;
}
protected function buildSprintApplicationCrumbs($can_create) {
$crumbs = $this->buildCrumbs('fa-bar-chart', $this->getApplicationURI());
$crumbs->addAction(
id(new PHUIListItemView())
->setName(pht('Create Sprint'))
->setHref('/conduit/method/sprint.create/')
->setIcon('fa-calendar')
->setDisabled(!$can_create));
return $crumbs;
}
protected function buildCrumbs($sprite, $uri) {
$crumbs = array();
$crumbs[] = id(new PHUICrumbView())
->setHref($uri)
->setAural($sprite)
->setIcon($sprite);
$view = new PHUICrumbsView();
foreach ($crumbs as $crumb) {
$view->addCrumb($crumb);
}
return $view;
}
public function getProjectIDfromSlug($slug, $viewer) {
$project = id(new PhabricatorProjectQuery())
->setViewer($viewer)
......
......@@ -13,7 +13,7 @@ final class SprintDataViewController extends SprintController {
if ($project) {
$viewer = $this->getViewer();
$engine = id(new SprintProjectProfilePanelEngine())
$engine = id(new PhabricatorProjectProfilePanelEngine())
->setViewer($viewer)
->setProfileObject($project);
......@@ -41,13 +41,10 @@ final class SprintDataViewController extends SprintController {
$error_box = $this->getErrorBox($e);
}
$can_create = $this->hasApplicationCapability(
ProjectCreateProjectsCapability::CAPABILITY);
$crumbs = $this->getCrumbs($can_create);
$crumbs = $this->getCrumbs();
$nav = $this->getProfileMenu($this->project);
return $this->newPage()
->setNavigation($nav)
->setCrumbs($crumbs)
->setTitle($this->project->getName())
->setPageObjectPHIDs(array($this->project->getPHID()))
->appendChild($error_box)
......@@ -64,9 +61,8 @@ final class SprintDataViewController extends SprintController {
return $project;
}
public function getCrumbs($can_create) {
$crumbs = $this->buildSprintApplicationCrumbs($can_create);
public function getCrumbs() {
$crumbs = new PHUICrumbsView();
$crumbs->addTextCrumb(
$this->project->getName(),
$this->getApplicationURI().'profile/'.$this->projectID);
......
<?php
final class SprintHistoryController extends SprintController {
private $view;
private $viewer;
public function handleRequest(AphrontRequest $request) {
$this->viewer = $request->getViewer();
if ($request->isFormPost()) {
$uri = $request->getRequestURI();
$project = head($request->getArr('set_project'));
$project = nonempty($project, null);
$uri = $uri->alter('project', $project);
$window = $request->getStr('set_window');
$uri = $uri->alter('window', $window);
return id(new AphrontRedirectResponse())->setURI($uri);
}
$error_box = null;
$sprintlist_table = null;
$history_model = id(new SprintHistoryDataProvider())
->setViewer($this->viewer)
->setRequest($request)
->execute();
try {
$sprintlist_table = id(new SprintHistoryTableView())
->setViewer($this->viewer)
->setRequest($request)
->setTableData($history_model)
->render();
} catch (Exception $e) {
$error_box = $this->getErrorBox($e);
}
$can_create = $this->hasApplicationCapability(
ProjectCreateProjectsCapability::CAPABILITY);
$crumbs = $this->buildSprintApplicationCrumbs($can_create);
$crumbs->addTextCrumb(pht('Task Project History'));
$help = id(new PHUIBoxView())
->appendChild(phutil_tag('p', array(),
'This is a history of tasks and logs when a project was added or removed'))
->appendChild(phutil_tag('br', array(), ''))
->appendChild(phutil_tag('p', array(),
'NOTE: The tasks are selected from the current tasks in the project. Tasks previously removed
will not appear!'))
->addMargin(PHUI::MARGIN_LARGE);
$nav = $this->buildNavMenu();
$this->view = $nav->selectFilter($this->view, 'history');
$nav->appendChild(
array(
$error_box,
$crumbs,
$help,
$sprintlist_table,
));
$title = pht('Task Project History');
return $this->newPage()
->setTitle($title)
->appendChild($nav);
}
}
<?php
final class SprintListController extends SprintController {
private $view;
private $viewer;
public function handleRequest(AphrontRequest $request) {
$this->viewer = $request->getViewer();
$error_box = null;
$sprintlist_model = id(new SprintListDataProvider())
->setViewer($this->viewer)
->setRequest($request)
->execute();
try {
$sprintlist_table = id(new SprintListTableView())
->setTableData($sprintlist_model)
->buildProjectsTable();
} catch (Exception $e) {
$error_box = $this->getErrorBox($e);
}
$can_create = $this->hasApplicationCapability(
ProjectCreateProjectsCapability::CAPABILITY);
$crumbs = $this->buildSprintApplicationCrumbs($can_create);
$crumbs->addTextCrumb(pht('Sprint Burndown List'));
$uri = $request->getRequestURI();
$uri->setPath('/project/');
$help = id(new PHUIBoxView())
->appendChild(phutil_tag('p', array(),
'To have a project show up in this list, make sure that the'
.'"Is Sprint" box has been checked in Project Edit Details'))
->addMargin(PHUI::MARGIN_LARGE);
$nav = $this->buildNavMenu();
$this->view = $nav->selectFilter($this->view, 'list');
$nav->appendChild(
array(
$error_box,
$crumbs,
$help,
$sprintlist_table,
));
$title = pht('Sprint List');
return $this->newPage()
->setTitle($title)
->appendChild($nav);
return id(new AphrontRedirectResponse())->setURI($uri);
}
}
<?php
final class SprintProjectBoardController
extends SprintController {
public function shouldAllowPublic() {
return true;
}
public function handleRequest(AphrontRequest $request) {
$uri = $request->getRequestURI();
$projectID = $request->getURIData('id');
$uri->setPath("/project/board/{$projectID}/");
return id(new AphrontRedirectResponse())->setURI($uri);
}
}
<?php
abstract class SprintProjectController extends SprintController {
private $project;
private $profileMenu;
const PANEL_BURNDOWN = 'project.sprint';
protected function setProject(PhabricatorProject $project) {
$this->project = $project;
return $this;
}
protected function getProject() {
return $this->project;
}
protected function loadProject() {
$viewer = $this->getViewer();
$request = $this->getRequest();
$id = nonempty(
$request->getURIData('projectID'),
$request->getURIData('id'));
$slug = $request->getURIData('slug');
if ($slug) {
$normal_slug = PhabricatorSlug::normalizeProjectSlug($slug);
$is_abnormal = ($slug !== $normal_slug);
$normal_uri = "/tag/{$normal_slug}/";
} else {
$is_abnormal = false;
}
$query = id(new PhabricatorProjectQuery())
->setViewer($viewer)
->needMembers(true)
->needWatchers(true)
->needImages(true)
->needSlugs(true);
if ($slug) {
$query->withSlugs(array($slug));
} else {
$query->withIDs(array($id));
}
$policy_exception = null;
try {
$project = $query->executeOne();
} catch (PhabricatorPolicyException $ex) {
$policy_exception = $ex;
$project = null;
}
if (!$project) {
// This project legitimately does not exist, so just 404 the user.
if (!$policy_exception) {
return new Aphront404Response();
}
// Here, the project exists but the user can't see it. If they are
// using a non-canonical slug to view the project, redirect to the
// canonical slug. If they're already using the canonical slug, rethrow
// the exception to give them the policy error.
if ($is_abnormal) {
return id(new AphrontRedirectResponse())->setURI($normal_uri);
} else {
throw $policy_exception;
}
}
// The user can view the project, but is using a noncanonical slug.
// Redirect to the canonical slug.
$primary_slug = $project->getPrimarySlug();
if ($slug && ($slug !== $primary_slug)) {
$primary_uri = "/tag/{$primary_slug}/";
return id(new AphrontRedirectResponse())->setURI($primary_uri);
}
$this->setProject($project);
return null;
}
public function buildApplicationMenu() {
$menu = $this->newApplicationMenu();
$profile_menu = $this->getProfileMenu();
if ($profile_menu) {
$menu->setProfileMenu($profile_menu);
}
$menu->setSearchEngine(new PhabricatorProjectSearchEngine());
return $menu;
}
protected function getProfileMenu() {
if (!$this->profileMenu) {
$project = $this->getProject();
if ($project) {
$viewer = $this->getViewer();
$engine = id(new SprintProjectProfilePanelEngine())
->setViewer($viewer)
->setProfileObject($project);
$this->profileMenu = $engine->buildNavigation();
}
}
return $this->profileMenu;
}
public function buildSideNavView($for_app = false) {
$project = $this->getProject();
$nav = new AphrontSideNavFilterView();
$nav->setBaseURI(new PhutilURI($this->getApplicationURI()));
$viewer = $this->getViewer();
$id = null;
if ($for_app) {
if ($project) {
$id = $project->getID();
$nav->addFilter("profile/{$id}/", pht('Profile'));
$nav->addFilter("board/{$id}/", pht('Workboard'));
$nav->addFilter("members/{$id}/", pht('Members'));
$nav->addFilter("feed/{$id}/", pht('Feed'));
$nav->addFilter("details/{$id}/", pht('Edit Details'));
}
$nav->addFilter('create', pht('Create Project'));
}
if (!$id) {
id(new PhabricatorProjectSearchEngine())
->setViewer($viewer)
->addNavigationItems($nav->getMenu());
}
$nav->selectFilter(null);
return $nav;
}
protected function buildApplicationCrumbs() {
$crumbs = parent::buildApplicationCrumbs();
$project = $this->getProject();
if ($project) {
$ancestors = $project->getAncestorProjects();
$ancestors = array_reverse($ancestors);
$ancestors[] = $project;
foreach ($ancestors as $ancestor) {
$crumbs->addTextCrumb(
$project->getName(),
$project->getURI());
}
}
return $crumbs;
}
}
<?php
final class SprintProjectProfileController
extends SprintProjectController {
public function shouldAllowPublic() {
return true;
}
public function handleRequest(AphrontRequest $request) {
$viewer = $request->getViewer();
$response = $this->loadProject();
if ($response) {
return $response;
}
$project = $this->getProject();
$id = $project->getID();
$picture = $project->getProfileImageURI();
$icon = $project->getDisplayIconIcon();
$icon_name = $project->getDisplayIconName();
$tag = id(new PHUITagView())
->setIcon($icon)
->setName($icon_name)
->addClass('project-view-header-tag')
->setType(PHUITagView::TYPE_SHADE);
$header = id(new PHUIHeaderView())
->setHeader(array($project->getDisplayName(), $tag))
->setViewer($viewer)
->setPolicyObject($project)
->setImage($picture)
->setProfileHeader(true);
if ($project->getStatus() == PhabricatorProjectStatus::STATUS_ACTIVE) {
$header->setStatus('fa-check', 'bluegrey', pht('Active'));
} else {
$header->setStatus('fa-ban', 'red', pht('Archived'));
}
$can_edit = PhabricatorPolicyFilter::hasCapability(
$viewer,
$project,
PhabricatorPolicyCapability::CAN_EDIT);
if ($can_edit) {
$header->setImageEditURL($this->getApplicationURI("picture/{$id}/"));
}
$properties = $this->buildPropertyListView($project);
$watch_action = $this->renderWatchAction($project);
$header->addActionLink($watch_action);
$milestone_list = $this->buildMilestoneList($project);
$subproject_list = $this->buildSubprojectList($project);
$member_list = id(new PhabricatorProjectMemberListView())
->setViewer($viewer)
->setProject($project)
->setLimit(5)
->setBackground(PHUIBoxView::GREY)
->setUserPHIDs($project->getMemberPHIDs());
$watcher_list = id(new PhabricatorProjectWatcherListView())
->setViewer($viewer)
->setProject($project)
->setLimit(5)
->setBackground(PHUIBoxView::GREY)
->setUserPHIDs($project->getWatcherPHIDs());
$nav = $this->getProfileMenu();
$nav->selectFilter(PhabricatorProject::PANEL_PROFILE);
$stories = id(new PhabricatorFeedQuery())
->setViewer($viewer)
->setFilterPHIDs(
array(
$project->getPHID(),
))
->setLimit(50)
->execute();
$feed = $this->renderStories($stories);
$feed = phutil_tag_div('project-view-feed', $feed);
$columns = id(new PHUITwoColumnView())
->setMainColumn(
array(
$properties,
$feed,
))
->setSideColumn(
array(
$milestone_list,
$subproject_list,
$member_list,
$watcher_list,
));
$crumbs = $this->buildApplicationCrumbs();
$crumbs->setBorder(true);
require_celerity_resource('project-view-css');
$home = phutil_tag(
'div',
array(
'class' => 'project-view-home',
),
array(
$header,
$columns,
));
return $this->newPage()
->setNavigation($nav)
->setCrumbs($crumbs)
->setTitle($project->getDisplayName())
->setPageObjectPHIDs(array($project->getPHID()))
->appendChild(
array(
$home,
));
}
private function buildPropertyListView(
PhabricatorProject $project) {
$request = $this->getRequest();
$viewer = $request->getViewer();
$view = id(new PHUIPropertyListView())
->setViewer($viewer)
->setObject($project);
$field_list = PhabricatorCustomField::getObjectFields(
$project,
PhabricatorCustomField::ROLE_VIEW);
$field_list->appendFieldsToPropertyList($project, $viewer, $view);
if (!$view->hasAnyProperties()) {
return null;
}
$view = id(new PHUIBoxView())
->setColor(PHUIBoxView::GREY)
->appendChild($view)
->addClass('project-view-properties');
return $view;
}
private function renderStories(array $stories) {
assert_instances_of($stories, 'PhabricatorFeedStory');
$builder = new PhabricatorFeedBuilder($stories);
$builder->setUser($this->getRequest()->getUser());
$builder->setShowHovercards(true);
$view = $builder->buildView();
return $view;
}
private function renderWatchAction(PhabricatorProject $project) {
$viewer = $this->getViewer();
$viewer_phid = $viewer->getPHID();
$id = $project->getID();
$is_watcher = ($viewer_phid && $project->isUserWatcher($viewer_phid));
if (!$is_watcher) {
$watch_icon = 'fa-eye';
$watch_text = pht('Watch Project');
$watch_href = "/project/watch/{$id}/?via=profile";
} else {
$watch_icon = 'fa-eye-slash';
$watch_text = pht('Unwatch Project');
$watch_href = "/project/unwatch/{$id}/?via=profile";
}
$watch_icon = id(new PHUIIconView())
->setIcon($watch_icon);
return id(new PHUIButtonView())
->setTag('a')
->setWorkflow(true)
->setIcon($watch_icon)
->setText($watch_text)
->setHref($watch_href);
}
private function buildMilestoneList(PhabricatorProject $project) {
if (!$project->getHasMilestones()) {
return null;
}
$viewer = $this->getViewer();
$id = $project->getID();
$milestones = id(new PhabricatorProjectQuery())
->setViewer($viewer)
->withParentProjectPHIDs(array($project->getPHID()))
->needImages(true)
->withIsMilestone(true)
->withStatuses(
array(
PhabricatorProjectStatus::STATUS_ACTIVE,
))
->setOrder('newest')
->execute();
if (!$milestones) {
return null;
}
$milestone_list = id(new PhabricatorProjectListView())
->setViewer($viewer)
->setProjects($milestones)
->renderList();
$view_all = id(new PHUIButtonView())
->setTag('a')
->setIcon(
id(new PHUIIconView())
->setIcon('fa-list-ul'))
->setText(pht('View All'))
->setHref("/project/subprojects/{$id}/");
$header = id(new PHUIHeaderView())
->setHeader(pht('Milestones'))
->addActionLink($view_all);
return id(new PHUIObjectBoxView())
->setHeader($header)
->setBackground(PHUIBoxView::GREY)
->setObjectList($milestone_list);
}
private function buildSubprojectList(PhabricatorProject $project) {
if (!$project->getHasSubprojects()) {
return null;
}
$viewer = $this->getViewer();
$id = $project->getID();
$limit = 25;
$subprojects = id(new PhabricatorProjectQuery())
->setViewer($viewer)
->withParentProjectPHIDs(array($project->getPHID()))
->needImages(true)
->withStatuses(
array(
PhabricatorProjectStatus::STATUS_ACTIVE,
))
->withIsMilestone(false)
->setLimit($limit)
->execute();
if (!$subprojects) {
return null;
}
$subproject_list = id(new PhabricatorProjectListView())
->setViewer($viewer)
->setProjects($subprojects)
->renderList();
$view_all = id(new PHUIButtonView())
->setTag('a')
->setIcon(
id(new PHUIIconView())
->setIcon('fa-list-ul'))
->setText(pht('View All'))
->setHref("/project/subprojects/{$id}/");
$header = id(new PHUIHeaderView())
->setHeader(pht('Subprojects'))
->addActionLink($view_all);
return id(new PHUIObjectBoxView())
->setHeader($header)
->setBackground(PHUIBoxView::GREY)
->setObjectList($subproject_list);
}
}
......@@ -8,49 +8,10 @@ final class SprintProjectViewController
}
public function handleRequest(AphrontRequest $request) {
$request = $this->getRequest();
$viewer = $request->getViewer();
$query = id(new PhabricatorProjectQuery())
->setViewer($viewer)
->needMembers(true)
->needWatchers(true)
->needImages(true)
->needSlugs(true);
$id = $request->getURIData('id');
$slug = $request->getURIData('slug');
if ($slug) {
$query->withSlugs(array($slug));
} else {
$query->withIDs(array($id));
}
$project = $query->executeOne();
if (!$project) {
return new Aphront404Response();
}
$columns = id(new PhabricatorProjectColumnQuery())
->setViewer($viewer)
->withProjectPHIDs(array($project->getPHID()))
->execute();
if ($columns) {
$controller = 'board';
} else {
$controller = 'profile';
}
switch ($controller) {
case 'board':
$controller_object = new SprintBoardViewController();
break;
case 'profile':
default:
$controller_object = new SprintProjectProfileController();
break;
}
return $this->delegateToController($controller_object);
$uri = $request->getRequestURI();
$projectID = $request->getURIData('id');
$uri->setPath("/project/view/{$projectID}/");
return id(new AphrontRedirectResponse())->setURI($uri);
}
}
<?php
final class SprintProjectProfilePanelEngine
extends PhabricatorProfilePanelEngine {
protected function isPanelEngineConfigurable() {
return true;
}
protected function getPanelURI($path) {
$project = $this->getProfileObject();
$id = $project->getID();
return "/project/{$id}/panel/{$path}";
}
protected function getBuiltinProfilePanels($object) {
$panels = array();
$panels[] = $this->newPanel()
->setBuiltinKey(PhabricatorProject::PANEL_PROFILE)
->setPanelKey(PhabricatorProjectDetailsProfilePanel::PANELKEY);
$panels[] = $this->newPanel()
->setBuiltinKey(PhabricatorProject::PANEL_POINTS)
->setPanelKey(PhabricatorProjectPointsProfilePanel::PANELKEY);
$panels[] = $this->newPanel()
->setBuiltinKey(PhabricatorProject::PANEL_WORKBOARD)
->setPanelKey(PhabricatorProjectWorkboardProfilePanel::PANELKEY);
$panels[] = $this->newPanel()
->setBuiltinKey(PhabricatorProject::PANEL_MEMBERS)
->setPanelKey(PhabricatorProjectMembersProfilePanel::PANELKEY);
$panels[] = $this->newPanel()
->setBuiltinKey(PhabricatorProject::PANEL_SUBPROJECTS)
->setPanelKey(PhabricatorProjectSubprojectsProfilePanel::PANELKEY);
$panels[] = $this->newPanel()
->setBuiltinKey(PhabricatorProject::PANEL_MANAGE)
->setPanelKey(PhabricatorProjectManageProfilePanel::PANELKEY);
$panels[] = $this->newPanel()
->setBuiltinKey(SprintConstants::PANEL_BURNDOWN)
->setPanelKey(SprintProjectProfilePanel::PANELKEY);
$panels[] = $this->newPanel()
->setBuiltinKey(SprintConstants::PANEL_PHRAGILE)
->setPanelKey(PhragileProfilePanel::PANELKEY);
return $panels;
}
}
......@@ -44,19 +44,21 @@ final class SprintProjectProfilePanel
$project = $config->getProfileObject();
$has_children = ($project->getHasSubprojects()) ||
($project->getHasMilestones());
$query = id(new SprintQuery())
->setViewer($this->getViewer())
->setPHID($project->getPHID());
$is_sprint = $query->getIsSprint();
$id = $project->getID();
$name = $this->getDisplayName($config);
$icon = 'fa-calendar';
$icon = 'fa-fire';
$href = "/project/sprint/view/{$id}/";
$item = $this->newItem()
->setHref($href)
->setName($name)
->setDisabled(!$has_children)
->setDisabled(!$is_sprint)
->setIcon($icon);
return array(
......
<?php
final class SprintHandleIconView extends AphrontTagView {
const SPRITE_TOKENS = 'tokens';
const SPRITE_LOGIN = 'login';
const SPRITE_PROJECTS = 'projects';
const HEAD_SMALL = 'phuihead-small';
const HEAD_MEDIUM = 'phuihead-medium';
private $href = null;
private $image;
private $text;
private $headSize = null;
private $spriteIcon;
private $spriteSheet;
private $iconFont;
private $iconColor;
private $iconStyle;
public function setHref($href) {
$this->href = $href;
return $this;
}
public function setIconStyle($style) {
$this->iconStyle = $style;
return $this;
}
public function setImage($image) {
$this->image = $image;
return $this;
}
public function setText($text) {
$this->text = $text;
return $this;
}
public function setHeadSize($size) {
$this->headSize = $size;
return $this;
}
public function setSpriteIcon($sprite) {
$this->spriteIcon = $sprite;
return $this;
}
public function setSpriteSheet($sheet) {
$this->spriteSheet = $sheet;
return $this;
}
public function setIconFont($icon, $color = null) {
$this->iconFont = $icon;
$this->iconColor = $color;
return $this;
}
protected function getTagName() {
$tag = 'span';
if ($this->href) {
$tag = 'a';
}
return $tag;
}
protected function getTagAttributes() {
$classes = array();
$classes[] = 'phui-object-item-handle-icon';
return array(
'href' => $this->href,
'style' => $this->iconStyle,
'aural' => false,
'class' => $classes,
);
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment