1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-11-22 14:52:41 +01:00

Build a Badges page for Profiles

Summary: Ref T12270. Moves badges into their own page and menu item. Capable of displaying hundreds of useful tokens of appreciation and dedication.

Test Plan:
Test blank state, mobile, awards badges.

{F3284139}

Reviewers: epriestley

Reviewed By: epriestley

Subscribers: Korvin

Maniphest Tasks: T12270

Differential Revision: https://secure.phabricator.com/D17410
This commit is contained in:
Chad Little 2017-02-24 13:15:30 -08:00
parent 4270649abe
commit 80cccebca2
13 changed files with 228 additions and 122 deletions

View file

@ -97,7 +97,7 @@ return array(
'rsrc/css/application/policy/policy.css' => '957ea14c',
'rsrc/css/application/ponder/ponder-view.css' => 'fbd45f96',
'rsrc/css/application/project/project-card-view.css' => '77219296',
'rsrc/css/application/project/project-view.css' => '9f6ce0e1',
'rsrc/css/application/project/project-view.css' => '792c9057',
'rsrc/css/application/releeph/releeph-core.css' => '9b3c5733',
'rsrc/css/application/releeph/releeph-preview-branch.css' => 'b7a6f4a5',
'rsrc/css/application/releeph/releeph-request-differential-create-dialog.css' => '8d8b92cd',
@ -130,7 +130,7 @@ return array(
'rsrc/css/phui/object-item/phui-oi-simple-ui.css' => 'a8beebea',
'rsrc/css/phui/phui-action-list.css' => 'f980c059',
'rsrc/css/phui/phui-action-panel.css' => '91c7b835',
'rsrc/css/phui/phui-badge.css' => '22fe77f8',
'rsrc/css/phui/phui-badge.css' => '22c0cf4f',
'rsrc/css/phui/phui-basic-nav-view.css' => 'a0705f53',
'rsrc/css/phui/phui-big-info-view.css' => 'bd903741',
'rsrc/css/phui/phui-box.css' => '269cbc99',
@ -837,7 +837,7 @@ return array(
'phrequent-css' => 'ffc185ad',
'phriction-document-css' => '4282e4ad',
'phui-action-panel-css' => '91c7b835',
'phui-badge-view-css' => '22fe77f8',
'phui-badge-view-css' => '22c0cf4f',
'phui-basic-nav-view-css' => 'a0705f53',
'phui-big-info-view-css' => 'bd903741',
'phui-box-css' => '269cbc99',
@ -906,7 +906,7 @@ return array(
'policy-transaction-detail-css' => '82100a43',
'ponder-view-css' => 'fbd45f96',
'project-card-view-css' => '77219296',
'project-view-css' => '9f6ce0e1',
'project-view-css' => '792c9057',
'releeph-core' => '9b3c5733',
'releeph-preview-branch' => 'b7a6f4a5',
'releeph-request-differential-create-dialog' => '8d8b92cd',

View file

@ -3316,6 +3316,7 @@ phutil_register_library_map(array(
'PhabricatorPeopleAnyOwnerDatasource' => 'applications/people/typeahead/PhabricatorPeopleAnyOwnerDatasource.php',
'PhabricatorPeopleApplication' => 'applications/people/application/PhabricatorPeopleApplication.php',
'PhabricatorPeopleApproveController' => 'applications/people/controller/PhabricatorPeopleApproveController.php',
'PhabricatorPeopleBadgesProfileMenuItem' => 'applications/people/menuitem/PhabricatorPeopleBadgesProfileMenuItem.php',
'PhabricatorPeopleController' => 'applications/people/controller/PhabricatorPeopleController.php',
'PhabricatorPeopleCreateController' => 'applications/people/controller/PhabricatorPeopleCreateController.php',
'PhabricatorPeopleCreateGuidanceContext' => 'applications/people/guidance/PhabricatorPeopleCreateGuidanceContext.php',
@ -3339,6 +3340,7 @@ phutil_register_library_map(array(
'PhabricatorPeopleNoOwnerDatasource' => 'applications/people/typeahead/PhabricatorPeopleNoOwnerDatasource.php',
'PhabricatorPeopleOwnerDatasource' => 'applications/people/typeahead/PhabricatorPeopleOwnerDatasource.php',
'PhabricatorPeoplePictureProfileMenuItem' => 'applications/people/menuitem/PhabricatorPeoplePictureProfileMenuItem.php',
'PhabricatorPeopleProfileBadgesController' => 'applications/people/controller/PhabricatorPeopleProfileBadgesController.php',
'PhabricatorPeopleProfileController' => 'applications/people/controller/PhabricatorPeopleProfileController.php',
'PhabricatorPeopleProfileEditController' => 'applications/people/controller/PhabricatorPeopleProfileEditController.php',
'PhabricatorPeopleProfileManageController' => 'applications/people/controller/PhabricatorPeopleProfileManageController.php',
@ -8473,6 +8475,7 @@ phutil_register_library_map(array(
'PhabricatorPeopleAnyOwnerDatasource' => 'PhabricatorTypeaheadDatasource',
'PhabricatorPeopleApplication' => 'PhabricatorApplication',
'PhabricatorPeopleApproveController' => 'PhabricatorPeopleController',
'PhabricatorPeopleBadgesProfileMenuItem' => 'PhabricatorProfileMenuItem',
'PhabricatorPeopleController' => 'PhabricatorController',
'PhabricatorPeopleCreateController' => 'PhabricatorPeopleController',
'PhabricatorPeopleCreateGuidanceContext' => 'PhabricatorGuidanceContext',
@ -8496,6 +8499,7 @@ phutil_register_library_map(array(
'PhabricatorPeopleNoOwnerDatasource' => 'PhabricatorTypeaheadDatasource',
'PhabricatorPeopleOwnerDatasource' => 'PhabricatorTypeaheadCompositeDatasource',
'PhabricatorPeoplePictureProfileMenuItem' => 'PhabricatorProfileMenuItem',
'PhabricatorPeopleProfileBadgesController' => 'PhabricatorPeopleProfileController',
'PhabricatorPeopleProfileController' => 'PhabricatorPeopleController',
'PhabricatorPeopleProfileEditController' => 'PhabricatorPeopleProfileController',
'PhabricatorPeopleProfileManageController' => 'PhabricatorPeopleProfileController',

View file

@ -15,7 +15,7 @@ final class PhabricatorBadgesAwardController
return new Aphront404Response();
}
$view_uri = '/p/'.$user->getUsername();
$view_uri = '/people/badges/'.$user->getID().'/';
if ($request->isFormPost()) {
$badge_phids = $request->getArr('badgePHIDs');

View file

@ -64,6 +64,8 @@ final class PhabricatorPeopleApplication extends PhabricatorApplication {
'ldap/' => 'PhabricatorPeopleLdapController',
'editprofile/(?P<id>[1-9]\d*)/' =>
'PhabricatorPeopleProfileEditController',
'badges/(?P<id>[1-9]\d*)/' =>
'PhabricatorPeopleProfileBadgesController',
'picture/(?P<id>[1-9]\d*)/' =>
'PhabricatorPeopleProfilePictureController',
'manage/(?P<id>[1-9]\d*)/' =>

View file

@ -0,0 +1,137 @@
<?php
final class PhabricatorPeopleProfileBadgesController
extends PhabricatorPeopleProfileController {
public function handleRequest(AphrontRequest $request) {
$viewer = $this->getViewer();
$id = $request->getURIData('id');
$user = id(new PhabricatorPeopleQuery())
->setViewer($viewer)
->withIDs(array($id))
->needProfile(true)
->needProfileImage(true)
->needAvailability(true)
->needBadges(true)
->requireCapabilities(
array(
PhabricatorPolicyCapability::CAN_VIEW,
))
->executeOne();
if (!$user) {
return new Aphront404Response();
}
$class = 'PhabricatorBadgesApplication';
if (!PhabricatorApplication::isClassInstalledForViewer($class, $viewer)) {
return new Aphront404Response();
}
$this->setUser($user);
$title = array(pht('Badges'), $user->getUsername());
$header = $this->buildProfileHeader();
$badges = $this->buildBadgesView($user);
$crumbs = $this->buildApplicationCrumbs();
$crumbs->addTextCrumb(pht('Badges'));
$crumbs->setBorder(true);
$nav = $this->getProfileMenu();
$nav->selectFilter(PhabricatorPeopleProfileMenuEngine::ITEM_BADGES);
// Best option?
$badges = id(new PhabricatorBadgesQuery())
->setViewer($viewer)
->withStatuses(array(
PhabricatorBadgesBadge::STATUS_ACTIVE,
))
->requireCapabilities(
array(
PhabricatorPolicyCapability::CAN_VIEW,
PhabricatorPolicyCapability::CAN_EDIT,
))
->execute();
$button = id(new PHUIButtonView())
->setTag('a')
->setIcon('fa-plus')
->setText(pht('Award Badge'))
->setWorkflow(true)
->setHref('/badges/award/'.$user->getID().'/');
if (count($badges)) {
$header->addActionLink($button);
}
$view = id(new PHUITwoColumnView())
->setHeader($header)
->addClass('project-view-home')
->addClass('project-view-people-home')
->setFooter(array(
$this->buildBadgesView($user)
));
return $this->newPage()
->setTitle($title)
->setCrumbs($crumbs)
->setNavigation($nav)
->appendChild($view);
}
private function buildBadgesView(PhabricatorUser $user) {
$viewer = $this->getViewer();
$awards = array();
$badges = array();
if ($user->getBadgePHIDs()) {
$awards = id(new PhabricatorBadgesAwardQuery())
->setViewer($viewer)
->withRecipientPHIDs(array($user->getPHID()))
->execute();
$awards = mpull($awards, null, 'getBadgePHID');
$badges = array();
foreach ($awards as $award) {
$badge = $award->getBadge();
if ($badge->getStatus() == PhabricatorBadgesBadge::STATUS_ACTIVE) {
$badges[$award->getBadgePHID()] = $badge;
}
}
}
if (count($badges)) {
$flex = new PHUIBadgeBoxView();
foreach ($badges as $badge) {
if ($badge) {
$awarder_info = array();
$award = idx($awards, $badge->getPHID(), null);
$awarder_phid = $award->getAwarderPHID();
$awarder_handle = $viewer->renderHandle($awarder_phid);
$awarder_info = pht(
'Awarded by %s',
$awarder_handle->render());
$item = id(new PHUIBadgeView())
->setIcon($badge->getIcon())
->setHeader($badge->getName())
->setSubhead($badge->getFlavor())
->setQuality($badge->getQuality())
->setHref($badge->getViewURI())
->addByLine($awarder_info);
$flex->addItem($item);
}
}
} else {
$flex = id(new PHUIInfoView())
->setSeverity(PHUIInfoView::SEVERITY_NOTICE)
->appendChild(pht('User has not been awarded any badges.'));
}
return $flex;
}
}

View file

@ -86,6 +86,9 @@ abstract class PhabricatorPeopleProfileController
if ($user->getIsMailingList()) {
$roles[] = pht('Mailing List');
}
if (!$user->getIsEmailVerified()) {
$roles[] = pht('Email Not Verified');
}
$tag = null;
if ($roles) {
@ -101,10 +104,10 @@ abstract class PhabricatorPeopleProfileController
->setProfileHeader(true)
->addClass('people-profile-header');
require_celerity_resource('project-view-css');
if ($user->getIsDisabled()) {
$header->setStatus('fa-ban', 'red', pht('Disabled'));
} else if (!$user->getIsEmailVerified()) {
$header->setStatus('fa-envelope', 'red', pht('Email Not Verified'));
} else {
$header->setStatus($profile_icon, 'bluegrey', $profile_title);
}

View file

@ -39,9 +39,9 @@ final class PhabricatorPeopleProfileManageController
$manage = id(new PHUITwoColumnView())
->setHeader($header)
->addClass('project-view-home')
->addClass('project-view-people-home')
->setCurtain($curtain)
->addPropertySection(pht('Details'), $properties);
require_celerity_resource('project-view-css');
return $this->newPage()
->setTitle(

View file

@ -258,12 +258,12 @@ final class PhabricatorPeopleProfilePictureController
$nav = $this->getProfileMenu();
$nav->selectFilter(PhabricatorPeopleProfileMenuEngine::ITEM_MANAGE);
$header = id(new PHUIHeaderView())
->setHeader(pht('Edit Profile Picture'))
->setHeaderIcon('fa-camera');
$header = $this->buildProfileHeader();
$view = id(new PHUITwoColumnView())
->setHeader($header)
->addClass('project-view-home')
->addClass('project-view-people-home')
->setFooter(array(
$form_box,
$upload_box,

View file

@ -14,7 +14,6 @@ final class PhabricatorPeopleProfileViewController
$user = id(new PhabricatorPeopleQuery())
->setViewer($viewer)
->withUsernames(array($username))
->needBadges(true)
->needProfileImage(true)
->needAvailability(true)
->executeOne();
@ -36,8 +35,6 @@ final class PhabricatorPeopleProfileViewController
$projects = $this->buildProjectsView($user);
$calendar = $this->buildCalendarDayView($user);
$badges = $this->buildBadgesView($user);
require_celerity_resource('project-view-css');
$home = id(new PHUITwoColumnView())
->setHeader($header)
@ -52,7 +49,6 @@ final class PhabricatorPeopleProfileViewController
array(
$projects,
$calendar,
$badges,
));
$nav = $this->getProfileMenu();
@ -228,106 +224,6 @@ final class PhabricatorPeopleProfileViewController
return $box;
}
private function buildBadgesView(PhabricatorUser $user) {
$viewer = $this->getViewer();
$class = 'PhabricatorBadgesApplication';
if (!PhabricatorApplication::isClassInstalledForViewer($class, $viewer)) {
return null;
}
$awards = array();
$badges = array();
if ($user->getBadgePHIDs()) {
$awards = id(new PhabricatorBadgesAwardQuery())
->setViewer($viewer)
->withRecipientPHIDs(array($user->getPHID()))
->execute();
$awards = mpull($awards, null, 'getBadgePHID');
$badges = array();
foreach ($awards as $award) {
$badge = $award->getBadge();
if ($badge->getStatus() == PhabricatorBadgesBadge::STATUS_ACTIVE) {
$badges[$award->getBadgePHID()] = $badge;
}
}
}
if (count($badges)) {
$flex = new PHUIBadgeBoxView();
foreach ($badges as $badge) {
if ($badge) {
$awarder_info = array();
$award = idx($awards, $badge->getPHID(), null);
$awarder_phid = $award->getAwarderPHID();
$awarder_handle = $viewer->renderHandle($awarder_phid);
$awarder_info = pht(
'Awarded by %s',
$awarder_handle->render());
$item = id(new PHUIBadgeView())
->setIcon($badge->getIcon())
->setHeader($badge->getName())
->setSubhead($badge->getFlavor())
->setQuality($badge->getQuality())
->setHref($badge->getViewURI())
->addByLine($awarder_info);
$flex->addItem($item);
}
}
} else {
$flex = id(new PHUIInfoView())
->setSeverity(PHUIInfoView::SEVERITY_NODATA)
->appendChild(pht('User does not have any badges.'));
}
// Best option?
$badges = id(new PhabricatorBadgesQuery())
->setViewer($viewer)
->withStatuses(array(
PhabricatorBadgesBadge::STATUS_ACTIVE,
))
->requireCapabilities(
array(
PhabricatorPolicyCapability::CAN_VIEW,
PhabricatorPolicyCapability::CAN_EDIT,
))
->execute();
$button = id(new PHUIButtonView())
->setTag('a')
->setIcon('fa-plus')
->setText(pht('Award'))
->setWorkflow(true)
->setHref('/badges/award/'.$user->getID().'/');
$can_award = false;
if (count($badges)) {
$can_award = true;
}
$header = id(new PHUIHeaderView())
->setHeader(pht('Badges'));
if (count($badges)) {
$header->addActionLink($button);
}
$box = id(new PHUIObjectBoxView())
->setHeader($header)
->addClass('project-view-badges')
->appendChild($flex)
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY);
return $box;
}
private function buildPeopleFeed(
PhabricatorUser $user,
$viewer) {

View file

@ -6,6 +6,7 @@ final class PhabricatorPeopleProfileMenuEngine
const ITEM_PROFILE = 'people.profile';
const ITEM_MANAGE = 'people.manage';
const ITEM_PICTURE = 'people.picture';
const ITEM_BADGES = 'people.badges';
protected function isMenuEngineConfigurable() {
return false;
@ -31,6 +32,15 @@ final class PhabricatorPeopleProfileMenuEngine
->setBuiltinKey(self::ITEM_PROFILE)
->setMenuItemKey(PhabricatorPeopleDetailsProfileMenuItem::MENUITEMKEY);
$have_badges = PhabricatorApplication::isClassInstalledForViewer(
'PhabricatorBadgesApplication',
$viewer);
if ($have_badges) {
$items[] = $this->newItem()
->setBuiltinKey(self::ITEM_BADGES)
->setMenuItemKey(PhabricatorPeopleBadgesProfileMenuItem::MENUITEMKEY);
}
$have_maniphest = PhabricatorApplication::isClassInstalledForViewer(
'PhabricatorManiphestApplication',
$viewer);

View file

@ -0,0 +1,59 @@
<?php
final class PhabricatorPeopleBadgesProfileMenuItem
extends PhabricatorProfileMenuItem {
const MENUITEMKEY = 'people.badges';
public function getMenuItemTypeName() {
return pht('Badges');
}
private function getDefaultName() {
return pht('Badges');
}
public function canHideMenuItem(
PhabricatorProfileMenuItemConfiguration $config) {
return true;
}
public function getDisplayName(
PhabricatorProfileMenuItemConfiguration $config) {
$name = $config->getMenuItemProperty('name');
if (strlen($name)) {
return $name;
}
return $this->getDefaultName();
}
public function buildEditEngineFields(
PhabricatorProfileMenuItemConfiguration $config) {
return array(
id(new PhabricatorTextEditField())
->setKey('name')
->setLabel(pht('Name'))
->setPlaceholder($this->getDefaultName())
->setValue($config->getMenuItemProperty('name')),
);
}
protected function newNavigationMenuItems(
PhabricatorProfileMenuItemConfiguration $config) {
$user = $config->getProfileObject();
$id = $user->getID();
$item = $this->newItem()
->setHref("/people/badges/{$id}/")
->setName($this->getDisplayName($config))
->setIcon('fa-trophy');
return array(
$item,
);
}
}

View file

@ -67,10 +67,6 @@
text-align: center;
}
.project-view-badges .phui-badge-flex-view {
background-color: #fff;
}
.project-view-home .phui-box-grey .phui-oi-attribute .phui-icon-view {
color: {$lightgreytext};
}

View file

@ -3,14 +3,13 @@
*/
.phui-badge-flex-view {
padding: 12px 4px 8px;
padding: 0;
overflow: hidden;
text-align: center;
}
.phui-badge-flex-item {
display: inline-block;
padding: 4px 8px;
padding: 4px 12px 4px 0;
}
.phui-badge-flex-view.flex-view-collapsed {