Page MenuHomestyx hydra

No OneTemporary

This file is larger than 256 KB, so syntax highlighting was skipped.
diff --git a/src/applications/almanac/application/PhabricatorAlmanacApplication.php b/src/applications/almanac/application/PhabricatorAlmanacApplication.php
index 88eafd3331..a444554a0e 100644
--- a/src/applications/almanac/application/PhabricatorAlmanacApplication.php
+++ b/src/applications/almanac/application/PhabricatorAlmanacApplication.php
@@ -1,93 +1,93 @@
<?php
final class PhabricatorAlmanacApplication extends PhabricatorApplication {
public function getBaseURI() {
return '/almanac/';
}
public function getName() {
return pht('Almanac');
}
public function getShortDescription() {
return pht('Service Directory');
}
- public function getFontIcon() {
+ public function getIcon() {
return 'fa-server';
}
public function getTitleGlyph() {
return "\xE2\x98\x82";
}
public function getApplicationGroup() {
return self::GROUP_UTILITIES;
}
public function getHelpDocumentationArticles(PhabricatorUser $viewer) {
return array(
array(
'name' => pht('Alamanac User Guide'),
'href' => PhabricatorEnv::getDoclink('Almanac User Guide'),
),
);
}
public function isPrototype() {
return true;
}
public function getRoutes() {
return array(
'/almanac/' => array(
'' => 'AlmanacConsoleController',
'service/' => array(
'(?:query/(?P<queryKey>[^/]+)/)?' => 'AlmanacServiceListController',
'edit/(?:(?P<id>\d+)/)?' => 'AlmanacServiceEditController',
'view/(?P<name>[^/]+)/' => 'AlmanacServiceViewController',
),
'device/' => array(
'(?:query/(?P<queryKey>[^/]+)/)?' => 'AlmanacDeviceListController',
'edit/(?:(?P<id>\d+)/)?' => 'AlmanacDeviceEditController',
'view/(?P<name>[^/]+)/' => 'AlmanacDeviceViewController',
),
'interface/' => array(
'edit/(?:(?P<id>\d+)/)?' => 'AlmanacInterfaceEditController',
),
'binding/' => array(
'edit/(?:(?P<id>\d+)/)?' => 'AlmanacBindingEditController',
'(?P<id>\d+)/' => 'AlmanacBindingViewController',
),
'network/' => array(
'(?:query/(?P<queryKey>[^/]+)/)?' => 'AlmanacNetworkListController',
'edit/(?:(?P<id>\d+)/)?' => 'AlmanacNetworkEditController',
'(?P<id>\d+)/' => 'AlmanacNetworkViewController',
),
'property/' => array(
'edit/' => 'AlmanacPropertyEditController',
'delete/' => 'AlmanacPropertyDeleteController',
),
),
);
}
protected function getCustomCapabilities() {
return array(
AlmanacCreateServicesCapability::CAPABILITY => array(
'default' => PhabricatorPolicies::POLICY_ADMIN,
),
AlmanacCreateDevicesCapability::CAPABILITY => array(
'default' => PhabricatorPolicies::POLICY_ADMIN,
),
AlmanacCreateNetworksCapability::CAPABILITY => array(
'default' => PhabricatorPolicies::POLICY_ADMIN,
),
AlmanacCreateClusterServicesCapability::CAPABILITY => array(
'default' => PhabricatorPolicies::POLICY_ADMIN,
),
);
}
}
diff --git a/src/applications/almanac/controller/AlmanacConsoleController.php b/src/applications/almanac/controller/AlmanacConsoleController.php
index 8abd8c6113..9f46bd54d3 100644
--- a/src/applications/almanac/controller/AlmanacConsoleController.php
+++ b/src/applications/almanac/controller/AlmanacConsoleController.php
@@ -1,53 +1,53 @@
<?php
final class AlmanacConsoleController extends AlmanacController {
public function shouldAllowPublic() {
return true;
}
public function handleRequest(AphrontRequest $request) {
$viewer = $request->getViewer();
$menu = id(new PHUIObjectItemListView())
->setUser($viewer);
$menu->addItem(
id(new PHUIObjectItemView())
->setHeader(pht('Services'))
->setHref($this->getApplicationURI('service/'))
- ->setFontIcon('fa-plug')
+ ->setIcon('fa-plug')
->addAttribute(pht('Manage Almanac services.')));
$menu->addItem(
id(new PHUIObjectItemView())
->setHeader(pht('Devices'))
->setHref($this->getApplicationURI('device/'))
- ->setFontIcon('fa-server')
+ ->setIcon('fa-server')
->addAttribute(pht('Manage Almanac devices.')));
$menu->addItem(
id(new PHUIObjectItemView())
->setHeader(pht('Networks'))
->setHref($this->getApplicationURI('network/'))
- ->setFontIcon('fa-globe')
+ ->setIcon('fa-globe')
->addAttribute(pht('Manage Almanac networks.')));
$crumbs = $this->buildApplicationCrumbs();
$crumbs->addTextCrumb(pht('Console'));
$box = id(new PHUIObjectBoxView())
->setHeaderText(pht('Console'))
->setObjectList($menu);
return $this->newPage()
->setTitle(pht('Almanac Console'))
->setCrumbs($crumbs)
->appendChild(
array(
$box,
));
}
}
diff --git a/src/applications/audit/application/PhabricatorAuditApplication.php b/src/applications/audit/application/PhabricatorAuditApplication.php
index 4f4c5a56d1..66280a16a0 100644
--- a/src/applications/audit/application/PhabricatorAuditApplication.php
+++ b/src/applications/audit/application/PhabricatorAuditApplication.php
@@ -1,97 +1,97 @@
<?php
final class PhabricatorAuditApplication extends PhabricatorApplication {
public function getBaseURI() {
return '/audit/';
}
- public function getFontIcon() {
+ public function getIcon() {
return 'fa-check-circle-o';
}
public function getName() {
return pht('Audit');
}
public function getShortDescription() {
return pht('Browse and Audit Commits');
}
public function isPinnedByDefault(PhabricatorUser $viewer) {
return true;
}
public function getHelpDocumentationArticles(PhabricatorUser $viewer) {
return array(
array(
'name' => pht('Audit User Guide'),
'href' => PhabricatorEnv::getDoclink('Audit User Guide'),
),
);
}
public function getRoutes() {
return array(
'/audit/' => array(
'(?:query/(?P<queryKey>[^/]+)/)?' => 'PhabricatorAuditListController',
'addcomment/' => 'PhabricatorAuditAddCommentController',
'preview/(?P<id>[1-9]\d*)/' => 'PhabricatorAuditPreviewController',
),
);
}
public function getApplicationOrder() {
return 0.130;
}
public function loadStatus(PhabricatorUser $user) {
$status = array();
$limit = self::MAX_STATUS_ITEMS;
$phids = PhabricatorAuditCommentEditor::loadAuditPHIDsForUser($user);
$query = id(new DiffusionCommitQuery())
->setViewer($user)
->withAuthorPHIDs(array($user->getPHID()))
->withAuditStatus(DiffusionCommitQuery::AUDIT_STATUS_CONCERN)
->setLimit($limit);
$commits = $query->execute();
$count = count($commits);
if ($count >= $limit) {
$count_str = pht('%s+ Problem Commit(s)', new PhutilNumber($limit - 1));
} else {
$count_str = pht('%s Problem Commit(s)', new PhutilNumber($count));
}
$type = PhabricatorApplicationStatusView::TYPE_NEEDS_ATTENTION;
$status[] = id(new PhabricatorApplicationStatusView())
->setType($type)
->setText($count_str)
->setCount($count);
$query = id(new DiffusionCommitQuery())
->setViewer($user)
->withNeedsAuditByPHIDs($phids)
->withAuditStatus(DiffusionCommitQuery::AUDIT_STATUS_OPEN)
->setLimit($limit);
$commits = $query->execute();
$count = count($commits);
if ($count >= $limit) {
$count_str = pht('%s+ Problem Commit(s)', new PhutilNumber($limit - 1));
} else {
$count_str = pht('%s Problem Commit(s)', new PhutilNumber($count));
}
$type = PhabricatorApplicationStatusView::TYPE_WARNING;
$status[] = id(new PhabricatorApplicationStatusView())
->setType($type)
->setText($count_str)
->setCount($count);
return $status;
}
}
diff --git a/src/applications/auth/application/PhabricatorAuthApplication.php b/src/applications/auth/application/PhabricatorAuthApplication.php
index a9831b20e3..808562e970 100644
--- a/src/applications/auth/application/PhabricatorAuthApplication.php
+++ b/src/applications/auth/application/PhabricatorAuthApplication.php
@@ -1,114 +1,114 @@
<?php
final class PhabricatorAuthApplication extends PhabricatorApplication {
public function canUninstall() {
return false;
}
public function getBaseURI() {
return '/auth/';
}
- public function getFontIcon() {
+ public function getIcon() {
return 'fa-key';
}
public function isPinnedByDefault(PhabricatorUser $viewer) {
return $viewer->getIsAdmin();
}
public function getName() {
return pht('Auth');
}
public function getShortDescription() {
return pht('Login/Registration');
}
public function getHelpDocumentationArticles(PhabricatorUser $viewer) {
// NOTE: Although reasonable help exists for this in "Configuring Accounts
// and Registration", specifying help items here means we get the menu
// item in all the login/link interfaces, which is confusing and not
// helpful.
// TODO: Special case this, or split the auth and auth administration
// applications?
return array();
}
public function getApplicationGroup() {
return self::GROUP_ADMIN;
}
public function getRoutes() {
return array(
'/auth/' => array(
'' => 'PhabricatorAuthListController',
'config/' => array(
'new/' => 'PhabricatorAuthNewController',
'new/(?P<className>[^/]+)/' => 'PhabricatorAuthEditController',
'edit/(?P<id>\d+)/' => 'PhabricatorAuthEditController',
'(?P<action>enable|disable)/(?P<id>\d+)/'
=> 'PhabricatorAuthDisableController',
),
'login/(?P<pkey>[^/]+)/(?:(?P<extra>[^/]+)/)?'
=> 'PhabricatorAuthLoginController',
'(?P<loggedout>loggedout)/' => 'PhabricatorAuthStartController',
'invite/(?P<code>[^/]+)/' => 'PhabricatorAuthInviteController',
'register/(?:(?P<akey>[^/]+)/)?' => 'PhabricatorAuthRegisterController',
'start/' => 'PhabricatorAuthStartController',
'validate/' => 'PhabricatorAuthValidateController',
'finish/' => 'PhabricatorAuthFinishController',
'unlink/(?P<pkey>[^/]+)/' => 'PhabricatorAuthUnlinkController',
'(?P<action>link|refresh)/(?P<pkey>[^/]+)/'
=> 'PhabricatorAuthLinkController',
'confirmlink/(?P<akey>[^/]+)/'
=> 'PhabricatorAuthConfirmLinkController',
'session/terminate/(?P<id>[^/]+)/'
=> 'PhabricatorAuthTerminateSessionController',
'token/revoke/(?P<id>[^/]+)/'
=> 'PhabricatorAuthRevokeTokenController',
'session/downgrade/'
=> 'PhabricatorAuthDowngradeSessionController',
'multifactor/'
=> 'PhabricatorAuthNeedsMultiFactorController',
'sshkey/' => array(
'generate/' => 'PhabricatorAuthSSHKeyGenerateController',
'upload/' => 'PhabricatorAuthSSHKeyEditController',
'edit/(?P<id>\d+)/' => 'PhabricatorAuthSSHKeyEditController',
'delete/(?P<id>\d+)/' => 'PhabricatorAuthSSHKeyDeleteController',
),
),
'/oauth/(?P<provider>\w+)/login/'
=> 'PhabricatorAuthOldOAuthRedirectController',
'/login/' => array(
'' => 'PhabricatorAuthStartController',
'email/' => 'PhabricatorEmailLoginController',
'once/'.
'(?P<type>[^/]+)/'.
'(?P<id>\d+)/'.
'(?P<key>[^/]+)/'.
'(?:(?P<emailID>\d+)/)?' => 'PhabricatorAuthOneTimeLoginController',
'refresh/' => 'PhabricatorRefreshCSRFController',
'mustverify/' => 'PhabricatorMustVerifyEmailController',
),
'/emailverify/(?P<code>[^/]+)/'
=> 'PhabricatorEmailVerificationController',
'/logout/' => 'PhabricatorLogoutController',
);
}
protected function getCustomCapabilities() {
return array(
AuthManageProvidersCapability::CAPABILITY => array(
'default' => PhabricatorPolicies::POLICY_ADMIN,
),
);
}
}
diff --git a/src/applications/badges/application/PhabricatorBadgesApplication.php b/src/applications/badges/application/PhabricatorBadgesApplication.php
index dea41ac244..887a11833d 100644
--- a/src/applications/badges/application/PhabricatorBadgesApplication.php
+++ b/src/applications/badges/application/PhabricatorBadgesApplication.php
@@ -1,75 +1,75 @@
<?php
final class PhabricatorBadgesApplication extends PhabricatorApplication {
public function getName() {
return pht('Badges');
}
public function getBaseURI() {
return '/badges/';
}
public function getShortDescription() {
return pht('Achievements and Notority');
}
- public function getFontIcon() {
+ public function getIcon() {
return 'fa-trophy';
}
public function getFlavorText() {
return pht('Build self esteem through gamification.');
}
public function getApplicationGroup() {
return self::GROUP_UTILITIES;
}
public function canUninstall() {
return true;
}
public function isPrototype() {
return true;
}
public function getRoutes() {
return array(
'/badges/' => array(
'(?:query/(?P<queryKey>[^/]+)/)?'
=> 'PhabricatorBadgesListController',
'create/'
=> 'PhabricatorBadgesEditController',
'comment/(?P<id>[1-9]\d*)/'
=> 'PhabricatorBadgesCommentController',
'edit/(?:(?P<id>\d+)/)?'
=> 'PhabricatorBadgesEditController',
'archive/(?:(?P<id>\d+)/)?'
=> 'PhabricatorBadgesArchiveController',
'view/(?:(?P<id>\d+)/)?'
=> 'PhabricatorBadgesViewController',
'recipients/(?P<id>[1-9]\d*)/'
=> 'PhabricatorBadgesEditRecipientsController',
'recipients/(?P<id>[1-9]\d*)/remove/'
=> 'PhabricatorBadgesRemoveRecipientsController',
),
);
}
protected function getCustomCapabilities() {
return array(
PhabricatorBadgesCreateCapability::CAPABILITY => array(
'default' => PhabricatorPolicies::POLICY_ADMIN,
'caption' => pht('Default create policy for badges.'),
),
PhabricatorBadgesDefaultEditCapability::CAPABILITY => array(
'default' => PhabricatorPolicies::POLICY_ADMIN,
'caption' => pht('Default edit policy for badges.'),
'template' => PhabricatorBadgesPHIDType::TYPECONST,
),
);
}
}
diff --git a/src/applications/badges/query/PhabricatorBadgesSearchEngine.php b/src/applications/badges/query/PhabricatorBadgesSearchEngine.php
index ab8432833e..4bad4d2c65 100644
--- a/src/applications/badges/query/PhabricatorBadgesSearchEngine.php
+++ b/src/applications/badges/query/PhabricatorBadgesSearchEngine.php
@@ -1,163 +1,163 @@
<?php
final class PhabricatorBadgesSearchEngine
extends PhabricatorApplicationSearchEngine {
public function getResultTypeDescription() {
return pht('Badge');
}
public function getApplicationClassName() {
return 'PhabricatorBadgesApplication';
}
public function newQuery() {
return new PhabricatorBadgesQuery();
}
public function buildSavedQueryFromRequest(AphrontRequest $request) {
$saved = new PhabricatorSavedQuery();
$saved->setParameter(
'statuses',
$this->readListFromRequest($request, 'statuses'));
$saved->setParameter(
'qualities',
$this->readListFromRequest($request, 'qualities'));
return $saved;
}
protected function buildCustomSearchFields() {
return array(
id(new PhabricatorSearchCheckboxesField())
->setKey('qualities')
->setLabel(pht('Quality'))
->setOptions(
id(new PhabricatorBadgesBadge())
->getQualityNameMap()),
id(new PhabricatorSearchCheckboxesField())
->setKey('statuses')
->setLabel(pht('Status'))
->setOptions(
id(new PhabricatorBadgesBadge())
->getStatusNameMap()),
);
}
protected function buildQueryFromParameters(array $map) {
$query = $this->newQuery();
if ($map['statuses']) {
$query->withStatuses($map['statuses']);
}
if ($map['qualities']) {
$query->withQualities($map['qualities']);
}
return $query;
}
protected function getURI($path) {
return '/badges/'.$path;
}
protected function getBuiltinQueryNames() {
$names = array();
$names['open'] = pht('Active Badges');
$names['all'] = pht('All Badges');
return $names;
}
public function buildSavedQueryFromBuiltin($query_key) {
$query = $this->newSavedQuery();
$query->setQueryKey($query_key);
switch ($query_key) {
case 'all':
return $query;
case 'open':
return $query->setParameter(
'statuses',
array(
PhabricatorBadgesBadge::STATUS_ACTIVE,
));
}
return parent::buildSavedQueryFromBuiltin($query_key);
}
protected function getRequiredHandlePHIDsForResultList(
array $badges,
PhabricatorSavedQuery $query) {
$phids = array();
return $phids;
}
protected function renderResultList(
array $badges,
PhabricatorSavedQuery $query,
array $handles) {
assert_instances_of($badges, 'PhabricatorBadgesBadge');
$viewer = $this->requireViewer();
$list = id(new PHUIObjectItemListView());
foreach ($badges as $badge) {
$quality = idx($badge->getQualityNameMap(), $badge->getQuality());
$mini_badge = id(new PHUIBadgeMiniView())
->setHeader($badge->getName())
->setIcon($badge->getIcon())
->setQuality($badge->getQuality());
$item = id(new PHUIObjectItemView())
->setHeader($badge->getName())
->setBadge($mini_badge)
->setHref('/badges/view/'.$badge->getID().'/')
->addAttribute($quality)
->addAttribute($badge->getFlavor());
if ($badge->isArchived()) {
$item->setDisabled(true);
$item->addIcon('fa-ban', pht('Archived'));
}
$list->addItem($item);
}
$result = new PhabricatorApplicationSearchResultView();
$result->setObjectList($list);
$result->setNoDataString(pht('No badges found.'));
return $result;
}
protected function getNewUserBody() {
$create_button = id(new PHUIButtonView())
->setTag('a')
->setText(pht('Create a Badge'))
->setHref('/badges/create/')
->setColor(PHUIButtonView::GREEN);
- $icon = $this->getApplication()->getFontIcon();
+ $icon = $this->getApplication()->getIcon();
$app_name = $this->getApplication()->getName();
$view = id(new PHUIBigInfoView())
->setIcon($icon)
->setTitle(pht('Welcome to %s', $app_name))
->setDescription(
pht('Badges let you award and distinguish special users '.
'throughout your instance.'))
->addAction($create_button);
return $view;
}
}
diff --git a/src/applications/base/PhabricatorApplication.php b/src/applications/base/PhabricatorApplication.php
index 0ed4917800..0bbb38ff89 100644
--- a/src/applications/base/PhabricatorApplication.php
+++ b/src/applications/base/PhabricatorApplication.php
@@ -1,654 +1,654 @@
<?php
/**
* @task info Application Information
* @task ui UI Integration
* @task uri URI Routing
* @task mail Email integration
* @task fact Fact Integration
* @task meta Application Management
*/
abstract class PhabricatorApplication
extends Phobject
implements PhabricatorPolicyInterface {
const MAX_STATUS_ITEMS = 100;
const GROUP_CORE = 'core';
const GROUP_UTILITIES = 'util';
const GROUP_ADMIN = 'admin';
const GROUP_DEVELOPER = 'developer';
final public static function getApplicationGroups() {
return array(
self::GROUP_CORE => pht('Core Applications'),
self::GROUP_UTILITIES => pht('Utilities'),
self::GROUP_ADMIN => pht('Administration'),
self::GROUP_DEVELOPER => pht('Developer Tools'),
);
}
/* -( Application Information )-------------------------------------------- */
abstract public function getName();
public function getShortDescription() {
return pht('%s Application', $this->getName());
}
final public function isInstalled() {
if (!$this->canUninstall()) {
return true;
}
$prototypes = PhabricatorEnv::getEnvConfig('phabricator.show-prototypes');
if (!$prototypes && $this->isPrototype()) {
return false;
}
$uninstalled = PhabricatorEnv::getEnvConfig(
'phabricator.uninstalled-applications');
return empty($uninstalled[get_class($this)]);
}
public function isPrototype() {
return false;
}
/**
* Return `true` if this application should never appear in application lists
* in the UI. Primarily intended for unit test applications or other
* pseudo-applications.
*
* Few applications should be unlisted. For most applications, use
* @{method:isLaunchable} to hide them from main launch views instead.
*
* @return bool True to remove application from UI lists.
*/
public function isUnlisted() {
return false;
}
/**
* Return `true` if this application is a normal application with a base
* URI and a web interface.
*
* Launchable applications can be pinned to the home page, and show up in the
* "Launcher" view of the Applications application. Making an application
* unlauncahble prevents pinning and hides it from this view.
*
* Usually, an application should be marked unlaunchable if:
*
* - it is available on every page anyway (like search); or
* - it does not have a web interface (like subscriptions); or
* - it is still pre-release and being intentionally buried.
*
* To hide applications more completely, use @{method:isUnlisted}.
*
* @return bool True if the application is launchable.
*/
public function isLaunchable() {
return true;
}
/**
* Return `true` if this application should be pinned by default.
*
* Users who have not yet set preferences see a default list of applications.
*
* @param PhabricatorUser User viewing the pinned application list.
* @return bool True if this application should be pinned by default.
*/
public function isPinnedByDefault(PhabricatorUser $viewer) {
return false;
}
/**
* Returns true if an application is first-party (developed by Phacility)
* and false otherwise.
*
* @return bool True if this application is developed by Phacility.
*/
final public function isFirstParty() {
$where = id(new ReflectionClass($this))->getFileName();
$root = phutil_get_library_root('phabricator');
if (!Filesystem::isDescendant($where, $root)) {
return false;
}
if (Filesystem::isDescendant($where, $root.'/extensions')) {
return false;
}
return true;
}
public function canUninstall() {
return true;
}
final public function getPHID() {
return 'PHID-APPS-'.get_class($this);
}
public function getTypeaheadURI() {
return $this->isLaunchable() ? $this->getBaseURI() : null;
}
public function getBaseURI() {
return null;
}
final public function getApplicationURI($path = '') {
return $this->getBaseURI().ltrim($path, '/');
}
public function getIconURI() {
return null;
}
- public function getFontIcon() {
+ public function getIcon() {
return 'fa-puzzle-piece';
}
public function getApplicationOrder() {
return PHP_INT_MAX;
}
public function getApplicationGroup() {
return self::GROUP_CORE;
}
public function getTitleGlyph() {
return null;
}
final public function getHelpMenuItems(PhabricatorUser $viewer) {
$items = array();
$articles = $this->getHelpDocumentationArticles($viewer);
if ($articles) {
$items[] = id(new PHUIListItemView())
->setType(PHUIListItemView::TYPE_LABEL)
->setName(pht('%s Documentation', $this->getName()));
foreach ($articles as $article) {
$item = id(new PHUIListItemView())
->setName($article['name'])
->setIcon('fa-book')
->setHref($article['href']);
$items[] = $item;
}
}
$command_specs = $this->getMailCommandObjects();
if ($command_specs) {
$items[] = id(new PHUIListItemView())
->setType(PHUIListItemView::TYPE_LABEL)
->setName(pht('Email Help'));
foreach ($command_specs as $key => $spec) {
$object = $spec['object'];
$class = get_class($this);
$href = '/applications/mailcommands/'.$class.'/'.$key.'/';
$item = id(new PHUIListItemView())
->setName($spec['name'])
->setIcon('fa-envelope-o')
->setHref($href);
$items[] = $item;
}
}
return $items;
}
public function getHelpDocumentationArticles(PhabricatorUser $viewer) {
return array();
}
public function getOverview() {
return null;
}
public function getEventListeners() {
return array();
}
public function getRemarkupRules() {
return array();
}
public function getQuicksandURIPatternBlacklist() {
return array();
}
public function getMailCommandObjects() {
return array();
}
/* -( URI Routing )-------------------------------------------------------- */
public function getRoutes() {
return array();
}
public function getResourceRoutes() {
return array();
}
/* -( Email Integration )-------------------------------------------------- */
public function supportsEmailIntegration() {
return false;
}
final protected function getInboundEmailSupportLink() {
return PhabricatorEnv::getDocLink('Configuring Inbound Email');
}
public function getAppEmailBlurb() {
throw new PhutilMethodNotImplementedException();
}
/* -( Fact Integration )--------------------------------------------------- */
public function getFactObjectsForAnalysis() {
return array();
}
/* -( UI Integration )----------------------------------------------------- */
/**
* Render status elements (like "3 Waiting Reviews") for application list
* views. These provide a way to alert users to new or pending action items
* in applications.
*
* @param PhabricatorUser Viewing user.
* @return list<PhabricatorApplicationStatusView> Application status elements.
* @task ui
*/
public function loadStatus(PhabricatorUser $user) {
return array();
}
/**
* You can provide an optional piece of flavor text for the application. This
* is currently rendered in application launch views if the application has no
* status elements.
*
* @return string|null Flavor text.
* @task ui
*/
public function getFlavorText() {
return null;
}
/**
* Build items for the main menu.
*
* @param PhabricatorUser The viewing user.
* @param AphrontController The current controller. May be null for special
* pages like 404, exception handlers, etc.
* @return list<PHUIListItemView> List of menu items.
* @task ui
*/
public function buildMainMenuItems(
PhabricatorUser $user,
PhabricatorController $controller = null) {
return array();
}
/**
* Build extra items for the main menu. Generally, this is used to render
* static dropdowns.
*
* @param PhabricatorUser The viewing user.
* @param AphrontController The current controller. May be null for special
* pages like 404, exception handlers, etc.
* @return view List of menu items.
* @task ui
*/
public function buildMainMenuExtraNodes(
PhabricatorUser $viewer,
PhabricatorController $controller = null) {
return array();
}
/**
* Build items for the "quick create" menu.
*
* @param PhabricatorUser The viewing user.
* @return list<PHUIListItemView> List of menu items.
*/
public function getQuickCreateItems(PhabricatorUser $viewer) {
return array();
}
/* -( Application Management )--------------------------------------------- */
final public static function getByClass($class_name) {
$selected = null;
$applications = self::getAllApplications();
foreach ($applications as $application) {
if (get_class($application) == $class_name) {
$selected = $application;
break;
}
}
if (!$selected) {
throw new Exception(pht("No application '%s'!", $class_name));
}
return $selected;
}
final public static function getAllApplications() {
static $applications;
if ($applications === null) {
$apps = id(new PhutilClassMapQuery())
->setAncestorClass(__CLASS__)
->setSortMethod('getApplicationOrder')
->execute();
// Reorder the applications into "application order". Notably, this
// ensures their event handlers register in application order.
$apps = mgroup($apps, 'getApplicationGroup');
$group_order = array_keys(self::getApplicationGroups());
$apps = array_select_keys($apps, $group_order) + $apps;
$apps = array_mergev($apps);
$applications = $apps;
}
return $applications;
}
final public static function getAllInstalledApplications() {
$all_applications = self::getAllApplications();
$apps = array();
foreach ($all_applications as $app) {
if (!$app->isInstalled()) {
continue;
}
$apps[] = $app;
}
return $apps;
}
/**
* Determine if an application is installed, by application class name.
*
* To check if an application is installed //and// available to a particular
* viewer, user @{method:isClassInstalledForViewer}.
*
* @param string Application class name.
* @return bool True if the class is installed.
* @task meta
*/
final public static function isClassInstalled($class) {
return self::getByClass($class)->isInstalled();
}
/**
* Determine if an application is installed and available to a viewer, by
* application class name.
*
* To check if an application is installed at all, use
* @{method:isClassInstalled}.
*
* @param string Application class name.
* @param PhabricatorUser Viewing user.
* @return bool True if the class is installed for the viewer.
* @task meta
*/
final public static function isClassInstalledForViewer(
$class,
PhabricatorUser $viewer) {
if ($viewer->isOmnipotent()) {
return true;
}
$cache = PhabricatorCaches::getRequestCache();
$viewer_phid = $viewer->getPHID();
$key = 'app.'.$class.'.installed.'.$viewer_phid;
$result = $cache->getKey($key);
if ($result === null) {
if (!self::isClassInstalled($class)) {
$result = false;
} else {
$result = PhabricatorPolicyFilter::hasCapability(
$viewer,
self::getByClass($class),
PhabricatorPolicyCapability::CAN_VIEW);
}
$cache->setKey($key, $result);
}
return $result;
}
/* -( PhabricatorPolicyInterface )----------------------------------------- */
public function getCapabilities() {
return array_merge(
array(
PhabricatorPolicyCapability::CAN_VIEW,
PhabricatorPolicyCapability::CAN_EDIT,
),
array_keys($this->getCustomCapabilities()));
}
public function getPolicy($capability) {
$default = $this->getCustomPolicySetting($capability);
if ($default) {
return $default;
}
switch ($capability) {
case PhabricatorPolicyCapability::CAN_VIEW:
return PhabricatorPolicies::getMostOpenPolicy();
case PhabricatorPolicyCapability::CAN_EDIT:
return PhabricatorPolicies::POLICY_ADMIN;
default:
$spec = $this->getCustomCapabilitySpecification($capability);
return idx($spec, 'default', PhabricatorPolicies::POLICY_USER);
}
}
public function hasAutomaticCapability($capability, PhabricatorUser $viewer) {
return false;
}
public function describeAutomaticCapability($capability) {
return null;
}
/* -( Policies )----------------------------------------------------------- */
protected function getCustomCapabilities() {
return array();
}
final private function getCustomPolicySetting($capability) {
if (!$this->isCapabilityEditable($capability)) {
return null;
}
$policy_locked = PhabricatorEnv::getEnvConfig('policy.locked');
if (isset($policy_locked[$capability])) {
return $policy_locked[$capability];
}
$config = PhabricatorEnv::getEnvConfig('phabricator.application-settings');
$app = idx($config, $this->getPHID());
if (!$app) {
return null;
}
$policy = idx($app, 'policy');
if (!$policy) {
return null;
}
return idx($policy, $capability);
}
final private function getCustomCapabilitySpecification($capability) {
$custom = $this->getCustomCapabilities();
if (!isset($custom[$capability])) {
throw new Exception(pht("Unknown capability '%s'!", $capability));
}
return $custom[$capability];
}
final public function getCapabilityLabel($capability) {
switch ($capability) {
case PhabricatorPolicyCapability::CAN_VIEW:
return pht('Can Use Application');
case PhabricatorPolicyCapability::CAN_EDIT:
return pht('Can Configure Application');
}
$capobj = PhabricatorPolicyCapability::getCapabilityByKey($capability);
if ($capobj) {
return $capobj->getCapabilityName();
}
return null;
}
final public function isCapabilityEditable($capability) {
switch ($capability) {
case PhabricatorPolicyCapability::CAN_VIEW:
return $this->canUninstall();
case PhabricatorPolicyCapability::CAN_EDIT:
return false;
default:
$spec = $this->getCustomCapabilitySpecification($capability);
return idx($spec, 'edit', true);
}
}
final public function getCapabilityCaption($capability) {
switch ($capability) {
case PhabricatorPolicyCapability::CAN_VIEW:
if (!$this->canUninstall()) {
return pht(
'This application is required for Phabricator to operate, so all '.
'users must have access to it.');
} else {
return null;
}
case PhabricatorPolicyCapability::CAN_EDIT:
return null;
default:
$spec = $this->getCustomCapabilitySpecification($capability);
return idx($spec, 'caption');
}
}
final public function getCapabilityTemplatePHIDType($capability) {
switch ($capability) {
case PhabricatorPolicyCapability::CAN_VIEW:
case PhabricatorPolicyCapability::CAN_EDIT:
return null;
}
$spec = $this->getCustomCapabilitySpecification($capability);
return idx($spec, 'template');
}
final public function getDefaultObjectTypePolicyMap() {
$map = array();
foreach ($this->getCustomCapabilities() as $capability => $spec) {
if (empty($spec['template'])) {
continue;
}
if (empty($spec['capability'])) {
continue;
}
$default = $this->getPolicy($capability);
$map[$spec['template']][$spec['capability']] = $default;
}
return $map;
}
public function getApplicationSearchDocumentTypes() {
return array();
}
protected function getEditRoutePattern($base = null) {
return $base.'(?:'.
'(?P<id>[0-9]\d*)/)?'.
'(?:'.
'(?:'.
'(?P<editAction>parameters|nodefault|nocreate|nomanage|comment)'.
'|'.
'(?:form/(?P<formKey>[^/]+))'.
')'.
'/)?';
}
protected function getQueryRoutePattern($base = null) {
return $base.'(?:query/(?P<queryKey>[^/]+)/)?';
}
protected function getPanelRouting($controller) {
$edit_route = $this->getEditRoutePattern();
return array(
'(?P<panelAction>view)/(?P<panelID>[^/]+)/' => $controller,
'(?P<panelAction>hide)/(?P<panelID>[^/]+)/' => $controller,
'(?P<panelAction>default)/(?P<panelID>[^/]+)/' => $controller,
'(?P<panelAction>configure)/' => $controller,
'(?P<panelAction>reorder)/' => $controller,
'(?P<panelAction>edit)/'.$edit_route => $controller,
'(?P<panelAction>new)/(?<panelKey>[^/]+)/'.$edit_route => $controller,
'(?P<panelAction>builtin)/(?<panelID>[^/]+)/'.$edit_route
=> $controller,
);
}
}
diff --git a/src/applications/base/controller/PhabricatorController.php b/src/applications/base/controller/PhabricatorController.php
index 1fe68abab3..e6997d97ab 100644
--- a/src/applications/base/controller/PhabricatorController.php
+++ b/src/applications/base/controller/PhabricatorController.php
@@ -1,590 +1,590 @@
<?php
abstract class PhabricatorController extends AphrontController {
private $handles;
public function shouldRequireLogin() {
return true;
}
public function shouldRequireAdmin() {
return false;
}
public function shouldRequireEnabledUser() {
return true;
}
public function shouldAllowPublic() {
return false;
}
public function shouldAllowPartialSessions() {
return false;
}
public function shouldRequireEmailVerification() {
return PhabricatorUserEmail::isEmailVerificationRequired();
}
public function shouldAllowRestrictedParameter($parameter_name) {
return false;
}
public function shouldRequireMultiFactorEnrollment() {
if (!$this->shouldRequireLogin()) {
return false;
}
if (!$this->shouldRequireEnabledUser()) {
return false;
}
if ($this->shouldAllowPartialSessions()) {
return false;
}
$user = $this->getRequest()->getUser();
if (!$user->getIsStandardUser()) {
return false;
}
return PhabricatorEnv::getEnvConfig('security.require-multi-factor-auth');
}
public function shouldAllowLegallyNonCompliantUsers() {
return false;
}
public function isGlobalDragAndDropUploadEnabled() {
return false;
}
public function willBeginExecution() {
$request = $this->getRequest();
if ($request->getUser()) {
// NOTE: Unit tests can set a user explicitly. Normal requests are not
// permitted to do this.
PhabricatorTestCase::assertExecutingUnitTests();
$user = $request->getUser();
} else {
$user = new PhabricatorUser();
$session_engine = new PhabricatorAuthSessionEngine();
$phsid = $request->getCookie(PhabricatorCookies::COOKIE_SESSION);
if (strlen($phsid)) {
$session_user = $session_engine->loadUserForSession(
PhabricatorAuthSession::TYPE_WEB,
$phsid);
if ($session_user) {
$user = $session_user;
}
} else {
// If the client doesn't have a session token, generate an anonymous
// session. This is used to provide CSRF protection to logged-out users.
$phsid = $session_engine->establishSession(
PhabricatorAuthSession::TYPE_WEB,
null,
$partial = false);
// This may be a resource request, in which case we just don't set
// the cookie.
if ($request->canSetCookies()) {
$request->setCookie(PhabricatorCookies::COOKIE_SESSION, $phsid);
}
}
if (!$user->isLoggedIn()) {
$user->attachAlternateCSRFString(PhabricatorHash::digest($phsid));
}
$request->setUser($user);
}
PhabricatorEnv::setLocaleCode($user->getTranslation());
$preferences = $user->loadPreferences();
if (PhabricatorEnv::getEnvConfig('darkconsole.enabled')) {
$dark_console = PhabricatorUserPreferences::PREFERENCE_DARK_CONSOLE;
if ($preferences->getPreference($dark_console) ||
PhabricatorEnv::getEnvConfig('darkconsole.always-on')) {
$console = new DarkConsoleCore();
$request->getApplicationConfiguration()->setConsole($console);
}
}
// NOTE: We want to set up the user first so we can render a real page
// here, but fire this before any real logic.
$restricted = array(
'code',
);
foreach ($restricted as $parameter) {
if ($request->getExists($parameter)) {
if (!$this->shouldAllowRestrictedParameter($parameter)) {
throw new Exception(
pht(
'Request includes restricted parameter "%s", but this '.
'controller ("%s") does not whitelist it. Refusing to '.
'serve this request because it might be part of a redirection '.
'attack.',
$parameter,
get_class($this)));
}
}
}
if ($this->shouldRequireEnabledUser()) {
if ($user->isLoggedIn() && !$user->getIsApproved()) {
$controller = new PhabricatorAuthNeedsApprovalController();
return $this->delegateToController($controller);
}
if ($user->getIsDisabled()) {
$controller = new PhabricatorDisabledUserController();
return $this->delegateToController($controller);
}
}
$auth_class = 'PhabricatorAuthApplication';
$auth_application = PhabricatorApplication::getByClass($auth_class);
// Require partial sessions to finish login before doing anything.
if (!$this->shouldAllowPartialSessions()) {
if ($user->hasSession() &&
$user->getSession()->getIsPartial()) {
$login_controller = new PhabricatorAuthFinishController();
$this->setCurrentApplication($auth_application);
return $this->delegateToController($login_controller);
}
}
// Check if the user needs to configure MFA.
$need_mfa = $this->shouldRequireMultiFactorEnrollment();
$have_mfa = $user->getIsEnrolledInMultiFactor();
if ($need_mfa && !$have_mfa) {
// Check if the cache is just out of date. Otherwise, roadblock the user
// and require MFA enrollment.
$user->updateMultiFactorEnrollment();
if (!$user->getIsEnrolledInMultiFactor()) {
$mfa_controller = new PhabricatorAuthNeedsMultiFactorController();
$this->setCurrentApplication($auth_application);
return $this->delegateToController($mfa_controller);
}
}
if ($this->shouldRequireLogin()) {
// This actually means we need either:
// - a valid user, or a public controller; and
// - permission to see the application; and
// - permission to see at least one Space if spaces are configured.
$allow_public = $this->shouldAllowPublic() &&
PhabricatorEnv::getEnvConfig('policy.allow-public');
// If this controller isn't public, and the user isn't logged in, require
// login.
if (!$allow_public && !$user->isLoggedIn()) {
$login_controller = new PhabricatorAuthStartController();
$this->setCurrentApplication($auth_application);
return $this->delegateToController($login_controller);
}
if ($user->isLoggedIn()) {
if ($this->shouldRequireEmailVerification()) {
if (!$user->getIsEmailVerified()) {
$controller = new PhabricatorMustVerifyEmailController();
$this->setCurrentApplication($auth_application);
return $this->delegateToController($controller);
}
}
}
// If Spaces are configured, require that the user have access to at
// least one. If we don't do this, they'll get confusing error messages
// later on.
$spaces = PhabricatorSpacesNamespaceQuery::getSpacesExist();
if ($spaces) {
$viewer_spaces = PhabricatorSpacesNamespaceQuery::getViewerSpaces(
$user);
if (!$viewer_spaces) {
$controller = new PhabricatorSpacesNoAccessController();
return $this->delegateToController($controller);
}
}
// If the user doesn't have access to the application, don't let them use
// any of its controllers. We query the application in order to generate
// a policy exception if the viewer doesn't have permission.
$application = $this->getCurrentApplication();
if ($application) {
id(new PhabricatorApplicationQuery())
->setViewer($user)
->withPHIDs(array($application->getPHID()))
->executeOne();
}
}
if (!$this->shouldAllowLegallyNonCompliantUsers()) {
$legalpad_class = 'PhabricatorLegalpadApplication';
$legalpad = id(new PhabricatorApplicationQuery())
->setViewer($user)
->withClasses(array($legalpad_class))
->withInstalled(true)
->execute();
$legalpad = head($legalpad);
$doc_query = id(new LegalpadDocumentQuery())
->setViewer($user)
->withSignatureRequired(1)
->needViewerSignatures(true);
if ($user->hasSession() &&
!$user->getSession()->getIsPartial() &&
!$user->getSession()->getSignedLegalpadDocuments() &&
$user->isLoggedIn() &&
$legalpad) {
$sign_docs = $doc_query->execute();
$must_sign_docs = array();
foreach ($sign_docs as $sign_doc) {
if (!$sign_doc->getUserSignature($user->getPHID())) {
$must_sign_docs[] = $sign_doc;
}
}
if ($must_sign_docs) {
$controller = new LegalpadDocumentSignController();
$this->getRequest()->setURIMap(array(
'id' => head($must_sign_docs)->getID(),
));
$this->setCurrentApplication($legalpad);
return $this->delegateToController($controller);
} else {
$engine = id(new PhabricatorAuthSessionEngine())
->signLegalpadDocuments($user, $sign_docs);
}
}
}
// NOTE: We do this last so that users get a login page instead of a 403
// if they need to login.
if ($this->shouldRequireAdmin() && !$user->getIsAdmin()) {
return new Aphront403Response();
}
}
public function getApplicationURI($path = '') {
if (!$this->getCurrentApplication()) {
throw new Exception(pht('No application!'));
}
return $this->getCurrentApplication()->getApplicationURI($path);
}
public function willSendResponse(AphrontResponse $response) {
$request = $this->getRequest();
if ($response instanceof AphrontDialogResponse) {
if (!$request->isAjax() && !$request->isQuicksand()) {
$dialog = $response->getDialog();
$title = $dialog->getTitle();
$short = $dialog->getShortTitle();
$crumbs = $this->buildApplicationCrumbs();
$crumbs->addTextCrumb(coalesce($short, $title));
$page_content = array(
$crumbs,
$response->buildResponseString(),
);
$view = id(new PhabricatorStandardPageView())
->setRequest($request)
->setController($this)
->setDeviceReady(true)
->setTitle($title)
->appendChild($page_content);
$response = id(new AphrontWebpageResponse())
->setContent($view->render())
->setHTTPResponseCode($response->getHTTPResponseCode());
} else {
$response->getDialog()->setIsStandalone(true);
return id(new AphrontAjaxResponse())
->setContent(array(
'dialog' => $response->buildResponseString(),
));
}
} else if ($response instanceof AphrontRedirectResponse) {
if ($request->isAjax() || $request->isQuicksand()) {
return id(new AphrontAjaxResponse())
->setContent(
array(
'redirect' => $response->getURI(),
));
}
}
return $response;
}
/**
* WARNING: Do not call this in new code.
*
* @deprecated See "Handles Technical Documentation".
*/
protected function loadViewerHandles(array $phids) {
return id(new PhabricatorHandleQuery())
->setViewer($this->getRequest()->getUser())
->withPHIDs($phids)
->execute();
}
public function buildApplicationMenu() {
return null;
}
protected function buildApplicationCrumbs() {
$crumbs = array();
$application = $this->getCurrentApplication();
if ($application) {
- $icon = $application->getFontIcon();
+ $icon = $application->getIcon();
if (!$icon) {
$icon = 'fa-puzzle';
}
$crumbs[] = id(new PHUICrumbView())
->setHref($this->getApplicationURI())
->setName($application->getName())
->setIcon($icon);
}
$view = new PHUICrumbsView();
foreach ($crumbs as $crumb) {
$view->addCrumb($crumb);
}
return $view;
}
protected function hasApplicationCapability($capability) {
return PhabricatorPolicyFilter::hasCapability(
$this->getRequest()->getUser(),
$this->getCurrentApplication(),
$capability);
}
protected function requireApplicationCapability($capability) {
PhabricatorPolicyFilter::requireCapability(
$this->getRequest()->getUser(),
$this->getCurrentApplication(),
$capability);
}
protected function explainApplicationCapability(
$capability,
$positive_message,
$negative_message) {
$can_act = $this->hasApplicationCapability($capability);
if ($can_act) {
$message = $positive_message;
$icon_name = 'fa-play-circle-o lightgreytext';
} else {
$message = $negative_message;
$icon_name = 'fa-lock';
}
$icon = id(new PHUIIconView())
->setIcon($icon_name);
require_celerity_resource('policy-css');
$phid = $this->getCurrentApplication()->getPHID();
$explain_uri = "/policy/explain/{$phid}/{$capability}/";
$message = phutil_tag(
'div',
array(
'class' => 'policy-capability-explanation',
),
array(
$icon,
javelin_tag(
'a',
array(
'href' => $explain_uri,
'sigil' => 'workflow',
),
$message),
));
return array($can_act, $message);
}
public function getDefaultResourceSource() {
return 'phabricator';
}
/**
* Create a new @{class:AphrontDialogView} with defaults filled in.
*
* @return AphrontDialogView New dialog.
*/
public function newDialog() {
$submit_uri = new PhutilURI($this->getRequest()->getRequestURI());
$submit_uri = $submit_uri->getPath();
return id(new AphrontDialogView())
->setUser($this->getRequest()->getUser())
->setSubmitURI($submit_uri);
}
public function newPage() {
$page = id(new PhabricatorStandardPageView())
->setRequest($this->getRequest())
->setController($this)
->setDeviceReady(true);
$application = $this->getCurrentApplication();
if ($application) {
$page->setApplicationName($application->getName());
if ($application->getTitleGlyph()) {
$page->setGlyph($application->getTitleGlyph());
}
}
$viewer = $this->getRequest()->getUser();
if ($viewer) {
$page->setUser($viewer);
}
return $page;
}
public function newApplicationMenu() {
return id(new PHUIApplicationMenuView())
->setViewer($this->getRequest()->getUser());
}
protected function buildTransactionTimeline(
PhabricatorApplicationTransactionInterface $object,
PhabricatorApplicationTransactionQuery $query,
PhabricatorMarkupEngine $engine = null,
$render_data = array()) {
$viewer = $this->getRequest()->getUser();
$xaction = $object->getApplicationTransactionTemplate();
$view = $xaction->getApplicationTransactionViewObject();
$pager = id(new AphrontCursorPagerView())
->readFromRequest($this->getRequest())
->setURI(new PhutilURI(
'/transactions/showolder/'.$object->getPHID().'/'));
$xactions = $query
->setViewer($viewer)
->withObjectPHIDs(array($object->getPHID()))
->needComments(true)
->executeWithCursorPager($pager);
$xactions = array_reverse($xactions);
if ($engine) {
foreach ($xactions as $xaction) {
if ($xaction->getComment()) {
$engine->addObject(
$xaction->getComment(),
PhabricatorApplicationTransactionComment::MARKUP_FIELD_COMMENT);
}
}
$engine->process();
$view->setMarkupEngine($engine);
}
$timeline = $view
->setUser($viewer)
->setObjectPHID($object->getPHID())
->setTransactions($xactions)
->setPager($pager)
->setRenderData($render_data)
->setQuoteTargetID($this->getRequest()->getStr('quoteTargetID'))
->setQuoteRef($this->getRequest()->getStr('quoteRef'));
$object->willRenderTimeline($timeline, $this->getRequest());
return $timeline;
}
public function buildApplicationCrumbsForEditEngine() {
// TODO: This is kind of gross, I'm bascially just making this public so
// I can use it in EditEngine. We could do this without making it public
// by using controller delegation, or make it properly public.
return $this->buildApplicationCrumbs();
}
/* -( Deprecated )--------------------------------------------------------- */
/**
* DEPRECATED. Use @{method:newPage}.
*/
public function buildStandardPageView() {
return $this->newPage();
}
/**
* DEPRECATED. Use @{method:newPage}.
*/
public function buildStandardPageResponse($view, array $data) {
$page = $this->buildStandardPageView();
$page->appendChild($view);
return $page->produceAphrontResponse();
}
/**
* DEPRECATED. Use @{method:newPage}.
*/
public function buildApplicationPage($view, array $options) {
$page = $this->newPage();
$title = PhabricatorEnv::getEnvConfig('phabricator.serious-business') ?
'Phabricator' :
pht('Bacon Ice Cream for Breakfast');
$page->setTitle(idx($options, 'title', $title));
if (idx($options, 'class')) {
$page->addClass($options['class']);
}
if (!($view instanceof AphrontSideNavFilterView)) {
$nav = new AphrontSideNavFilterView();
$nav->appendChild($view);
$view = $nav;
}
$page->appendChild($view);
$object_phids = idx($options, 'pageObjects', array());
if ($object_phids) {
$page->setPageObjectPHIDs($object_phids);
}
if (!idx($options, 'device', true)) {
$page->setDeviceReady(false);
}
$page->setShowFooter(idx($options, 'showFooter', true));
$page->setShowChrome(idx($options, 'chrome', true));
return $page->produceAphrontResponse();
}
}
diff --git a/src/applications/calendar/application/PhabricatorCalendarApplication.php b/src/applications/calendar/application/PhabricatorCalendarApplication.php
index 1f8ea57383..cf05e96666 100644
--- a/src/applications/calendar/application/PhabricatorCalendarApplication.php
+++ b/src/applications/calendar/application/PhabricatorCalendarApplication.php
@@ -1,102 +1,102 @@
<?php
final class PhabricatorCalendarApplication extends PhabricatorApplication {
public function getName() {
return pht('Calendar');
}
public function getShortDescription() {
return pht('Upcoming Events');
}
public function getFlavorText() {
return pht('Never miss an episode ever again.');
}
public function getBaseURI() {
return '/calendar/';
}
- public function getFontIcon() {
+ public function getIcon() {
return 'fa-calendar';
}
public function getTitleGlyph() {
// Unicode has a calendar character but it's in some distant code plane,
// use "keyboard" since it looks vaguely similar.
return "\xE2\x8C\xA8";
}
public function isPrototype() {
return true;
}
public function getRemarkupRules() {
return array(
new PhabricatorCalendarRemarkupRule(),
);
}
public function getRoutes() {
return array(
'/E(?P<id>[1-9]\d*)(?:/(?P<sequence>\d+))?'
=> 'PhabricatorCalendarEventViewController',
'/calendar/' => array(
'(?:query/(?P<queryKey>[^/]+)/(?:(?P<year>\d+)/'.
'(?P<month>\d+)/)?(?:(?P<day>\d+)/)?)?'
=> 'PhabricatorCalendarEventListController',
'event/' => array(
'create/'
=> 'PhabricatorCalendarEventEditController',
'edit/(?P<id>[1-9]\d*)/(?:(?P<sequence>\d+)/)?'
=> 'PhabricatorCalendarEventEditController',
'drag/(?P<id>[1-9]\d*)/'
=> 'PhabricatorCalendarEventDragController',
'cancel/(?P<id>[1-9]\d*)/(?:(?P<sequence>\d+)/)?'
=> 'PhabricatorCalendarEventCancelController',
'(?P<action>join|decline|accept)/(?P<id>[1-9]\d*)/'
=> 'PhabricatorCalendarEventJoinController',
'comment/(?P<id>[1-9]\d*)/(?:(?P<sequence>\d+)/)?'
=> 'PhabricatorCalendarEventCommentController',
),
),
);
}
public function getHelpDocumentationArticles(PhabricatorUser $viewer) {
return array(
array(
'name' => pht('Calendar User Guide'),
'href' => PhabricatorEnv::getDoclink('Calendar User Guide'),
),
);
}
public function getQuickCreateItems(PhabricatorUser $viewer) {
$items = array();
$item = id(new PHUIListItemView())
->setName(pht('Calendar Event'))
->setIcon('fa-calendar')
->setHref($this->getBaseURI().'event/create/');
$items[] = $item;
return $items;
}
public function getMailCommandObjects() {
return array(
'event' => array(
'name' => pht('Email Commands: Events'),
'header' => pht('Interacting with Calendar Events'),
'object' => new PhabricatorCalendarEvent(),
'summary' => pht(
'This page documents the commands you can use to interact with '.
'events in Calendar. These commands work when creating new tasks '.
'via email and when replying to existing tasks.'),
),
);
}
}
diff --git a/src/applications/chatlog/application/PhabricatorChatLogApplication.php b/src/applications/chatlog/application/PhabricatorChatLogApplication.php
index b2023ce07c..912ddd9b6b 100644
--- a/src/applications/chatlog/application/PhabricatorChatLogApplication.php
+++ b/src/applications/chatlog/application/PhabricatorChatLogApplication.php
@@ -1,43 +1,43 @@
<?php
final class PhabricatorChatLogApplication extends PhabricatorApplication {
public function getBaseURI() {
return '/chatlog/';
}
public function getName() {
return pht('ChatLog');
}
public function getShortDescription() {
return pht('(Deprecated)');
}
- public function getFontIcon() {
+ public function getIcon() {
return 'fa-coffee';
}
public function isPrototype() {
return true;
}
public function getTitleGlyph() {
return "\xE0\xBC\x84";
}
public function getApplicationGroup() {
return self::GROUP_UTILITIES;
}
public function getRoutes() {
return array(
'/chatlog/' => array(
'' => 'PhabricatorChatLogChannelListController',
'channel/(?P<channelID>[^/]+)/'
=> 'PhabricatorChatLogChannelLogController',
),
);
}
}
diff --git a/src/applications/conduit/application/PhabricatorConduitApplication.php b/src/applications/conduit/application/PhabricatorConduitApplication.php
index 7a0ca0e4b9..a036860aad 100644
--- a/src/applications/conduit/application/PhabricatorConduitApplication.php
+++ b/src/applications/conduit/application/PhabricatorConduitApplication.php
@@ -1,65 +1,65 @@
<?php
final class PhabricatorConduitApplication extends PhabricatorApplication {
public function getBaseURI() {
return '/conduit/';
}
- public function getFontIcon() {
+ public function getIcon() {
return 'fa-tty';
}
public function canUninstall() {
return false;
}
public function getHelpDocumentationArticles(PhabricatorUser $viewer) {
return array(
array(
'name' => pht('Conduit API Overview'),
'href' => PhabricatorEnv::getDoclink('Conduit API Overview'),
),
);
}
public function getName() {
return pht('Conduit');
}
public function getShortDescription() {
return pht('Developer API');
}
public function getTitleGlyph() {
return "\xE2\x87\xB5";
}
public function getApplicationGroup() {
return self::GROUP_DEVELOPER;
}
public function getApplicationOrder() {
return 0.100;
}
public function getRoutes() {
return array(
'/conduit/' => array(
'(?:query/(?P<queryKey>[^/]+)/)?' => 'PhabricatorConduitListController',
'method/(?P<method>[^/]+)/' => 'PhabricatorConduitConsoleController',
'log/(?:query/(?P<queryKey>[^/]+)/)?' =>
'PhabricatorConduitLogController',
'log/view/(?P<view>[^/]+)/' => 'PhabricatorConduitLogController',
'token/' => 'PhabricatorConduitTokenController',
'token/edit/(?:(?P<id>\d+)/)?' =>
'PhabricatorConduitTokenEditController',
'token/terminate/(?:(?P<id>\d+)/)?' =>
'PhabricatorConduitTokenTerminateController',
'login/' => 'PhabricatorConduitTokenHandshakeController',
),
'/api/(?P<method>[^/]+)' => 'PhabricatorConduitAPIController',
);
}
}
diff --git a/src/applications/config/application/PhabricatorConfigApplication.php b/src/applications/config/application/PhabricatorConfigApplication.php
index 36bac1d25b..8570484e31 100644
--- a/src/applications/config/application/PhabricatorConfigApplication.php
+++ b/src/applications/config/application/PhabricatorConfigApplication.php
@@ -1,69 +1,69 @@
<?php
final class PhabricatorConfigApplication extends PhabricatorApplication {
public function getBaseURI() {
return '/config/';
}
- public function getFontIcon() {
+ public function getIcon() {
return 'fa-sliders';
}
public function isPinnedByDefault(PhabricatorUser $viewer) {
return $viewer->getIsAdmin();
}
public function getTitleGlyph() {
return "\xE2\x98\xBA";
}
public function getApplicationGroup() {
return self::GROUP_ADMIN;
}
public function canUninstall() {
return false;
}
public function getName() {
return 'Config';
}
public function getShortDescription() {
return pht('Configure Phabricator');
}
public function getRoutes() {
return array(
'/config/' => array(
'' => 'PhabricatorConfigListController',
'all/' => 'PhabricatorConfigAllController',
'history/' => 'PhabricatorConfigHistoryController',
'edit/(?P<key>[\w\.\-]+)/' => 'PhabricatorConfigEditController',
'group/(?P<key>[^/]+)/' => 'PhabricatorConfigGroupController',
'welcome/' => 'PhabricatorConfigWelcomeController',
'database/'.
'(?:(?P<database>[^/]+)/'.
'(?:(?P<table>[^/]+)/'.
'(?:(?:col/(?P<column>[^/]+)|key/(?P<key>[^/]+))/)?)?)?'
=> 'PhabricatorConfigDatabaseStatusController',
'dbissue/' => 'PhabricatorConfigDatabaseIssueController',
'(?P<verb>ignore|unignore)/(?P<key>[^/]+)/'
=> 'PhabricatorConfigIgnoreController',
'issue/' => array(
'' => 'PhabricatorConfigIssueListController',
'(?P<key>[^/]+)/' => 'PhabricatorConfigIssueViewController',
),
'cache/' => array(
'' => 'PhabricatorConfigCacheController',
'purge/' => 'PhabricatorConfigPurgeCacheController',
),
'module/' => array(
'(?P<module>[^/]+)/' => 'PhabricatorConfigModuleController',
),
),
);
}
}
diff --git a/src/applications/config/controller/PhabricatorConfigListController.php b/src/applications/config/controller/PhabricatorConfigListController.php
index 6a1823ecda..9e87995ebc 100644
--- a/src/applications/config/controller/PhabricatorConfigListController.php
+++ b/src/applications/config/controller/PhabricatorConfigListController.php
@@ -1,64 +1,64 @@
<?php
final class PhabricatorConfigListController
extends PhabricatorConfigController {
public function handleRequest(AphrontRequest $request) {
$viewer = $request->getViewer();
$nav = $this->buildSideNavView();
$nav->selectFilter('/');
$groups = PhabricatorApplicationConfigOptions::loadAll();
$core_list = $this->buildConfigOptionsList($groups, 'core');
$apps_list = $this->buildConfigOptionsList($groups, 'apps');
$title = pht('Phabricator Configuration');
$core = id(new PHUIObjectBoxView())
->setHeaderText($title)
->setObjectList($core_list);
$apps = id(new PHUIObjectBoxView())
->setHeaderText(pht('Applications Configuration'))
->setObjectList($apps_list);
$nav->appendChild(
array(
$core,
$apps,
));
$crumbs = $this
->buildApplicationCrumbs()
->addTextCrumb(pht('Config'), $this->getApplicationURI());
$nav->setCrumbs($crumbs);
return $this->buildApplicationPage(
$nav,
array(
'title' => $title,
));
}
private function buildConfigOptionsList(array $groups, $type) {
assert_instances_of($groups, 'PhabricatorApplicationConfigOptions');
$list = new PHUIObjectItemListView();
$groups = msort($groups, 'getName');
foreach ($groups as $group) {
if ($group->getGroup() == $type) {
$item = id(new PHUIObjectItemView())
->setHeader($group->getName())
->setHref('/config/group/'.$group->getKey().'/')
->addAttribute($group->getDescription())
- ->setFontIcon($group->getFontIcon());
+ ->setIcon($group->getIcon());
$list->addItem($item);
}
}
return $list;
}
}
diff --git a/src/applications/config/module/PhabricatorConfigPHIDModule.php b/src/applications/config/module/PhabricatorConfigPHIDModule.php
index 0a1eaf7b3f..cd7d0e0092 100644
--- a/src/applications/config/module/PhabricatorConfigPHIDModule.php
+++ b/src/applications/config/module/PhabricatorConfigPHIDModule.php
@@ -1,79 +1,79 @@
<?php
final class PhabricatorConfigPHIDModule extends PhabricatorConfigModule {
public function getModuleKey() {
return 'phid';
}
public function getModuleName() {
return pht('PHID Types');
}
public function renderModuleStatus(AphrontRequest $request) {
$viewer = $request->getViewer();
$types = PhabricatorPHIDType::getAllTypes();
$types = msort($types, 'getTypeConstant');
$rows = array();
foreach ($types as $key => $type) {
$class_name = $type->getPHIDTypeApplicationClass();
if ($class_name !== null) {
$app = PhabricatorApplication::getByClass($class_name);
$app_name = $app->getName();
- $icon = $app->getFontIcon();
+ $icon = $app->getIcon();
if ($icon) {
$app_icon = id(new PHUIIconView())->setIcon($icon);
} else {
$app_icon = null;
}
} else {
$app_name = null;
$app_icon = null;
}
$icon = $type->getTypeIcon();
if ($icon) {
$type_icon = id(new PHUIIconView())->setIcon($icon);
} else {
$type_icon = null;
}
$rows[] = array(
$type->getTypeConstant(),
get_class($type),
$app_icon,
$app_name,
$type_icon,
$type->getTypeName(),
);
}
$table = id(new AphrontTableView($rows))
->setHeaders(
array(
pht('Constant'),
pht('Class'),
null,
pht('Application'),
null,
pht('Name'),
))
->setColumnClasses(
array(
null,
'pri',
'icon',
null,
'icon',
'wide',
));
return id(new PHUIObjectBoxView())
->setHeaderText(pht('PHID Types'))
->setTable($table);
}
}
diff --git a/src/applications/config/option/PhabricatorAWSConfigOptions.php b/src/applications/config/option/PhabricatorAWSConfigOptions.php
index af328ba0af..faed807ae3 100644
--- a/src/applications/config/option/PhabricatorAWSConfigOptions.php
+++ b/src/applications/config/option/PhabricatorAWSConfigOptions.php
@@ -1,66 +1,66 @@
<?php
final class PhabricatorAWSConfigOptions
extends PhabricatorApplicationConfigOptions {
public function getName() {
return pht('Amazon Web Services');
}
public function getDescription() {
return pht('Configure integration with AWS (EC2, SES, S3, etc).');
}
- public function getFontIcon() {
+ public function getIcon() {
return 'fa-server';
}
public function getGroup() {
return 'core';
}
public function getOptions() {
return array(
$this->newOption('amazon-ses.access-key', 'string', null)
->setLocked(true)
->setDescription(pht('Access key for Amazon SES.')),
$this->newOption('amazon-ses.secret-key', 'string', null)
->setHidden(true)
->setDescription(pht('Secret key for Amazon SES.')),
$this->newOption('amazon-s3.access-key', 'string', null)
->setLocked(true)
->setDescription(pht('Access key for Amazon S3.')),
$this->newOption('amazon-s3.secret-key', 'string', null)
->setHidden(true)
->setDescription(pht('Secret key for Amazon S3.')),
$this->newOption('amazon-s3.region', 'string', null)
->setLocked(true)
->setDescription(
pht(
'Amazon S3 region where your S3 bucket is located. When you '.
'specify a region, you should also specify a corresponding '.
'endpoint with `amazon-s3.endpoint`. You can find a list of '.
'available regions and endpoints in the AWS documentation.'))
->addExample('us-west-1', pht('USWest Region')),
$this->newOption('amazon-s3.endpoint', 'string', null)
->setLocked(true)
->setDescription(
pht(
'Explicit S3 endpoint to use. This should be the endpoint '.
'which corresponds to the region you have selected in '.
'`amazon-s3.region`. Phabricator can not determine the correct '.
'endpoint automatically because some endpoint locations are '.
'irregular.'))
->addExample(
's3-us-west-1.amazonaws.com',
pht('Use specific endpoint')),
$this->newOption('amazon-ec2.access-key', 'string', null)
->setLocked(true)
->setDescription(pht('Access key for Amazon EC2.')),
$this->newOption('amazon-ec2.secret-key', 'string', null)
->setHidden(true)
->setDescription(pht('Secret key for Amazon EC2.')),
);
}
}
diff --git a/src/applications/config/option/PhabricatorAccessLogConfigOptions.php b/src/applications/config/option/PhabricatorAccessLogConfigOptions.php
index 5bc55f64a7..6183f9936f 100644
--- a/src/applications/config/option/PhabricatorAccessLogConfigOptions.php
+++ b/src/applications/config/option/PhabricatorAccessLogConfigOptions.php
@@ -1,135 +1,135 @@
<?php
final class PhabricatorAccessLogConfigOptions
extends PhabricatorApplicationConfigOptions {
public function getName() {
return pht('Access Logs');
}
public function getDescription() {
return pht('Configure the access logs, which log HTTP/SSH requests.');
}
- public function getFontIcon() {
+ public function getIcon() {
return 'fa-list';
}
public function getGroup() {
return 'core';
}
public function getOptions() {
$common_map = array(
'C' => pht('The controller or workflow which handled the request.'),
'c' => pht('The HTTP response code or process exit code.'),
'D' => pht('The request date.'),
'e' => pht('Epoch timestamp.'),
'h' => pht("The webserver's host name."),
'p' => pht('The PID of the server process.'),
'r' => pht('The remote IP.'),
'T' => pht('The request duration, in microseconds.'),
'U' => pht('The request path, or request target.'),
'm' => pht('For conduit, the Conduit method which was invoked.'),
'u' => pht('The logged-in username, if one is logged in.'),
'P' => pht('The logged-in user PHID, if one is logged in.'),
'i' => pht('Request input, in bytes.'),
'o' => pht('Request output, in bytes.'),
);
$http_map = $common_map + array(
'R' => pht('The HTTP referrer.'),
'M' => pht('The HTTP method.'),
);
$ssh_map = $common_map + array(
's' => pht('The system user.'),
'S' => pht('The system sudo user.'),
'k' => pht('ID of the SSH key used to authenticate the request.'),
);
$http_desc = pht(
'Format for the HTTP access log. Use `%s` to set the path. '.
'Available variables are:',
'log.access.path');
$http_desc .= "\n\n";
$http_desc .= $this->renderMapHelp($http_map);
$ssh_desc = pht(
'Format for the SSH access log. Use %s to set the path. '.
'Available variables are:',
'log.ssh.path');
$ssh_desc .= "\n\n";
$ssh_desc .= $this->renderMapHelp($ssh_map);
return array(
$this->newOption('log.access.path', 'string', null)
->setLocked(true)
->setSummary(pht('Access log location.'))
->setDescription(
pht(
"To enable the Phabricator access log, specify a path. The ".
"Phabricator access than normal HTTP access logs (for instance, ".
"it can show logged-in users, controllers, and other application ".
"data).\n\n".
"If not set, no log will be written."))
->addExample(
null,
pht('Disable access log.'))
->addExample(
'/var/log/phabricator/access.log',
pht('Write access log here.')),
$this->newOption(
'log.access.format',
// NOTE: This is 'wild' intead of 'string' so "\t" and such can be
// specified.
'wild',
"[%D]\t%p\t%h\t%r\t%u\t%C\t%m\t%U\t%R\t%c\t%T")
->setLocked(true)
->setSummary(pht('Access log format.'))
->setDescription($http_desc),
$this->newOption('log.ssh.path', 'string', null)
->setLocked(true)
->setSummary(pht('SSH log location.'))
->setDescription(
pht(
"To enable the Phabricator SSH log, specify a path. The ".
"access log can provide more detailed information about SSH ".
"access than a normal SSH log (for instance, it can show ".
"logged-in users, commands, and other application data).\n\n".
"If not set, no log will be written."))
->addExample(
null,
pht('Disable SSH log.'))
->addExample(
'/var/log/phabricator/ssh.log',
pht('Write SSH log here.')),
$this->newOption(
'log.ssh.format',
'wild',
"[%D]\t%p\t%h\t%r\t%s\t%S\t%u\t%C\t%U\t%c\t%T\t%i\t%o")
->setLocked(true)
->setSummary(pht('SSH log format.'))
->setDescription($ssh_desc),
);
}
private function renderMapHelp(array $map) {
$desc = '';
foreach ($map as $key => $kdesc) {
$desc .= " - `%".$key."` ".$kdesc."\n";
}
$desc .= "\n";
$desc .= pht(
"If a variable isn't available (for example, %%m appears in the file ".
"format but the request is not a Conduit request), it will be rendered ".
"as '-'");
$desc .= "\n\n";
$desc .= pht(
"Note that the default format is subject to change in the future, so ".
"if you rely on the log's format, specify it explicitly.");
return $desc;
}
}
diff --git a/src/applications/config/option/PhabricatorApplicationConfigOptions.php b/src/applications/config/option/PhabricatorApplicationConfigOptions.php
index 491852eab6..dab28af776 100644
--- a/src/applications/config/option/PhabricatorApplicationConfigOptions.php
+++ b/src/applications/config/option/PhabricatorApplicationConfigOptions.php
@@ -1,256 +1,256 @@
<?php
abstract class PhabricatorApplicationConfigOptions extends Phobject {
abstract public function getName();
abstract public function getDescription();
abstract public function getGroup();
abstract public function getOptions();
- public function getFontIcon() {
+ public function getIcon() {
return 'fa-sliders';
}
public function validateOption(PhabricatorConfigOption $option, $value) {
if ($value === $option->getDefault()) {
return;
}
if ($value === null) {
return;
}
if ($option->isCustomType()) {
try {
return $option->getCustomObject()->validateOption($option, $value);
} catch (Exception $ex) {
// If custom validators threw exceptions, convert them to configuation
// validation exceptions so we repair the configuration and raise
// an error.
throw new PhabricatorConfigValidationException($ex->getMessage());
}
}
switch ($option->getType()) {
case 'bool':
if ($value !== true &&
$value !== false) {
throw new PhabricatorConfigValidationException(
pht(
"Option '%s' is of type bool, but value is not true or false.",
$option->getKey()));
}
break;
case 'int':
if (!is_int($value)) {
throw new PhabricatorConfigValidationException(
pht(
"Option '%s' is of type int, but value is not an integer.",
$option->getKey()));
}
break;
case 'string':
if (!is_string($value)) {
throw new PhabricatorConfigValidationException(
pht(
"Option '%s' is of type string, but value is not a string.",
$option->getKey()));
}
break;
case 'class':
$symbols = id(new PhutilSymbolLoader())
->setType('class')
->setAncestorClass($option->getBaseClass())
->setConcreteOnly(true)
->selectSymbolsWithoutLoading();
$names = ipull($symbols, 'name', 'name');
if (empty($names[$value])) {
throw new PhabricatorConfigValidationException(
pht(
"Option '%s' value must name a class extending '%s'.",
$option->getKey(),
$option->getBaseClass()));
}
break;
case 'set':
$valid = true;
if (!is_array($value)) {
throw new PhabricatorConfigValidationException(
pht(
"Option '%s' must be a set, but value is not an array.",
$option->getKey()));
}
foreach ($value as $v) {
if ($v !== true) {
throw new PhabricatorConfigValidationException(
pht(
"Option '%s' must be a set, but array contains values other ".
"than 'true'.",
$option->getKey()));
}
}
break;
case 'list<regex>':
$valid = true;
if (!is_array($value)) {
throw new PhabricatorConfigValidationException(
pht(
"Option '%s' must be a list of regular expressions, but value ".
"is not an array.",
$option->getKey()));
}
if ($value && array_keys($value) != range(0, count($value) - 1)) {
throw new PhabricatorConfigValidationException(
pht(
"Option '%s' must be a list of regular expressions, but the ".
"value is a map with unnatural keys.",
$option->getKey()));
}
foreach ($value as $v) {
$ok = @preg_match($v, '');
if ($ok === false) {
throw new PhabricatorConfigValidationException(
pht(
"Option '%s' must be a list of regular expressions, but the ".
"value '%s' is not a valid regular expression.",
$option->getKey(),
$v));
}
}
break;
case 'list<string>':
$valid = true;
if (!is_array($value)) {
throw new PhabricatorConfigValidationException(
pht(
"Option '%s' must be a list of strings, but value is not ".
"an array.",
$option->getKey()));
}
if ($value && array_keys($value) != range(0, count($value) - 1)) {
throw new PhabricatorConfigValidationException(
pht(
"Option '%s' must be a list of strings, but the value is a ".
"map with unnatural keys.",
$option->getKey()));
}
foreach ($value as $v) {
if (!is_string($v)) {
throw new PhabricatorConfigValidationException(
pht(
"Option '%s' must be a list of strings, but it contains one ".
"or more non-strings.",
$option->getKey()));
}
}
break;
case 'wild':
default:
break;
}
$this->didValidateOption($option, $value);
}
protected function didValidateOption(
PhabricatorConfigOption $option,
$value) {
// Hook for subclasses to do complex validation.
return;
}
/**
* Hook to render additional hints based on, e.g., the viewing user, request,
* or other context. For example, this is used to show workspace IDs when
* configuring `asana.workspace-id`.
*
* @param PhabricatorConfigOption Option being rendered.
* @param AphrontRequest Active request.
* @return wild Additional contextual description
* information.
*/
public function renderContextualDescription(
PhabricatorConfigOption $option,
AphrontRequest $request) {
return null;
}
public function getKey() {
$class = get_class($this);
$matches = null;
if (preg_match('/^Phabricator(.*)ConfigOptions$/', $class, $matches)) {
return strtolower($matches[1]);
}
return strtolower(get_class($this));
}
final protected function newOption($key, $type, $default) {
return id(new PhabricatorConfigOption())
->setKey($key)
->setType($type)
->setDefault($default)
->setGroup($this);
}
final public static function loadAll($external_only = false) {
$symbols = id(new PhutilSymbolLoader())
->setAncestorClass(__CLASS__)
->setConcreteOnly(true)
->selectAndLoadSymbols();
$groups = array();
foreach ($symbols as $symbol) {
if ($external_only && $symbol['library'] == 'phabricator') {
continue;
}
$obj = newv($symbol['name'], array());
$key = $obj->getKey();
if (isset($groups[$key])) {
$pclass = get_class($groups[$key]);
$nclass = $symbol['name'];
throw new Exception(
pht(
"Multiple %s subclasses have the same key ('%s'): %s, %s.",
__CLASS__,
$key,
$pclass,
$nclass));
}
$groups[$key] = $obj;
}
return $groups;
}
final public static function loadAllOptions($external_only = false) {
$groups = self::loadAll($external_only);
$options = array();
foreach ($groups as $group) {
foreach ($group->getOptions() as $option) {
$key = $option->getKey();
if (isset($options[$key])) {
throw new Exception(
pht(
"Mulitple %s subclasses contain an option named '%s'!",
__CLASS__,
$key));
}
$options[$key] = $option;
}
}
return $options;
}
/**
* Deformat a HEREDOC for use in remarkup by converting line breaks to
* spaces.
*/
final protected function deformat($string) {
return preg_replace('/(?<=\S)\n(?=\S)/', ' ', $string);
}
}
diff --git a/src/applications/config/option/PhabricatorAuthenticationConfigOptions.php b/src/applications/config/option/PhabricatorAuthenticationConfigOptions.php
index 8092f52ff8..bd1c8965eb 100644
--- a/src/applications/config/option/PhabricatorAuthenticationConfigOptions.php
+++ b/src/applications/config/option/PhabricatorAuthenticationConfigOptions.php
@@ -1,101 +1,101 @@
<?php
final class PhabricatorAuthenticationConfigOptions
extends PhabricatorApplicationConfigOptions {
public function getName() {
return pht('Authentication');
}
public function getDescription() {
return pht('Options relating to authentication.');
}
- public function getFontIcon() {
+ public function getIcon() {
return 'fa-key';
}
public function getGroup() {
return 'core';
}
public function getOptions() {
return array(
$this->newOption('auth.require-email-verification', 'bool', false)
->setBoolOptions(
array(
pht('Require email verification'),
pht("Don't require email verification"),
))
->setSummary(
pht('Require email verification before a user can log in.'))
->setDescription(
pht(
'If true, email addresses must be verified (by clicking a link '.
'in an email) before a user can login. By default, verification '.
'is optional unless {{auth.email-domains}} is nonempty.')),
$this->newOption('auth.require-approval', 'bool', true)
->setBoolOptions(
array(
pht('Require Administrators to Approve Accounts'),
pht("Don't Require Manual Approval"),
))
->setSummary(
pht('Require administrators to approve new accounts.'))
->setDescription(
pht(
"Newly registered Phabricator accounts can either be placed ".
"into a manual approval queue for administrative review, or ".
"automatically activated immediately. The approval queue is ".
"enabled by default because it gives you greater control over ".
"who can register an account and access Phabricator.\n\n".
"If your install is completely public, or on a VPN, or users can ".
"only register with a trusted provider like LDAP, or you've ".
"otherwise configured Phabricator to prevent unauthorized ".
"registration, you can disable the queue to reduce administrative ".
"overhead.\n\n".
"NOTE: Before you disable the queue, make sure ".
"{{auth.email-domains}} is configured correctly ".
"for your install!")),
$this->newOption('auth.email-domains', 'list<string>', array())
->setSummary(pht('Only allow registration from particular domains.'))
->setDescription(
pht(
"You can restrict allowed email addresses to certain domains ".
"(like `yourcompany.com`) by setting a list of allowed domains ".
"here.\n\nUsers will only be allowed to register using email ".
"addresses at one of the domains, and will only be able to add ".
"new email addresses for these domains. If you configure this, ".
"it implies {{auth.require-email-verification}}.\n\n".
"You should omit the `@` from domains. Note that the domain must ".
"match exactly. If you allow `yourcompany.com`, that permits ".
"`joe@yourcompany.com` but rejects `joe@mail.yourcompany.com`."))
->addExample(
"yourcompany.com\nmail.yourcompany.com",
pht('Valid Setting')),
$this->newOption('account.editable', 'bool', true)
->setBoolOptions(
array(
pht('Allow editing'),
pht('Prevent editing'),
))
->setSummary(
pht(
'Determines whether or not basic account information is editable.'))
->setDescription(
pht(
'Is basic account information (email, real name, profile '.
'picture) editable? If you set up Phabricator to automatically '.
'synchronize account information from some other authoritative '.
'system, you can disable this to ensure information remains '.
'consistent across both systems.')),
$this->newOption('account.minimum-password-length', 'int', 8)
->setSummary(pht('Minimum password length.'))
->setDescription(
pht(
'When users set or reset a password, it must have at least this '.
'many characters.')),
);
}
}
diff --git a/src/applications/config/option/PhabricatorClusterConfigOptions.php b/src/applications/config/option/PhabricatorClusterConfigOptions.php
index 8684d98233..0b7974904c 100644
--- a/src/applications/config/option/PhabricatorClusterConfigOptions.php
+++ b/src/applications/config/option/PhabricatorClusterConfigOptions.php
@@ -1,79 +1,79 @@
<?php
final class PhabricatorClusterConfigOptions
extends PhabricatorApplicationConfigOptions {
public function getName() {
return pht('Cluster Setup');
}
public function getDescription() {
return pht('Configure Phabricator to run on a cluster of hosts.');
}
- public function getFontIcon() {
+ public function getIcon() {
return 'fa-sitemap';
}
public function getGroup() {
return 'core';
}
public function getOptions() {
return array(
$this->newOption('cluster.addresses', 'list<string>', array())
->setLocked(true)
->setSummary(pht('Address ranges of cluster hosts.'))
->setDescription(
pht(
'To allow Phabricator nodes to communicate with other nodes '.
'in the cluster, provide an address whitelist of hosts that '.
'are part of the cluster.'.
"\n\n".
'Hosts on this whitelist are permitted to use special cluster '.
'mechanisms to authenticate requests. By default, these '.
'mechanisms are disabled.'.
"\n\n".
'Define a list of CIDR blocks which whitelist all hosts in the '.
'cluster. See the examples below for details.',
"\n\n".
'When cluster addresses are defined, Phabricator hosts will also '.
'reject requests to interfaces which are not whitelisted.'))
->addExample(
array(
'23.24.25.80/32',
'23.24.25.81/32',
),
pht('Whitelist Specific Addresses'))
->addExample(
array(
'1.2.3.0/24',
),
pht('Whitelist 1.2.3.*'))
->addExample(
array(
'1.2.0.0/16',
),
pht('Whitelist 1.2.*.*'))
->addExample(
array(
'0.0.0.0/0',
),
pht('Allow Any Host (Insecure!)')),
$this->newOption('cluster.instance', 'string', null)
->setLocked(true)
->setSummary(pht('Instance identifier for multi-tenant clusters.'))
->setDescription(
pht(
'WARNING: This is a very advanced option, and only useful for '.
'hosting providers running multi-tenant clusters.'.
"\n\n".
'If you provide an instance identifier here (normally by '.
'injecting it with a `%s`), Phabricator will pass it to '.
'subprocesses and commit hooks in the `%s` environmental variable.',
'PhabricatorConfigSiteSource',
'PHABRICATOR_INSTANCE')),
);
}
}
diff --git a/src/applications/config/option/PhabricatorCoreConfigOptions.php b/src/applications/config/option/PhabricatorCoreConfigOptions.php
index 7f696ae48c..c486ce0db1 100644
--- a/src/applications/config/option/PhabricatorCoreConfigOptions.php
+++ b/src/applications/config/option/PhabricatorCoreConfigOptions.php
@@ -1,324 +1,324 @@
<?php
final class PhabricatorCoreConfigOptions
extends PhabricatorApplicationConfigOptions {
public function getName() {
return pht('Core');
}
public function getDescription() {
return pht('Configure core options, including URIs.');
}
- public function getFontIcon() {
+ public function getIcon() {
return 'fa-bullseye';
}
public function getGroup() {
return 'core';
}
public function getOptions() {
if (phutil_is_windows()) {
$paths = array();
} else {
$paths = array(
'/bin',
'/usr/bin',
'/usr/local/bin',
);
}
$path = getenv('PATH');
$proto_doc_href = PhabricatorEnv::getDoclink(
'User Guide: Prototype Applications');
$proto_doc_name = pht('User Guide: Prototype Applications');
$applications_app_href = '/applications/';
return array(
$this->newOption('phabricator.base-uri', 'string', null)
->setLocked(true)
->setSummary(pht('URI where Phabricator is installed.'))
->setDescription(
pht(
'Set the URI where Phabricator is installed. Setting this '.
'improves security by preventing cookies from being set on other '.
'domains, and allows daemons to send emails with links that have '.
'the correct domain.'))
->addExample('http://phabricator.example.com/', pht('Valid Setting')),
$this->newOption('phabricator.production-uri', 'string', null)
->setSummary(
pht('Primary install URI, for multi-environment installs.'))
->setDescription(
pht(
'If you have multiple Phabricator environments (like a '.
'development/staging environment for working on testing '.
'Phabricator, and a production environment for deploying it), '.
'set the production environment URI here so that emails and other '.
'durable URIs will always generate with links pointing at the '.
'production environment. If unset, defaults to `%s`. Most '.
'installs do not need to set this option.',
'phabricator.base-uri'))
->addExample('http://phabricator.example.com/', pht('Valid Setting')),
$this->newOption('phabricator.allowed-uris', 'list<string>', array())
->setLocked(true)
->setSummary(pht('Alternative URIs that can access Phabricator.'))
->setDescription(
pht(
"These alternative URIs will be able to access 'normal' pages ".
"on your Phabricator install. Other features such as OAuth ".
"won't work. The major use case for this is moving installs ".
"across domains."))
->addExample(
"http://phabricator2.example.com/\n".
"http://phabricator3.example.com/",
pht('Valid Setting')),
$this->newOption('phabricator.timezone', 'string', null)
->setSummary(
pht('The timezone Phabricator should use.'))
->setDescription(
pht(
"PHP requires that you set a timezone in your php.ini before ".
"using date functions, or it will emit a warning. If this isn't ".
"possible (for instance, because you are using HPHP) you can set ".
"some valid constant for %s here and Phabricator will set it on ".
"your behalf, silencing the warning.",
'date_default_timezone_set()'))
->addExample('America/New_York', pht('US East (EDT)'))
->addExample('America/Chicago', pht('US Central (CDT)'))
->addExample('America/Boise', pht('US Mountain (MDT)'))
->addExample('America/Los_Angeles', pht('US West (PDT)')),
$this->newOption('phabricator.cookie-prefix', 'string', null)
->setLocked(true)
->setSummary(
pht(
'Set a string Phabricator should use to prefix cookie names.'))
->setDescription(
pht(
'Cookies set for x.com are also sent for y.x.com. Assuming '.
'Phabricator instances are running on both domains, this will '.
'create a collision preventing you from logging in.'))
->addExample('dev', pht('Prefix cookie with "%s"', 'dev')),
$this->newOption('phabricator.show-prototypes', 'bool', false)
->setLocked(true)
->setBoolOptions(
array(
pht('Enable Prototypes'),
pht('Disable Prototypes'),
))
->setSummary(
pht(
'Install applications which are still under development.'))
->setDescription(
pht(
"IMPORTANT: The upstream does not provide support for prototype ".
"applications.".
"\n\n".
"Phabricator includes prototype applications which are in an ".
"**early stage of development**. By default, prototype ".
"applications are not installed, because they are often not yet ".
"developed enough to be generally usable. You can enable ".
"this option to install them if you're developing Phabricator ".
"or are interested in previewing upcoming features.".
"\n\n".
"To learn more about prototypes, see [[ %s | %s ]].".
"\n\n".
"After enabling prototypes, you can selectively uninstall them ".
"(like normal applications).",
$proto_doc_href,
$proto_doc_name)),
$this->newOption('phabricator.serious-business', 'bool', false)
->setBoolOptions(
array(
pht('Serious business'),
pht('Shenanigans'), // That should be interesting to translate. :P
))
->setSummary(
pht('Allows you to remove levity and jokes from the UI.'))
->setDescription(
pht(
'By default, Phabricator includes some flavor text in the UI, '.
'like a prompt to "Weigh In" rather than "Add Comment" in '.
'Maniphest. If you\'d prefer more traditional UI strings like '.
'"Add Comment", you can set this flag to disable most of the '.
'extra flavor.')),
$this->newOption('remarkup.ignored-object-names', 'string', '/^(Q|V)\d$/')
->setSummary(
pht('Text values that match this regex and are also object names '.
'will not be linked.'))
->setDescription(
pht(
'By default, Phabricator links object names in Remarkup fields '.
'to the corresponding object. This regex can be used to modify '.
'this behavior; object names that match this regex will not be '.
'linked.')),
$this->newOption('environment.append-paths', 'list<string>', $paths)
->setSummary(
pht(
'These paths get appended to your %s environment variable.',
'$PATH'))
->setDescription(
pht(
"Phabricator occasionally shells out to other binaries on the ".
"server. An example of this is the `%s` command, used to ".
"syntax-highlight code written in languages other than PHP. By ".
"default, it is assumed that these binaries are in the %s of the ".
"user running Phabricator (normally 'apache', 'httpd', or ".
"'nobody'). Here you can add extra directories to the %s ".
"environment variable, for when these binaries are in ".
"non-standard locations.\n\n".
"Note that you can also put binaries in `%s` (for example, by ".
"symlinking them).\n\n".
"The current value of PATH after configuration is applied is:\n\n".
" lang=text\n".
" %s",
'pygmentize',
'$PATH',
'$PATH',
'phabricator/support/bin/',
$path))
->setLocked(true)
->addExample('/usr/local/bin', pht('Add One Path'))
->addExample("/usr/bin\n/usr/local/bin", pht('Add Multiple Paths')),
$this->newOption('config.lock', 'set', array())
->setLocked(true)
->setDescription(pht('Additional configuration options to lock.')),
$this->newOption('config.hide', 'set', array())
->setLocked(true)
->setDescription(pht('Additional configuration options to hide.')),
$this->newOption('config.ignore-issues', 'set', array())
->setLocked(true)
->setDescription(pht('Setup issues to ignore.')),
$this->newOption('phabricator.env', 'string', null)
->setLocked(true)
->setDescription(pht('Internal.')),
$this->newOption('test.value', 'wild', null)
->setLocked(true)
->setDescription(pht('Unit test value.')),
$this->newOption('phabricator.uninstalled-applications', 'set', array())
->setLocked(true)
->setLockedMessage(pht(
'Use the %s to manage installed applications.',
phutil_tag(
'a',
array(
'href' => $applications_app_href,
),
pht('Applications application'))))
->setDescription(
pht('Array containing list of uninstalled applications.')),
$this->newOption('phabricator.application-settings', 'wild', array())
->setLocked(true)
->setDescription(
pht('Customized settings for Phabricator applications.')),
$this->newOption('welcome.html', 'string', null)
->setLocked(true)
->setDescription(
pht('Custom HTML to show on the main Phabricator dashboard.')),
$this->newOption('phabricator.cache-namespace', 'string', 'phabricator')
->setLocked(true)
->setDescription(pht('Cache namespace.')),
$this->newOption('phabricator.allow-email-users', 'bool', false)
->setBoolOptions(
array(
pht('Allow'),
pht('Disallow'),
))
->setDescription(
pht('Allow non-members to interact with tasks over email.')),
$this->newOption('phabricator.silent', 'bool', false)
->setLocked(true)
->setBoolOptions(
array(
pht('Run Silently'),
pht('Run Normally'),
))
->setSummary(pht('Stop Phabricator from sending any email, etc.'))
->setDescription(
pht(
'This option allows you to stop Phabricator from sending '.
'any data to external services. Among other things, it will '.
'disable email, SMS, repository mirroring, and HTTP hooks.'.
"\n\n".
'This option is intended to allow a Phabricator instance to '.
'be exported, copied, imported, and run in a test environment '.
'without impacting users. For example, if you are migrating '.
'to new hardware, you could perform a test migration first, '.
'make sure things work, and then do a production cutover '.
'later with higher confidence and less disruption. Without '.
'this flag, users would receive duplicate email during the '.
'time the test instance and old production instance were '.
'both in operation.')),
);
}
protected function didValidateOption(
PhabricatorConfigOption $option,
$value) {
$key = $option->getKey();
if ($key == 'phabricator.base-uri' ||
$key == 'phabricator.production-uri') {
$uri = new PhutilURI($value);
$protocol = $uri->getProtocol();
if ($protocol !== 'http' && $protocol !== 'https') {
throw new PhabricatorConfigValidationException(
pht(
"Config option '%s' is invalid. The URI must start with ".
"%s' or '%s'.",
'http://',
'https://',
$key));
}
$domain = $uri->getDomain();
if (strpos($domain, '.') === false) {
throw new PhabricatorConfigValidationException(
pht(
"Config option '%s' is invalid. The URI must contain a dot ".
"('%s'), like '%s', not just a bare name like '%s'. Some web ".
"browsers will not set cookies on domains with no TLD.",
'.',
'http://example.com/',
'http://example/',
$key));
}
$path = $uri->getPath();
if ($path !== '' && $path !== '/') {
throw new PhabricatorConfigValidationException(
pht(
"Config option '%s' is invalid. The URI must NOT have a path, ".
"e.g. '%s' is OK, but '%s' is not. Phabricator must be installed ".
"on an entire domain; it can not be installed on a path.",
$key,
'http://phabricator.example.com/',
'http://example.com/phabricator/'));
}
}
if ($key === 'phabricator.timezone') {
$old = date_default_timezone_get();
$ok = @date_default_timezone_set($value);
@date_default_timezone_set($old);
if (!$ok) {
throw new PhabricatorConfigValidationException(
pht(
"Config option '%s' is invalid. The timezone identifier must ".
"be a valid timezone identifier recognized by PHP, like '%s'. "."
You can find a list of valid identifiers here: %s",
$key,
'America/Los_Angeles',
'http://php.net/manual/timezones.php'));
}
}
}
}
diff --git a/src/applications/config/option/PhabricatorDeveloperConfigOptions.php b/src/applications/config/option/PhabricatorDeveloperConfigOptions.php
index 37cf752f68..a84a7484a6 100644
--- a/src/applications/config/option/PhabricatorDeveloperConfigOptions.php
+++ b/src/applications/config/option/PhabricatorDeveloperConfigOptions.php
@@ -1,183 +1,183 @@
<?php
final class PhabricatorDeveloperConfigOptions
extends PhabricatorApplicationConfigOptions {
public function getName() {
return pht('Developer / Debugging');
}
public function getDescription() {
return pht('Options for Phabricator developers, including debugging.');
}
- public function getFontIcon() {
+ public function getIcon() {
return 'fa-bug';
}
public function getGroup() {
return 'core';
}
public function getOptions() {
return array(
$this->newOption('darkconsole.enabled', 'bool', false)
->setBoolOptions(
array(
pht('Enable DarkConsole'),
pht('Disable DarkConsole'),
))
->setSummary(pht("Enable Phabricator's debugging console."))
->setDescription(
pht(
"DarkConsole is a development and profiling tool built into ".
"Phabricator's web interface. You should leave it disabled unless ".
"you are developing or debugging Phabricator.\n\n".
"Once you activate DarkConsole for the install, **you need to ".
"enable it for your account before it will actually appear on ".
"pages.** You can do this in Settings > Developer Settings.\n\n".
"DarkConsole exposes potentially sensitive data (like queries, ".
"stack traces, and configuration) so you generally should not ".
"turn it on in production.")),
$this->newOption('darkconsole.always-on', 'bool', false)
->setBoolOptions(
array(
pht('Always Activate DarkConsole'),
pht('Require DarkConsole Activation'),
))
->setSummary(pht('Activate DarkConsole on every page.'))
->setDescription(
pht(
"This option allows you to enable DarkConsole on every page, ".
"even for logged-out users. This is only really useful if you ".
"need to debug something on a logged-out page. You should not ".
"enable this option in production.\n\n".
"You must enable DarkConsole by setting '%s' ".
"before this option will have any effect.",
'darkconsole.enabled')),
$this->newOption('debug.time-limit', 'int', null)
->setSummary(
pht(
'Limit page execution time to debug hangs.'))
->setDescription(
pht(
"This option can help debug pages which are taking a very ".
"long time (more than 30 seconds) to render.\n\n".
"If a page is slow to render (but taking less than 30 seconds), ".
"the best tools to use to figure out why it is slow are usually ".
"the DarkConsole service call profiler and XHProf.\n\n".
"However, if a request takes a very long time to return, some ".
"components (like Apache, nginx, or PHP itself) may abort the ".
"request before it finishes. This can prevent you from using ".
"profiling tools to understand page performance in detail.\n\n".
"In these cases, you can use this option to force the page to ".
"abort after a smaller number of seconds (for example, 10), and ".
"dump a useful stack trace. This can provide useful information ".
"about why a page is hanging.\n\n".
"To use this option, set it to a small number (like 10), and ".
"reload a hanging page. The page should exit after 10 seconds ".
"and give you a stack trace.\n\n".
"You should turn this option off (set it to 0) when you are ".
"done with it. Leaving it on creates a small amount of overhead ".
"for all requests, even if they do not hit the time limit.")),
$this->newOption('debug.stop-on-redirect', 'bool', false)
->setBoolOptions(
array(
pht('Stop Before HTTP Redirect'),
pht('Use Normal HTTP Redirects'),
))
->setSummary(
pht(
'Confirm before redirecting so DarkConsole can be examined.'))
->setDescription(
pht(
'Normally, Phabricator issues HTTP redirects after a successful '.
'POST. This can make it difficult to debug things which happen '.
'while processing the POST, because service and profiling '.
'information are lost. By setting this configuration option, '.
'Phabricator will show a page instead of automatically '.
'redirecting, allowing you to examine service and profiling '.
'information. It also makes the UX awful, so you should only '.
'enable it when debugging.')),
$this->newOption('debug.profile-rate', 'int', 0)
->addExample(0, pht('No profiling'))
->addExample(1, pht('Profile every request (slow)'))
->addExample(1000, pht('Profile 0.1%% of all requests'))
->setSummary(pht('Automatically profile some percentage of pages.'))
->setDescription(
pht(
"Normally, Phabricator profiles pages only when explicitly ".
"requested via DarkConsole. However, it may be useful to profile ".
"some pages automatically.\n\n".
"Set this option to a positive integer N to profile 1 / N pages ".
"automatically. For example, setting it to 1 will profile every ".
"page, while setting it to 1000 will profile 1 page per 1000 ".
"requests (i.e., 0.1%% of requests).\n\n".
"Since profiling is slow and generates a lot of data, you should ".
"set this to 0 in production (to disable it) or to a large number ".
"(to collect a few samples, if you're interested in having some ".
"data to look at eventually). In development, it may be useful to ".
"set it to 1 in order to debug performance problems.\n\n".
"NOTE: You must install XHProf for profiling to work.")),
$this->newOption('debug.sample-rate', 'int', 1000)
->setLocked(true)
->addExample(0, pht('No performance sampling.'))
->addExample(1, pht('Sample every request (slow).'))
->addExample(1000, pht('Sample 0.1%% of requests.'))
->setSummary(pht('Automatically sample some fraction of requests.'))
->setDescription(
pht(
"The Multimeter application collects performance samples. You ".
"can use this data to help you understand what Phabricator is ".
"spending time and resources doing, and to identify problematic ".
"access patterns.".
"\n\n".
"This option controls how frequently sampling activates. Set it ".
"to some positive integer N to sample every 1 / N pages.".
"\n\n".
"For most installs, the default value (1 sample per 1000 pages) ".
"should collect enough data to be useful without requiring much ".
"storage or meaningfully impacting performance. If you're ".
"investigating performance issues, you can adjust the rate ".
"in order to collect more data.")),
$this->newOption('phabricator.developer-mode', 'bool', false)
->setBoolOptions(
array(
pht('Enable developer mode'),
pht('Disable developer mode'),
))
->setSummary(pht('Enable verbose error reporting and disk reads.'))
->setDescription(
pht(
'This option enables verbose error reporting (stack traces, '.
'error callouts) and forces disk reads of static assets on '.
'every reload.')),
$this->newOption('celerity.minify', 'bool', true)
->setBoolOptions(
array(
pht('Minify static resources.'),
pht("Don't minify static resources."),
))
->setSummary(pht('Minify static Celerity resources.'))
->setDescription(
pht(
'Minify static resources by removing whitespace and comments. You '.
'should enable this in production, but disable it in '.
'development.')),
$this->newOption('cache.enable-deflate', 'bool', true)
->setBoolOptions(
array(
pht('Enable deflate compression'),
pht('Disable deflate compression'),
))
->setSummary(
pht('Toggle %s-based compression for some caches.', 'gzdeflate()'))
->setDescription(
pht(
'Set this to false to disable the use of %s-based '.
'compression in some caches. This may give you less performant '.
'(but more debuggable) caching.',
'gzdeflate()')),
);
}
}
diff --git a/src/applications/config/option/PhabricatorExtendingPhabricatorConfigOptions.php b/src/applications/config/option/PhabricatorExtendingPhabricatorConfigOptions.php
index ef07bc9109..28a0f619dd 100644
--- a/src/applications/config/option/PhabricatorExtendingPhabricatorConfigOptions.php
+++ b/src/applications/config/option/PhabricatorExtendingPhabricatorConfigOptions.php
@@ -1,50 +1,50 @@
<?php
final class PhabricatorExtendingPhabricatorConfigOptions
extends PhabricatorApplicationConfigOptions {
public function getName() {
return pht('Extending Phabricator');
}
public function getDescription() {
return pht('Make Phabricator even cooler!');
}
- public function getFontIcon() {
+ public function getIcon() {
return 'fa-rocket';
}
public function getGroup() {
return 'core';
}
public function getOptions() {
return array(
$this->newOption('load-libraries', 'list<string>', array())
->setLocked(true)
->setSummary(pht('Paths to additional phutil libraries to load.'))
->addExample('/srv/our-libs/sekrit-phutil', pht('Valid Setting')),
$this->newOption('events.listeners', 'list<string>', array())
->setLocked(true)
->setSummary(
pht('Listeners receive callbacks when interesting things occur.'))
->setDescription(
pht(
'You can respond to various application events by installing '.
'listeners, which will receive callbacks when interesting things '.
'occur. Specify a list of classes which extend '.
'PhabricatorEventListener here.'))
->addExample('MyEventListener', pht('Valid Setting')),
$this->newOption(
'aphront.default-application-configuration-class',
'class',
'AphrontDefaultApplicationConfiguration')
->setLocked(true)
->setBaseClass('AphrontApplicationConfiguration')
// TODO: This could probably use some better documentation.
->setDescription(pht('Application configuration class.')),
);
}
}
diff --git a/src/applications/config/option/PhabricatorMailgunConfigOptions.php b/src/applications/config/option/PhabricatorMailgunConfigOptions.php
index aebcba6725..cc4e71fb59 100644
--- a/src/applications/config/option/PhabricatorMailgunConfigOptions.php
+++ b/src/applications/config/option/PhabricatorMailgunConfigOptions.php
@@ -1,38 +1,38 @@
<?php
final class PhabricatorMailgunConfigOptions
extends PhabricatorApplicationConfigOptions {
public function getName() {
return pht('Integration with Mailgun');
}
public function getDescription() {
return pht('Configure Mailgun integration.');
}
- public function getFontIcon() {
+ public function getIcon() {
return 'fa-send-o';
}
public function getGroup() {
return 'core';
}
public function getOptions() {
return array(
$this->newOption('mailgun.domain', 'string', null)
->setLocked(true)
->setDescription(
pht(
'Mailgun domain name. See %s.',
'https://mailgun.com/cp/domains'))
->addExample('mycompany.com', pht('Use specific domain')),
$this->newOption('mailgun.api-key', 'string', null)
->setHidden(true)
->setDescription(pht('Mailgun API key.')),
);
}
}
diff --git a/src/applications/config/option/PhabricatorMetaMTAConfigOptions.php b/src/applications/config/option/PhabricatorMetaMTAConfigOptions.php
index 929f02be2d..16bdb7e520 100644
--- a/src/applications/config/option/PhabricatorMetaMTAConfigOptions.php
+++ b/src/applications/config/option/PhabricatorMetaMTAConfigOptions.php
@@ -1,349 +1,349 @@
<?php
final class PhabricatorMetaMTAConfigOptions
extends PhabricatorApplicationConfigOptions {
public function getName() {
return pht('Mail');
}
public function getDescription() {
return pht('Configure Mail.');
}
- public function getFontIcon() {
+ public function getIcon() {
return 'fa-send';
}
public function getGroup() {
return 'core';
}
public function getOptions() {
$send_as_user_desc = $this->deformat(pht(<<<EODOC
When a user takes an action which generates an email notification (like
commenting on a Differential revision), Phabricator can either send that mail
"From" the user's email address (like "alincoln@logcabin.com") or "From" the
'%s' address.
The user experience is generally better if Phabricator uses the user's real
address as the "From" since the messages are easier to organize when they appear
in mail clients, but this will only work if the server is authorized to send
email on behalf of the "From" domain. Practically, this means:
- If you are doing an install for Example Corp and all the users will have
corporate @corp.example.com addresses and any hosts Phabricator is running
on are authorized to send email from corp.example.com, you can enable this
to make the user experience a little better.
- If you are doing an install for an open source project and your users will
be registering via Facebook and using personal email addresses, you probably
should not enable this or all of your outgoing email might vanish into SFP
blackholes.
- If your install is anything else, you're safer leaving this off, at least
initially, since the risk in turning it on is that your outgoing mail will
never arrive.
EODOC
,
'metamta.default-address'));
$one_mail_per_recipient_desc = $this->deformat(pht(<<<EODOC
When a message is sent to multiple recipients (for example, several reviewers on
a code review), Phabricator can either deliver one email to everyone (e.g., "To:
alincoln, usgrant, htaft") or separate emails to each user (e.g., "To:
alincoln", "To: usgrant", "To: htaft"). The major advantages and disadvantages
of each approach are:
- One mail to everyone:
- This violates policy controls. The body of the mail is generated without
respect for object policies.
- Recipients can see To/Cc at a glance.
- If you use mailing lists, you won't get duplicate mail if you're
a normal recipient and also Cc'd on a mailing list.
- Getting threading to work properly is harder, and probably requires
making mail less useful by turning off options.
- Sometimes people will "Reply All" and everyone will get two mails,
one from the user and one from Phabricator turning their mail into
a comment.
- Not supported with a private reply-to address.
- Mails are sent in the server default translation.
- One mail to each user:
- Policy controls work correctly and are enforced per-user.
- Recipients need to look in the mail body to see To/Cc.
- If you use mailing lists, recipients may sometimes get duplicate
mail.
- Getting threading to work properly is easier, and threading settings
can be customzied by each user.
- "Reply All" no longer spams all other users.
- Required if private reply-to addresses are configured.
- Mails are sent in the language of user preference.
EODOC
));
$herald_hints_description = $this->deformat(pht(<<<EODOC
You can disable the Herald hints in email if users prefer smaller messages.
These are the links under the header "WHY DID I GET THIS EMAIL?". If you set
this to `false`, they will not appear in any mail. Users can still navigate to
the links via the web interface.
EODOC
));
$reply_hints_description = $this->deformat(pht(<<<EODOC
You can disable the hints under "REPLY HANDLER ACTIONS" if users prefer
smaller messages. The actions themselves will still work properly.
EODOC
));
$recipient_hints_description = $this->deformat(pht(<<<EODOC
You can disable the "To:" and "Cc:" footers in mail if users prefer smaller
messages.
EODOC
));
$bulk_description = $this->deformat(pht(<<<EODOC
If this option is enabled, Phabricator will add a "Precedence: bulk" header to
transactional mail (e.g., Differential, Maniphest and Herald notifications).
This may improve the behavior of some auto-responder software and prevent it
from replying. However, it may also cause deliverability issues -- notably, you
currently can not send this header via Amazon SES, and enabling this option with
SES will prevent delivery of any affected mail.
EODOC
));
$email_preferences_description = $this->deformat(pht(<<<EODOC
You can disable the email preference link in emails if users prefer smaller
emails.
EODOC
));
$re_prefix_description = $this->deformat(pht(<<<EODOC
Mail.app on OS X Lion won't respect threading headers unless the subject is
prefixed with "Re:". If you enable this option, Phabricator will add "Re:" to
the subject line of all mail which is expected to thread. If you've set
'metamta.one-mail-per-recipient', users can override this setting in their
preferences.
EODOC
));
$vary_subjects_description = $this->deformat(pht(<<<EODOC
If true, allow MetaMTA to change mail subjects to put text like '[Accepted]' and
'[Commented]' in them. This makes subjects more useful, but might break
threading on some clients. If you've set '%s', users can override this setting
in their preferences.
EODOC
,
'metamta.one-mail-per-recipient'));
$reply_to_description = $this->deformat(pht(<<<EODOC
If you enable `%s`, Phabricator uses "From" to authenticate users. You can
additionally enable this setting to try to authenticate with 'Reply-To'. Note
that this is completely spoofable and insecure (any user can set any 'Reply-To'
address) but depending on the nature of your install or other deliverability
conditions this might be okay. Generally, you can't do much more by spoofing
Reply-To than be annoying (you can write but not read content). But this is
still **COMPLETELY INSECURE**.
EODOC
,
'metamta.public-replies'));
$adapter_description = $this->deformat(pht(<<<EODOC
Adapter class to use to transmit mail to the MTA. The default uses
PHPMailerLite, which will invoke "sendmail". This is appropriate if sendmail
actually works on your host, but if you haven't configured mail it may not be so
great. A number of other mailers are available (e.g., SES, SendGrid, SMTP,
custom mailers), consult "Configuring Outbound Email" in the documentation for
details.
EODOC
));
$placeholder_description = $this->deformat(pht(<<<EODOC
When sending a message that has no To recipient (i.e. all recipients are CC'd,
for example when multiplexing mail), set the To field to the following value. If
no value is set, messages with no To will have their CCs upgraded to To.
EODOC
));
$public_replies_description = $this->deformat(pht(<<<EODOC
By default, Phabricator generates unique reply-to addresses and sends a separate
email to each recipient when you enable reply handling. This is more secure than
using "From" to establish user identity, but can mean users may receive multiple
emails when they are on mailing lists. Instead, you can use a single, non-unique
reply to address and authenticate users based on the "From" address by setting
this to 'true'. This trades away a little bit of security for convenience, but
it's reasonable in many installs. Object interactions are still protected using
hashes in the single public email address, so objects can not be replied to
blindly.
EODOC
));
$single_description = $this->deformat(pht(<<<EODOC
If you want to use a single mailbox for Phabricator reply mail, you can use this
and set a common prefix for reply addresses generated by Phabricator. It will
make use of the fact that a mail-address such as
`phabricator+D123+1hjk213h@example.com` will be delivered to the `phabricator`
user's mailbox. Set this to the left part of the email address and it will be
prepended to all generated reply addresses.
For example, if you want to use `phabricator@example.com`, this should be set
to `phabricator`.
EODOC
));
$address_description = $this->deformat(pht(<<<EODOC
When email is sent, what format should Phabricator use for user's email
addresses? Valid values are:
- `short`: 'gwashington <gwashington@example.com>'
- `real`: 'George Washington <gwashington@example.com>'
- `full`: 'gwashington (George Washington) <gwashington@example.com>'
The default is `full`.
EODOC
));
return array(
$this->newOption(
'metamta.default-address',
'string',
'noreply@phabricator.example.com')
->setDescription(pht('Default "From" address.')),
$this->newOption(
'metamta.domain',
'string',
'phabricator.example.com')
->setDescription(pht('Domain used to generate Message-IDs.')),
$this->newOption(
'metamta.mail-adapter',
'class',
'PhabricatorMailImplementationPHPMailerLiteAdapter')
->setBaseClass('PhabricatorMailImplementationAdapter')
->setSummary(pht('Control how mail is sent.'))
->setDescription($adapter_description),
$this->newOption(
'metamta.one-mail-per-recipient',
'bool',
true)
->setLocked(true)
->setBoolOptions(
array(
pht('Send Mail To Each Recipient'),
pht('Send Mail To All Recipients'),
))
->setSummary(
pht(
'Controls whether Phabricator sends one email with multiple '.
'recipients in the "To:" line, or multiple emails, each with a '.
'single recipient in the "To:" line.'))
->setDescription($one_mail_per_recipient_desc),
$this->newOption('metamta.can-send-as-user', 'bool', false)
->setBoolOptions(
array(
pht('Send as User Taking Action'),
pht('Send as Phabricator'),
))
->setSummary(
pht(
'Controls whether Phabricator sends email "From" users.'))
->setDescription($send_as_user_desc),
$this->newOption(
'metamta.reply-handler-domain',
'string',
null)
->setLocked(true)
->setDescription(pht('Domain used for reply email addresses.'))
->addExample('phabricator.example.com', ''),
$this->newOption('metamta.herald.show-hints', 'bool', true)
->setBoolOptions(
array(
pht('Show Herald Hints'),
pht('No Herald Hints'),
))
->setSummary(pht('Show hints about Herald rules in email.'))
->setDescription($herald_hints_description),
$this->newOption('metamta.recipients.show-hints', 'bool', true)
->setBoolOptions(
array(
pht('Show Recipient Hints'),
pht('No Recipient Hints'),
))
->setSummary(pht('Show "To:" and "Cc:" footer hints in email.'))
->setDescription($recipient_hints_description),
$this->newOption('metamta.email-preferences', 'bool', true)
->setBoolOptions(
array(
pht('Show Email Preferences Link'),
pht('No Email Preferences Link'),
))
->setSummary(pht('Show email preferences link in email.'))
->setDescription($email_preferences_description),
$this->newOption('metamta.re-prefix', 'bool', false)
->setBoolOptions(
array(
pht('Force "Re:" Subject Prefix'),
pht('No "Re:" Subject Prefix'),
))
->setSummary(pht('Control "Re:" subject prefix, for Mail.app.'))
->setDescription($re_prefix_description),
$this->newOption('metamta.vary-subjects', 'bool', true)
->setBoolOptions(
array(
pht('Allow Varied Subjects'),
pht('Always Use the Same Thread Subject'),
))
->setSummary(pht('Control subject variance, for some mail clients.'))
->setDescription($vary_subjects_description),
$this->newOption('metamta.insecure-auth-with-reply-to', 'bool', false)
->setBoolOptions(
array(
pht('Allow Insecure Reply-To Auth'),
pht('Disallow Reply-To Auth'),
))
->setSummary(pht('Trust "Reply-To" headers for authentication.'))
->setDescription($reply_to_description),
$this->newOption('metamta.placeholder-to-recipient', 'string', null)
->setSummary(pht('Placeholder for mail with only CCs.'))
->setDescription($placeholder_description),
$this->newOption('metamta.public-replies', 'bool', false)
->setBoolOptions(
array(
pht('Use Public Replies (Less Secure)'),
pht('Use Private Replies (More Secure)'),
))
->setSummary(
pht(
'Phabricator can use less-secure but mailing list friendly public '.
'reply addresses.'))
->setDescription($public_replies_description),
$this->newOption('metamta.single-reply-handler-prefix', 'string', null)
->setSummary(
pht('Allow Phabricator to use a single mailbox for all replies.'))
->setDescription($single_description),
$this->newOption('metamta.user-address-format', 'enum', 'full')
->setEnumOptions(
array(
'short' => 'short',
'real' => 'real',
'full' => 'full',
))
->setSummary(pht('Control how Phabricator renders user names in mail.'))
->setDescription($address_description)
->addExample('gwashington <gwashington@example.com>', 'short')
->addExample('George Washington <gwashington@example.com>', 'real')
->addExample(
'gwashington (George Washington) <gwashington@example.com>',
'full'),
$this->newOption('metamta.email-body-limit', 'int', 524288)
->setDescription(
pht(
'You can set a limit for the maximum byte size of outbound mail. '.
'Mail which is larger than this limit will be truncated before '.
'being sent. This can be useful if your MTA rejects mail which '.
'exceeds some limit (this is reasonably common). Specify a value '.
'in bytes.'))
->setSummary(pht('Global cap for size of generated emails (bytes).'))
->addExample(524288, pht('Truncate at 512KB'))
->addExample(1048576, pht('Truncate at 1MB')),
);
}
}
diff --git a/src/applications/config/option/PhabricatorMySQLConfigOptions.php b/src/applications/config/option/PhabricatorMySQLConfigOptions.php
index e3cd480e21..28fa78d2ab 100644
--- a/src/applications/config/option/PhabricatorMySQLConfigOptions.php
+++ b/src/applications/config/option/PhabricatorMySQLConfigOptions.php
@@ -1,87 +1,87 @@
<?php
final class PhabricatorMySQLConfigOptions
extends PhabricatorApplicationConfigOptions {
public function getName() {
return pht('MySQL');
}
public function getDescription() {
return pht('Database configuration.');
}
- public function getFontIcon() {
+ public function getIcon() {
return 'fa-database';
}
public function getGroup() {
return 'core';
}
public function getOptions() {
return array(
$this->newOption('mysql.host', 'string', 'localhost')
->setLocked(true)
->setDescription(
pht('MySQL database hostname.'))
->addExample('localhost', pht('MySQL on this machine'))
->addExample('db.example.com:3300', pht('Nonstandard port')),
$this->newOption('mysql.user', 'string', 'root')
->setLocked(true)
->setDescription(
pht('MySQL username to use when connecting to the database.')),
$this->newOption('mysql.pass', 'string', null)
->setHidden(true)
->setDescription(
pht('MySQL password to use when connecting to the database.')),
$this->newOption(
'mysql.configuration-provider',
'class',
'DefaultDatabaseConfigurationProvider')
->setLocked(true)
->setBaseClass('DatabaseConfigurationProvider')
->setSummary(
pht('Configure database configuration class.'))
->setDescription(
pht(
'Phabricator chooses which database to connect to through a '.
'swappable configuration provider. You almost certainly do not '.
'need to change this.')),
$this->newOption(
'mysql.implementation',
'class',
(extension_loaded('mysqli')
? 'AphrontMySQLiDatabaseConnection'
: 'AphrontMySQLDatabaseConnection'))
->setLocked(true)
->setBaseClass('AphrontMySQLDatabaseConnectionBase')
->setSummary(
pht('Configure database connection class.'))
->setDescription(
pht(
'Phabricator connects to MySQL through a swappable abstraction '.
'layer. You can choose an alternate implementation by setting '.
'this option. To provide your own implementation, extend '.
'`%s`. It is very unlikely that you need to change this.',
'AphrontMySQLDatabaseConnectionBase')),
$this->newOption('storage.default-namespace', 'string', 'phabricator')
->setLocked(true)
->setSummary(
pht('The namespace that Phabricator databases should use.'))
->setDescription(
pht(
"Phabricator puts databases in a namespace, which defaults to ".
"'phabricator' -- for instance, the Differential database is ".
"named 'phabricator_differential' by default. You can change ".
"this namespace if you want. Normally, you should not do this ".
"unless you are developing Phabricator and using namespaces to ".
"separate multiple sandbox datasets.")),
$this->newOption('mysql.port', 'string', null)
->setLocked(true)
->setDescription(
pht('MySQL port to use when connecting to the database.')),
);
}
}
diff --git a/src/applications/config/option/PhabricatorNotificationConfigOptions.php b/src/applications/config/option/PhabricatorNotificationConfigOptions.php
index f43f2af32a..7b6acf4ec7 100644
--- a/src/applications/config/option/PhabricatorNotificationConfigOptions.php
+++ b/src/applications/config/option/PhabricatorNotificationConfigOptions.php
@@ -1,65 +1,65 @@
<?php
final class PhabricatorNotificationConfigOptions
extends PhabricatorApplicationConfigOptions {
public function getName() {
return pht('Notifications');
}
public function getDescription() {
return pht('Configure real-time notifications.');
}
- public function getFontIcon() {
+ public function getIcon() {
return 'fa-bell';
}
public function getGroup() {
return 'core';
}
public function getOptions() {
return array(
$this->newOption('notification.enabled', 'bool', false)
->setBoolOptions(
array(
pht('Enable Real-Time Notifications'),
pht('Disable Real-Time Notifications'),
))
->setSummary(pht('Enable real-time notifications.'))
->setDescription(
pht(
"Enable real-time notifications. You must also run a Node.js ".
"based notification server for this to work. Consult the ".
"documentation in 'Notifications User Guide: Setup and ".
"Configuration' for instructions.")),
$this->newOption(
'notification.client-uri',
'string',
'http://localhost:22280/')
->setDescription(pht('Location of the client server.')),
$this->newOption(
'notification.server-uri',
'string',
'http://localhost:22281/')
->setDescription(pht('Location of the notification receiver server.')),
$this->newOption('notification.log', 'string', '/var/log/aphlict.log')
->setDescription(pht('Location of the server log file.')),
$this->newOption('notification.ssl-key', 'string', null)
->setLocked(true)
->setDescription(
pht('Path to SSL key to use for secure WebSockets.')),
$this->newOption('notification.ssl-cert', 'string', null)
->setLocked(true)
->setDescription(
pht('Path to SSL certificate to use for secure WebSockets.')),
$this->newOption(
'notification.pidfile',
'string',
'/var/tmp/aphlict/pid/aphlict.pid')
->setDescription(pht('Location of the server PID file.')),
);
}
}
diff --git a/src/applications/config/option/PhabricatorPHDConfigOptions.php b/src/applications/config/option/PhabricatorPHDConfigOptions.php
index 6fecd7117f..bfe7c148c4 100644
--- a/src/applications/config/option/PhabricatorPHDConfigOptions.php
+++ b/src/applications/config/option/PhabricatorPHDConfigOptions.php
@@ -1,95 +1,95 @@
<?php
final class PhabricatorPHDConfigOptions
extends PhabricatorApplicationConfigOptions {
public function getName() {
return pht('Daemons');
}
public function getDescription() {
return pht('Options relating to PHD (daemons).');
}
- public function getFontIcon() {
+ public function getIcon() {
return 'fa-pied-piper-alt';
}
public function getGroup() {
return 'core';
}
public function getOptions() {
return array(
$this->newOption('phd.pid-directory', 'string', '/var/tmp/phd/pid')
->setLocked(true)
->setDescription(
pht('Directory that phd should use to track running daemons.')),
$this->newOption('phd.log-directory', 'string', '/var/tmp/phd/log')
->setLocked(true)
->setDescription(
pht('Directory that the daemons should use to store log files.')),
$this->newOption('phd.taskmasters', 'int', 4)
->setLocked(true)
->setSummary(pht('Maximum taskmaster daemon pool size.'))
->setDescription(
pht(
'Maximum number of taskmaster daemons to run at once. Raising '.
'this can increase the maximum throughput of the task queue. The '.
'pool will automatically scale down when unutilized.')),
$this->newOption('phd.verbose', 'bool', false)
->setLocked(true)
->setBoolOptions(
array(
pht('Verbose mode'),
pht('Normal mode'),
))
->setSummary(pht("Launch daemons in 'verbose' mode by default."))
->setDescription(
pht(
"Launch daemons in 'verbose' mode by default. This creates a lot ".
"of output, but can help debug issues. Daemons launched in debug ".
"mode with '%s' are always launched in verbose mode. ".
"See also '%s'.",
'phd debug',
'phd.trace')),
$this->newOption('phd.user', 'string', null)
->setLocked(true)
->setSummary(pht('System user to run daemons as.'))
->setDescription(
pht(
'Specify a system user to run the daemons as. Primarily, this '.
'user will own the working copies of any repositories that '.
'Phabricator imports or manages. This option is new and '.
'experimental.')),
$this->newOption('phd.trace', 'bool', false)
->setLocked(true)
->setBoolOptions(
array(
pht('Trace mode'),
pht('Normal mode'),
))
->setSummary(pht("Launch daemons in 'trace' mode by default."))
->setDescription(
pht(
"Launch daemons in 'trace' mode by default. This creates an ".
"ENORMOUS amount of output, but can help debug issues. Daemons ".
"launched in debug mode with '%s' are always launched in ".
"trace mode. See also '%s'.",
'phd debug',
'phd.verbose')),
$this->newOption('phd.garbage-collection', 'wild', array())
->setLocked(true)
->setLockedMessage(
pht(
'This option can not be edited from the web UI. Use %s to adjust '.
'garbage collector policies.',
phutil_tag('tt', array(), 'bin/garbage set-policy')))
->setSummary(pht('Retention policies for garbage collection.'))
->setDescription(
pht(
'Customizes retention policies for garbage collectors.')),
);
}
}
diff --git a/src/applications/config/option/PhabricatorPHPMailerConfigOptions.php b/src/applications/config/option/PhabricatorPHPMailerConfigOptions.php
index b2d5c91e91..6b999b0d55 100644
--- a/src/applications/config/option/PhabricatorPHPMailerConfigOptions.php
+++ b/src/applications/config/option/PhabricatorPHPMailerConfigOptions.php
@@ -1,78 +1,78 @@
<?php
final class PhabricatorPHPMailerConfigOptions
extends PhabricatorApplicationConfigOptions {
public function getName() {
return pht('PHPMailer');
}
public function getDescription() {
return pht('Configure PHPMailer.');
}
- public function getFontIcon() {
+ public function getIcon() {
return 'fa-send-o';
}
public function getGroup() {
return 'core';
}
public function getOptions() {
return array(
$this->newOption('phpmailer.mailer', 'string', 'smtp')
->setLocked(true)
->setSummary(pht('Configure mailer used by PHPMailer.'))
->setDescription(
pht(
"If you're using PHPMailer to send email, provide the mailer and ".
"options here. PHPMailer is much more enormous than ".
"PHPMailerLite, and provides more mailers and greater enormity. ".
"You need it when you want to use SMTP instead of sendmail as the ".
"mailer.")),
$this->newOption('phpmailer.smtp-host', 'string', null)
->setLocked(true)
->setDescription(pht('Host for SMTP.')),
$this->newOption('phpmailer.smtp-port', 'int', 25)
->setLocked(true)
->setDescription(pht('Port for SMTP.')),
// TODO: Implement "enum"? Valid values are empty, 'tls', or 'ssl'.
$this->newOption('phpmailer.smtp-protocol', 'string', null)
->setLocked(true)
->setSummary(pht('Configure TLS or SSL for SMTP.'))
->setDescription(
pht(
"Using PHPMailer with SMTP, you can set this to one of '%s' or ".
"'%s' to use TLS or SSL, respectively. Leave it blank for ".
"vanilla SMTP. If you're sending via Gmail, set it to '%s'.",
'tls',
'ssl',
'ssl')),
$this->newOption('phpmailer.smtp-user', 'string', null)
->setLocked(true)
->setDescription(pht('Username for SMTP.')),
$this->newOption('phpmailer.smtp-password', 'string', null)
->setHidden(true)
->setDescription(pht('Password for SMTP.')),
$this->newOption('phpmailer.smtp-encoding', 'string', '8bit')
->setSummary(pht('Configure how mail is encoded.'))
->setDescription(
pht(
"Mail is normally encoded in `8bit`, which works correctly with ".
"most MTAs. However, some MTAs do not work well with this ".
"encoding. If you're having trouble with mail being mangled or ".
"arriving with too many or too few newlines, you may try ".
"adjusting this setting.\n\n".
"Supported values are `8bit` (default), `quoted-printable`, ".
"`7bit`, `binary` and `base64`.\n\n".
"The settings in the table below may work well.\n\n".
"| MTA | Setting | Notes\n".
"|-----|---------|------\n".
"| SendGrid via SMTP | `quoted-printable` | Double newlines under ".
"`8bit`.\n".
"| All Other MTAs | `8bit` | Default setting.")),
);
}
}
diff --git a/src/applications/config/option/PhabricatorPhurlConfigOptions.php b/src/applications/config/option/PhabricatorPhurlConfigOptions.php
index 726540d3dd..69e3dd6769 100644
--- a/src/applications/config/option/PhabricatorPhurlConfigOptions.php
+++ b/src/applications/config/option/PhabricatorPhurlConfigOptions.php
@@ -1,35 +1,35 @@
<?php
final class PhabricatorPhurlConfigOptions
extends PhabricatorApplicationConfigOptions {
public function getName() {
return pht('Phurl');
}
public function getDescription() {
return pht('Options for Phurl.');
}
- public function getFontIcon() {
+ public function getIcon() {
return 'fa-link';
}
public function getGroup() {
return 'apps';
}
public function getOptions() {
return array(
$this->newOption('phurl.short-uri', 'string', null)
->setLocked(true)
->setSummary(pht('URI that Phurl will use to shorten URLs.'))
->setDescription(
pht(
'Set the URI that Phurl will use to share shortened URLs.'))
->addExample(
'https://some-very-short-domain.museum/',
pht('Valid Setting')),
);
}
}
diff --git a/src/applications/config/option/PhabricatorRecaptchaConfigOptions.php b/src/applications/config/option/PhabricatorRecaptchaConfigOptions.php
index 576ac18913..356bcfd4dd 100644
--- a/src/applications/config/option/PhabricatorRecaptchaConfigOptions.php
+++ b/src/applications/config/option/PhabricatorRecaptchaConfigOptions.php
@@ -1,47 +1,47 @@
<?php
final class PhabricatorRecaptchaConfigOptions
extends PhabricatorApplicationConfigOptions {
public function getName() {
return pht('Integration with Recaptcha');
}
public function getDescription() {
return pht('Configure Recaptcha captchas.');
}
- public function getFontIcon() {
+ public function getIcon() {
return 'fa-recycle';
}
public function getGroup() {
return 'core';
}
public function getOptions() {
return array(
$this->newOption('recaptcha.enabled', 'bool', false)
->setBoolOptions(
array(
pht('Enable Recaptcha'),
pht('Disable Recaptcha'),
))
->setSummary(pht('Enable captchas with Recaptcha.'))
->setDescription(
pht(
'Enable recaptcha to require users solve captchas after a few '.
'failed login attempts. This hinders brute-force attacks against '.
'user passwords. For more information, see http://recaptcha.net/')),
$this->newOption('recaptcha.public-key', 'string', null)
->setDescription(
pht('Recaptcha public key, obtained by signing up for Recaptcha.')),
$this->newOption('recaptcha.private-key', 'string', null)
->setHidden(true)
->setDescription(
pht('Recaptcha private key, obtained by signing up for Recaptcha.')),
);
}
}
diff --git a/src/applications/config/option/PhabricatorSMSConfigOptions.php b/src/applications/config/option/PhabricatorSMSConfigOptions.php
index 33b75c263f..08f2e50ee1 100644
--- a/src/applications/config/option/PhabricatorSMSConfigOptions.php
+++ b/src/applications/config/option/PhabricatorSMSConfigOptions.php
@@ -1,60 +1,60 @@
<?php
final class PhabricatorSMSConfigOptions
extends PhabricatorApplicationConfigOptions {
public function getName() {
return pht('SMS');
}
public function getDescription() {
return pht('Configure SMS.');
}
- public function getFontIcon() {
+ public function getIcon() {
return 'fa-mobile';
}
public function getGroup() {
return 'core';
}
public function getOptions() {
$adapter_description = pht(
'Adapter class to use to transmit SMS to an external provider. A given '.
'external provider will most likely need more configuration which will '.
'most likely require registration and payment for the service.');
return array(
$this->newOption(
'sms.default-sender',
'string',
null)
->setDescription(pht('Default "from" number.'))
->addExample('8675309', 'Jenny still has this number')
->addExample('18005555555', 'Maybe not a real number'),
$this->newOption(
'sms.default-adapter',
'class',
null)
->setBaseClass('PhabricatorSMSImplementationAdapter')
->setSummary(pht('Control how SMS is sent.'))
->setDescription($adapter_description),
$this->newOption(
'twilio.account-sid',
'string',
null)
->setDescription(pht('Account ID on Twilio service.'))
->setLocked(true)
->addExample('gf5kzccfn2sfknpnadvz7kokv6nz5v', pht('30 characters')),
$this->newOption(
'twilio.auth-token',
'string',
null)
->setDescription(pht('Authorization token from Twilio service.'))
->setHidden(true)
->addExample('f3jsi4i67wiwt6w54hf2zwvy3fjf5h', pht('30 characters')),
);
}
}
diff --git a/src/applications/config/option/PhabricatorSecurityConfigOptions.php b/src/applications/config/option/PhabricatorSecurityConfigOptions.php
index 8baea2e664..8c9907d736 100644
--- a/src/applications/config/option/PhabricatorSecurityConfigOptions.php
+++ b/src/applications/config/option/PhabricatorSecurityConfigOptions.php
@@ -1,325 +1,325 @@
<?php
final class PhabricatorSecurityConfigOptions
extends PhabricatorApplicationConfigOptions {
public function getName() {
return pht('Security');
}
public function getDescription() {
return pht('Security options.');
}
- public function getFontIcon() {
+ public function getIcon() {
return 'fa-lock';
}
public function getGroup() {
return 'core';
}
public function getOptions() {
$doc_href = PhabricatorEnv::getDoclink('Configuring a File Domain');
$doc_name = pht('Configuration Guide: Configuring a File Domain');
// This is all of the IANA special/reserved blocks in IPv4 space.
$default_address_blacklist = array(
'0.0.0.0/8',
'10.0.0.0/8',
'100.64.0.0/10',
'127.0.0.0/8',
'169.254.0.0/16',
'172.16.0.0/12',
'192.0.0.0/24',
'192.0.2.0/24',
'192.88.99.0/24',
'192.168.0.0/16',
'198.18.0.0/15',
'198.51.100.0/24',
'203.0.113.0/24',
'224.0.0.0/4',
'240.0.0.0/4',
'255.255.255.255/32',
);
return array(
$this->newOption('security.alternate-file-domain', 'string', null)
->setLocked(true)
->setSummary(pht('Alternate domain to serve files from.'))
->setDescription(
pht(
'By default, Phabricator serves files from the same domain '.
'the application is served from. This is convenient, but '.
'presents a security risk.'.
"\n\n".
'You should configure a CDN or alternate file domain to mitigate '.
'this risk. Configuring a CDN will also improve performance. See '.
'[[ %s | %s ]] for instructions.',
$doc_href,
$doc_name))
->addExample('https://files.phabcdn.net/', pht('Valid Setting')),
$this->newOption(
'security.hmac-key',
'string',
'[D\t~Y7eNmnQGJ;rnH6aF;m2!vJ8@v8C=Cs:aQS\.Qw')
->setHidden(true)
->setSummary(
pht('Key for HMAC digests.'))
->setDescription(
pht(
'Default key for HMAC digests where the key is not important '.
'(i.e., the hash itself is secret). You can change this if you '.
'want (to any other string), but doing so will break existing '.
'sessions and CSRF tokens.')),
$this->newOption('security.require-https', 'bool', false)
->setLocked(true)
->setSummary(
pht('Force users to connect via HTTPS instead of HTTP.'))
->setDescription(
pht(
"If the web server responds to both HTTP and HTTPS requests but ".
"you want users to connect with only HTTPS, you can set this ".
"to true to make Phabricator redirect HTTP requests to HTTPS.\n\n".
"Normally, you should just configure your server not to accept ".
"HTTP traffic, but this setting may be useful if you originally ".
"used HTTP and have now switched to HTTPS but don't want to ".
"break old links, or if your webserver sits behind a load ".
"balancer which terminates HTTPS connections and you can not ".
"reasonably configure more granular behavior there.\n\n".
"IMPORTANT: Phabricator determines if a request is HTTPS or not ".
"by examining the PHP `%s` variable. If you run ".
"Apache/mod_php this will probably be set correctly for you ".
"automatically, but if you run Phabricator as CGI/FCGI (e.g., ".
"through nginx or lighttpd), you need to configure your web ".
"server so that it passes the value correctly based on the ".
"connection type.",
"\$_SERVER['HTTPS']"))
->setBoolOptions(
array(
pht('Force HTTPS'),
pht('Allow HTTP'),
)),
$this->newOption('security.require-multi-factor-auth', 'bool', false)
->setLocked(true)
->setSummary(
pht('Require all users to configure multi-factor authentication.'))
->setDescription(
pht(
'By default, Phabricator allows users to add multi-factor '.
'authentication to their accounts, but does not require it. '.
'By enabling this option, you can force all users to add '.
'at least one authentication factor before they can use their '.
'accounts.'))
->setBoolOptions(
array(
pht('Multi-Factor Required'),
pht('Multi-Factor Optional'),
)),
$this->newOption(
'phabricator.csrf-key',
'string',
'0b7ec0592e0a2829d8b71df2fa269b2c6172eca3')
->setHidden(true)
->setSummary(
pht('Hashed with other inputs to generate CSRF tokens.'))
->setDescription(
pht(
'This is hashed with other inputs to generate CSRF tokens. If '.
'you want, you can change it to some other string which is '.
'unique to your install. This will make your install more secure '.
'in a vague, mostly theoretical way. But it will take you like 3 '.
'seconds of mashing on your keyboard to set it up so you might '.
'as well.')),
$this->newOption(
'phabricator.mail-key',
'string',
'5ce3e7e8787f6e40dfae861da315a5cdf1018f12')
->setHidden(true)
->setSummary(
pht('Hashed with other inputs to generate mail tokens.'))
->setDescription(
pht(
"This is hashed with other inputs to generate mail tokens. If ".
"you want, you can change it to some other string which is ".
"unique to your install. In particular, you will want to do ".
"this if you accidentally send a bunch of mail somewhere you ".
"shouldn't have, to invalidate all old reply-to addresses.")),
$this->newOption(
'uri.allowed-protocols',
'set',
array(
'http' => true,
'https' => true,
'mailto' => true,
))
->setSummary(
pht('Determines which URI protocols are auto-linked.'))
->setDescription(
pht(
"When users write comments which have URIs, they'll be ".
"automatically linked if the protocol appears in this set. This ".
"whitelist is primarily to prevent security issues like ".
"%s URIs.",
'javascript://'))
->addExample("http\nhttps", pht('Valid Setting'))
->setLocked(true),
$this->newOption(
'uri.allowed-editor-protocols',
'set',
array(
'http' => true,
'https' => true,
// This handler is installed by Textmate.
'txmt' => true,
// This handler is for MacVim.
'mvim' => true,
// Unofficial handler for Vim.
'vim' => true,
// Unofficial handler for Sublime.
'subl' => true,
// Unofficial handler for Emacs.
'emacs' => true,
// This isn't a standard handler installed by an application, but
// is a reasonable name for a user-installed handler.
'editor' => true,
))
->setSummary(pht('Whitelists editor protocols for "Open in Editor".'))
->setDescription(
pht(
'Users can configure a URI pattern to open files in a text '.
'editor. The URI must use a protocol on this whitelist.'))
->setLocked(true),
$this->newOption(
'celerity.resource-hash',
'string',
'd9455ea150622ee044f7931dabfa52aa')
->setSummary(
pht('An input to the hash function when building resource hashes.'))
->setDescription(
pht(
'This value is an input to the hash function when building '.
'resource hashes. It has no security value, but if you '.
'accidentally poison user caches (by pushing a bad patch or '.
'having something go wrong with a CDN, e.g.) you can change this '.
'to something else and rebuild the Celerity map to break user '.
'caches. Unless you are doing Celerity development, it is '.
'exceptionally unlikely that you need to modify this.')),
$this->newOption('remarkup.enable-embedded-youtube', 'bool', false)
->setBoolOptions(
array(
pht('Embed YouTube videos'),
pht("Don't embed YouTube videos"),
))
->setSummary(
pht('Determines whether or not YouTube videos get embedded.'))
->setDescription(
pht(
"If you enable this, linked YouTube videos will be embedded ".
"inline. This has mild security implications (you'll leak ".
"referrers to YouTube) and is pretty silly (but sort of ".
"awesome).")),
$this->newOption(
'security.outbound-blacklist',
'list<string>',
$default_address_blacklist)
->setLocked(true)
->setSummary(
pht(
'Blacklist subnets to prevent user-initiated outbound '.
'requests.'))
->setDescription(
pht(
'Phabricator users can make requests to other services from '.
'the Phabricator host in some circumstances (for example, by '.
'creating a repository with a remote URL or having Phabricator '.
'fetch an image from a remote server).'.
"\n\n".
'This may represent a security vulnerability if services on '.
'the same subnet will accept commands or reveal private '.
'information over unauthenticated HTTP GET, based on the source '.
'IP address. In particular, all hosts in EC2 have access to '.
'such a service.'.
"\n\n".
'This option defines a list of netblocks which Phabricator '.
'will decline to connect to. Generally, you should list all '.
'private IP space here.'))
->addExample(array('0.0.0.0/0'), pht('No Outbound Requests')),
$this->newOption('security.strict-transport-security', 'bool', false)
->setLocked(true)
->setBoolOptions(
array(
pht('Use HSTS'),
pht('Do Not Use HSTS'),
))
->setSummary(pht('Enable HTTP Strict Transport Security (HSTS).'))
->setDescription(
pht(
'HTTP Strict Transport Security (HSTS) sends a header which '.
'instructs browsers that the site should only be accessed '.
'over HTTPS, never HTTP. This defuses an attack where an '.
'adversary gains access to your network, then proxies requests '.
'through an unsecured link.'.
"\n\n".
'Do not enable this option if you serve (or plan to ever serve) '.
'unsecured content over plain HTTP. It is very difficult to '.
'undo this change once users\' browsers have accepted the '.
'setting.')),
);
}
protected function didValidateOption(
PhabricatorConfigOption $option,
$value) {
$key = $option->getKey();
if ($key == 'security.alternate-file-domain') {
$uri = new PhutilURI($value);
$protocol = $uri->getProtocol();
if ($protocol !== 'http' && $protocol !== 'https') {
throw new PhabricatorConfigValidationException(
pht(
"Config option '%s' is invalid. The URI must start with ".
"'%s' or '%s'.",
$key,
'http://',
'https://'));
}
$domain = $uri->getDomain();
if (strpos($domain, '.') === false) {
throw new PhabricatorConfigValidationException(
pht(
"Config option '%s' is invalid. The URI must contain a dot ('.'), ".
"like '%s', not just a bare name like '%s'. ".
"Some web browsers will not set cookies on domains with no TLD.",
$key,
'http://example.com/',
'http://example/'));
}
$path = $uri->getPath();
if ($path !== '' && $path !== '/') {
throw new PhabricatorConfigValidationException(
pht(
"Config option '%s' is invalid. The URI must NOT have a path, ".
"e.g. '%s' is OK, but '%s' is not. Phabricator must be installed ".
"on an entire domain; it can not be installed on a path.",
$key,
'http://phabricator.example.com/',
'http://example.com/phabricator/'));
}
}
}
}
diff --git a/src/applications/config/option/PhabricatorSendGridConfigOptions.php b/src/applications/config/option/PhabricatorSendGridConfigOptions.php
index c740792a7a..0baa7390af 100644
--- a/src/applications/config/option/PhabricatorSendGridConfigOptions.php
+++ b/src/applications/config/option/PhabricatorSendGridConfigOptions.php
@@ -1,33 +1,33 @@
<?php
final class PhabricatorSendGridConfigOptions
extends PhabricatorApplicationConfigOptions {
public function getName() {
return pht('Integration with SendGrid');
}
public function getDescription() {
return pht('Configure SendGrid integration.');
}
- public function getFontIcon() {
+ public function getIcon() {
return 'fa-send-o';
}
public function getGroup() {
return 'core';
}
public function getOptions() {
return array(
$this->newOption('sendgrid.api-user', 'string', null)
->setLocked(true)
->setDescription(pht('SendGrid API username.')),
$this->newOption('sendgrid.api-key', 'string', null)
->setHidden(true)
->setDescription(pht('SendGrid API key.')),
);
}
}
diff --git a/src/applications/config/option/PhabricatorSyntaxHighlightingConfigOptions.php b/src/applications/config/option/PhabricatorSyntaxHighlightingConfigOptions.php
index 25b8835caf..41133d5ede 100644
--- a/src/applications/config/option/PhabricatorSyntaxHighlightingConfigOptions.php
+++ b/src/applications/config/option/PhabricatorSyntaxHighlightingConfigOptions.php
@@ -1,153 +1,153 @@
<?php
final class PhabricatorSyntaxHighlightingConfigOptions
extends PhabricatorApplicationConfigOptions {
public function getName() {
return pht('Syntax Highlighting');
}
public function getDescription() {
return pht('Options relating to syntax highlighting source code.');
}
- public function getFontIcon() {
+ public function getIcon() {
return 'fa-code';
}
public function getGroup() {
return 'core';
}
public function getOptions() {
$caches_href = PhabricatorEnv::getDocLink('Managing Caches');
return array(
$this->newOption(
'syntax-highlighter.engine',
'class',
'PhutilDefaultSyntaxHighlighterEngine')
->setBaseClass('PhutilSyntaxHighlighterEngine')
->setSummary(pht('Default non-pygments syntax highlighter engine.'))
->setDescription(
pht(
'Phabricator can highlight PHP by default and use Pygments for '.
'other languages if enabled. You can provide a custom '.
'highlighter engine by extending class %s.',
'PhutilSyntaxHighlighterEngine')),
$this->newOption('pygments.enabled', 'bool', false)
->setSummary(
pht('Should Phabricator use Pygments to highlight code?'))
->setBoolOptions(
array(
pht('Use Pygments'),
pht('Do Not Use Pygments'),
))
->setDescription(
pht(
'Phabricator supports syntax highlighting a few languages by '.
'default, but you can install Pygments (a third-party syntax '.
'highlighting tool) to provide support for many more languages.'.
"\n\n".
'To install Pygments, visit '.
'[[ http://pygments.org | pygments.org ]] and follow the '.
'download and install instructions.'.
"\n\n".
'Once Pygments is installed, enable this option '.
'(`pygments.enabled`) to make Phabricator use Pygments when '.
'highlighting source code.'.
"\n\n".
'After you install and enable Pygments, newly created source '.
'code (like diffs and pastes) should highlight correctly. '.
'You may need to clear Phabricator\'s caches to get previously '.
'existing source code to highlight. For instructions on '.
'managing caches, see [[ %s | Managing Caches ]].',
$caches_href)),
$this->newOption(
'pygments.dropdown-choices',
'wild',
array(
'apacheconf' => 'Apache Configuration',
'bash' => 'Bash Scripting',
'brainfuck' => 'Brainf*ck',
'c' => 'C',
'coffee-script' => 'CoffeeScript',
'cpp' => 'C++',
'csharp' => 'C#',
'css' => 'CSS',
'd' => 'D',
'diff' => 'Diff',
'django' => 'Django Templating',
'docker' => 'Docker',
'erb' => 'Embedded Ruby/ERB',
'erlang' => 'Erlang',
'go' => 'Golang',
'groovy' => 'Groovy',
'haskell' => 'Haskell',
'html' => 'HTML',
'http' => 'HTTP',
'invisible' => 'Invisible',
'java' => 'Java',
'js' => 'Javascript',
'json' => 'JSON',
'make' => 'Makefile',
'mysql' => 'MySQL',
'nginx' => 'Nginx Configuration',
'objc' => 'Objective-C',
'perl' => 'Perl',
'php' => 'PHP',
'postgresql' => 'PostgreSQL',
'pot' => 'Gettext Catalog',
'puppet' => 'Puppet',
'python' => 'Python',
'rainbow' => 'Rainbow',
'remarkup' => 'Remarkup',
'rst' => 'reStructuredText',
'robotframework' => 'RobotFramework',
'ruby' => 'Ruby',
'sql' => 'SQL',
'tex' => 'LaTeX',
'text' => 'Plain Text',
'twig' => 'Twig',
'xml' => 'XML',
'yaml' => 'YAML',
))
->setSummary(
pht('Set the language list which appears in dropdowns.'))
->setDescription(
pht(
'In places that we display a dropdown to syntax-highlight code, '.
'this is where that list is defined.')),
$this->newOption(
'syntax.filemap',
'wild',
array(
'@\.arcconfig$@' => 'js',
'@\.arclint$@' => 'js',
'@\.divinerconfig$@' => 'js',
))
->setSummary(
pht('Override what language files (based on filename) highlight as.'))
->setDescription(
pht(
'This is an override list of regular expressions which allows '.
'you to choose what language files are highlighted as. If your '.
'projects have certain rules about filenames or use unusual or '.
'ambiguous language extensions, you can create a mapping here. '.
'This is an ordered dictionary of regular expressions which will '.
'be tested against the filename. They should map to either an '.
'explicit language as a string value, or a numeric index into '.
'the captured groups as an integer.'))
->addExample('{"@\\.xyz$@": "php"}', pht('Highlight %s as PHP.', '*.xyz'))
->addExample(
'{"@/httpd\\.conf@": "apacheconf"}',
pht('Highlight httpd.conf as "apacheconf".'))
->addExample(
'{"@\\.([^.]+)\\.bak$@": 1}',
pht(
"Treat all '*.x.bak' file as '.x'. NOTE: We map to capturing group ".
"1 by specifying the mapping as '1'")),
);
}
}
diff --git a/src/applications/config/option/PhabricatorTranslationsConfigOptions.php b/src/applications/config/option/PhabricatorTranslationsConfigOptions.php
index aa7b9a2b32..c82e7901bc 100644
--- a/src/applications/config/option/PhabricatorTranslationsConfigOptions.php
+++ b/src/applications/config/option/PhabricatorTranslationsConfigOptions.php
@@ -1,38 +1,38 @@
<?php
final class PhabricatorTranslationsConfigOptions
extends PhabricatorApplicationConfigOptions {
public function getName() {
return pht('Translations');
}
public function getDescription() {
return pht('Options relating to translations.');
}
- public function getFontIcon() {
+ public function getIcon() {
return 'fa-globe';
}
public function getGroup() {
return 'core';
}
public function getOptions() {
return array(
$this->newOption('translation.override', 'wild', array())
->setSummary(pht('Override translations.'))
->setDescription(
pht(
"You can use '%s' if you don't want to create a full translation ".
"to give users an option for switching to it and you just want to ".
"override some strings in the default translation.",
'translation.override'))
->addExample(
'{"some string": "my alternative"}',
pht('Valid Setting')),
);
}
}
diff --git a/src/applications/config/option/PhabricatorUIConfigOptions.php b/src/applications/config/option/PhabricatorUIConfigOptions.php
index efd4f5a5bd..e73b4ee780 100644
--- a/src/applications/config/option/PhabricatorUIConfigOptions.php
+++ b/src/applications/config/option/PhabricatorUIConfigOptions.php
@@ -1,100 +1,100 @@
<?php
final class PhabricatorUIConfigOptions
extends PhabricatorApplicationConfigOptions {
public function getName() {
return pht('User Interface');
}
public function getDescription() {
return pht('Configure the Phabricator UI, including colors.');
}
- public function getFontIcon() {
+ public function getIcon() {
return 'fa-magnet';
}
public function getGroup() {
return 'core';
}
public function getOptions() {
$custom_header_example =
PhabricatorCustomHeaderConfigType::getExampleConfig();
$experimental_link = 'https://secure.phabricator.com/T4214';
$options = array(
'blindigo' => 'blindigo',
'red' => 'red',
'blue' => 'blue',
'green' => 'green',
'indigo' => 'indigo',
'dark' => 'dark',
);
$example = <<<EOJSON
[
{
"name" : "Copyright 2199 Examplecorp"
},
{
"name" : "Privacy Policy",
"href" : "http://www.example.org/privacy/"
},
{
"name" : "Terms and Conditions",
"href" : "http://www.example.org/terms/"
}
]
EOJSON;
return array(
$this->newOption('ui.header-color', 'enum', 'blindigo')
->setDescription(
pht('Sets the default color scheme of Phabricator.'))
->setEnumOptions($options),
$this->newOption('ui.footer-items', 'list<wild>', array())
->setSummary(
pht(
'Allows you to add footer links on most pages.'))
->setDescription(
pht(
"Allows you to add a footer with links in it to most ".
"pages. You might want to use these links to point at legal ".
"information or an about page.\n\n".
"Specify a list of dictionaries. Each dictionary describes ".
"a footer item. These keys are supported:\n\n".
" - `name` The name of the item.\n".
" - `href` Optionally, the link target of the item. You can ".
" omit this if you just want a piece of text, like a copyright ".
" notice."))
->addExample($example, pht('Basic Example')),
$this->newOption(
'ui.custom-header',
'custom:PhabricatorCustomHeaderConfigType',
null)
->setSummary(
pht('Customize the Phabricator logo.'))
->setDescription(
pht('You can customize the Phabricator logo by specifying the '.
'phid for a viewable image you have uploaded to Phabricator '.
'via the [[ /file/ | Files application]]. This image should '.
'be:'."\n".
' - 192px X 80px; while not enforced, images with these '.
'dimensions will look best across devices.'."\n".
' - have view policy public if [[ '.
'/config/edit/policy.allow-public | `policy.allow-public`]] '.
'is true and otherwise view policy user; mismatches in these '.
'policy settings will result in a broken logo for some users.'.
"\n\n".
'You should restart Phabricator after updating this value '.
'to see this change take effect.'.
"\n\n".
'As this feature is experimental, please read [[ %s | T4214 ]] '.
'for up to date information.',
$experimental_link))
->addExample($custom_header_example, pht('Valid Config')),
);
}
}
diff --git a/src/applications/conpherence/application/PhabricatorConpherenceApplication.php b/src/applications/conpherence/application/PhabricatorConpherenceApplication.php
index 7708e6a539..ea06aaa456 100644
--- a/src/applications/conpherence/application/PhabricatorConpherenceApplication.php
+++ b/src/applications/conpherence/application/PhabricatorConpherenceApplication.php
@@ -1,81 +1,81 @@
<?php
final class PhabricatorConpherenceApplication extends PhabricatorApplication {
public function getBaseURI() {
return '/conpherence/';
}
public function getName() {
return pht('Conpherence');
}
public function getShortDescription() {
return pht('Chat with Others');
}
- public function getFontIcon() {
+ public function getIcon() {
return 'fa-comments';
}
public function getTitleGlyph() {
return "\xE2\x9C\x86";
}
public function getRemarkupRules() {
return array(
new ConpherenceThreadRemarkupRule(),
);
}
public function getRoutes() {
return array(
'/Z(?P<id>[1-9]\d*)' => 'ConpherenceViewController',
'/conpherence/' => array(
'' => 'ConpherenceListController',
'thread/(?P<id>[1-9]\d*)/' => 'ConpherenceListController',
'(?P<id>[1-9]\d*)/' => 'ConpherenceViewController',
'(?P<id>[1-9]\d*)/(?P<messageID>[1-9]\d*)/'
=> 'ConpherenceViewController',
'columnview/' => 'ConpherenceColumnViewController',
'new/' => 'ConpherenceNewRoomController',
'search/(?:query/(?P<queryKey>[^/]+)/)?'
=> 'ConpherenceRoomListController',
'panel/' => 'ConpherenceNotificationPanelController',
'widget/(?P<id>[1-9]\d*)/' => 'ConpherenceWidgetController',
'update/(?P<id>[1-9]\d*)/' => 'ConpherenceUpdateController',
),
);
}
public function getQuickCreateItems(PhabricatorUser $viewer) {
$items = array();
$item = id(new PHUIListItemView())
->setName(pht('Conpherence Room'))
->setIcon('fa-comments')
->setWorkflow(true)
->setHref($this->getBaseURI().'new/');
$items[] = $item;
return $items;
}
public function getQuicksandURIPatternBlacklist() {
return array(
'/conpherence/.*',
'/Z\d+',
);
}
public function getMailCommandObjects() {
// TODO: Conpherence threads don't currently support any commands directly,
// so the documentation page we end up generating is empty and funny
// looking. Add support here once we support "!add", "!leave", "!topic",
// or whatever else.
return array();
}
}
diff --git a/src/applications/conpherence/config/ConpherenceConfigOptions.php b/src/applications/conpherence/config/ConpherenceConfigOptions.php
index f309b8d569..24e1cb126d 100644
--- a/src/applications/conpherence/config/ConpherenceConfigOptions.php
+++ b/src/applications/conpherence/config/ConpherenceConfigOptions.php
@@ -1,32 +1,32 @@
<?php
final class ConpherenceConfigOptions
extends PhabricatorApplicationConfigOptions {
public function getName() {
return pht('Conpherence');
}
public function getDescription() {
return pht('Configure Conpherence messaging.');
}
- public function getFontIcon() {
+ public function getIcon() {
return 'fa-comments';
}
public function getGroup() {
return 'apps';
}
public function getOptions() {
return array(
$this->newOption(
'metamta.conpherence.subject-prefix',
'string',
'[Conpherence]')
->setDescription(pht('Subject prefix for Conpherence mail.')),
);
}
}
diff --git a/src/applications/countdown/application/PhabricatorCountdownApplication.php b/src/applications/countdown/application/PhabricatorCountdownApplication.php
index 5daaa5021f..d6c62d7e1c 100644
--- a/src/applications/countdown/application/PhabricatorCountdownApplication.php
+++ b/src/applications/countdown/application/PhabricatorCountdownApplication.php
@@ -1,74 +1,74 @@
<?php
final class PhabricatorCountdownApplication extends PhabricatorApplication {
public function getBaseURI() {
return '/countdown/';
}
- public function getFontIcon() {
+ public function getIcon() {
return 'fa-rocket';
}
public function getName() {
return pht('Countdown');
}
public function getShortDescription() {
return pht('Countdown to Events');
}
public function getTitleGlyph() {
return "\xE2\x9A\xB2";
}
public function getFlavorText() {
return pht('Utilize the full capabilities of your ALU.');
}
public function getApplicationGroup() {
return self::GROUP_UTILITIES;
}
public function getRemarkupRules() {
return array(
new PhabricatorCountdownRemarkupRule(),
);
}
public function getRoutes() {
return array(
'/C(?P<id>[1-9]\d*)' => 'PhabricatorCountdownViewController',
'/countdown/' => array(
'(?:query/(?P<queryKey>[^/]+)/)?'
=> 'PhabricatorCountdownListController',
'(?P<id>[1-9]\d*)/'
=> 'PhabricatorCountdownViewController',
'comment/(?P<id>[1-9]\d*)/'
=> 'PhabricatorCountdownCommentController',
'edit/(?:(?P<id>[1-9]\d*)/)?'
=> 'PhabricatorCountdownEditController',
'create/'
=> 'PhabricatorCountdownEditController',
'delete/(?P<id>[1-9]\d*)/'
=> 'PhabricatorCountdownDeleteController',
),
);
}
protected function getCustomCapabilities() {
return array(
PhabricatorCountdownDefaultViewCapability::CAPABILITY => array(
'caption' => pht('Default view policy for new countdowns.'),
'template' => PhabricatorCountdownCountdownPHIDType::TYPECONST,
'capability' => PhabricatorPolicyCapability::CAN_VIEW,
),
PhabricatorCountdownDefaultEditCapability::CAPABILITY => array(
'caption' => pht('Default edit policy for new countdowns.'),
'template' => PhabricatorCountdownCountdownPHIDType::TYPECONST,
'capability' => PhabricatorPolicyCapability::CAN_EDIT,
),
);
}
}
diff --git a/src/applications/countdown/query/PhabricatorCountdownSearchEngine.php b/src/applications/countdown/query/PhabricatorCountdownSearchEngine.php
index ae90e5f3e7..79b329385a 100644
--- a/src/applications/countdown/query/PhabricatorCountdownSearchEngine.php
+++ b/src/applications/countdown/query/PhabricatorCountdownSearchEngine.php
@@ -1,168 +1,168 @@
<?php
final class PhabricatorCountdownSearchEngine
extends PhabricatorApplicationSearchEngine {
public function getResultTypeDescription() {
return pht('Countdowns');
}
public function getApplicationClassName() {
return 'PhabricatorCountdownApplication';
}
public function newQuery() {
return new PhabricatorCountdownQuery();
}
protected function buildQueryFromParameters(array $map) {
$query = $this->newQuery();
if ($map['authorPHIDs']) {
$query->withAuthorPHIDs($map['authorPHIDs']);
}
if ($map['upcoming'] && $map['upcoming'][0] == 'upcoming') {
$query->withUpcoming();
}
return $query;
}
protected function buildCustomSearchFields() {
return array(
id(new PhabricatorUsersSearchField())
->setLabel(pht('Authors'))
->setKey('authorPHIDs')
->setAliases(array('author', 'authors')),
id(new PhabricatorSearchCheckboxesField())
->setKey('upcoming')
->setOptions(array(
'upcoming' => pht('Show only upcoming countdowns.'),
)),
);
}
protected function getURI($path) {
return '/countdown/'.$path;
}
protected function getBuiltinQueryNames() {
$names = array(
'upcoming' => pht('Upcoming'),
'all' => pht('All'),
);
if ($this->requireViewer()->getPHID()) {
$names['authored'] = pht('Authored');
}
return $names;
}
public function buildSavedQueryFromBuiltin($query_key) {
$query = $this->newSavedQuery();
$query->setQueryKey($query_key);
switch ($query_key) {
case 'all':
return $query;
case 'authored':
return $query->setParameter(
'authorPHIDs',
array($this->requireViewer()->getPHID()));
case 'upcoming':
return $query->setParameter('upcoming', array('upcoming'));
}
return parent::buildSavedQueryFromBuiltin($query_key);
}
protected function getRequiredHandlePHIDsForResultList(
array $countdowns,
PhabricatorSavedQuery $query) {
return mpull($countdowns, 'getAuthorPHID');
}
protected function renderResultList(
array $countdowns,
PhabricatorSavedQuery $query,
array $handles) {
assert_instances_of($countdowns, 'PhabricatorCountdown');
$viewer = $this->requireViewer();
$list = new PHUIObjectItemListView();
$list->setUser($viewer);
foreach ($countdowns as $countdown) {
$id = $countdown->getID();
$ended = false;
$epoch = $countdown->getEpoch();
if ($epoch <= PhabricatorTime::getNow()) {
$ended = true;
}
$item = id(new PHUIObjectItemView())
->setUser($viewer)
->setObject($countdown)
->setObjectName("C{$id}")
->setHeader($countdown->getTitle())
->setHref($this->getApplicationURI("{$id}/"))
->addByline(
pht(
'Created by %s',
$handles[$countdown->getAuthorPHID()]->renderLink()));
if ($ended) {
$item->addAttribute(
pht('Launched on %s', phabricator_datetime($epoch, $viewer)));
$item->setDisabled(true);
} else {
$time_left = ($epoch - PhabricatorTime::getNow());
$num = round($time_left / (60 * 60 * 24));
$noun = pht('Days');
if ($num < 1) {
$num = round($time_left / (60 * 60), 1);
$noun = pht('Hours');
}
$item->setCountdown($num, $noun);
$item->addAttribute(
phabricator_datetime($epoch, $viewer));
}
$list->addItem($item);
}
$result = new PhabricatorApplicationSearchResultView();
$result->setObjectList($list);
$result->setNoDataString(pht('No countdowns found.'));
return $result;
}
protected function getNewUserBody() {
$create_button = id(new PHUIButtonView())
->setTag('a')
->setText(pht('Create a Countdown'))
->setHref('/countdown/create/')
->setColor(PHUIButtonView::GREEN);
- $icon = $this->getApplication()->getFontIcon();
+ $icon = $this->getApplication()->getIcon();
$app_name = $this->getApplication()->getName();
$view = id(new PHUIBigInfoView())
->setIcon($icon)
->setTitle(pht('Welcome to %s', $app_name))
->setDescription(
pht('Keep track of upcoming launch dates with '.
'embeddable counters.'))
->addAction($create_button);
return $view;
}
}
diff --git a/src/applications/daemon/application/PhabricatorDaemonsApplication.php b/src/applications/daemon/application/PhabricatorDaemonsApplication.php
index c605be63b6..a0fb77beb0 100644
--- a/src/applications/daemon/application/PhabricatorDaemonsApplication.php
+++ b/src/applications/daemon/application/PhabricatorDaemonsApplication.php
@@ -1,62 +1,62 @@
<?php
final class PhabricatorDaemonsApplication extends PhabricatorApplication {
public function getName() {
return pht('Daemons');
}
public function getShortDescription() {
return pht('Manage Phabricator Daemons');
}
public function getBaseURI() {
return '/daemon/';
}
public function getTitleGlyph() {
return "\xE2\x98\xAF";
}
- public function getFontIcon() {
+ public function getIcon() {
return 'fa-pied-piper-alt';
}
public function getApplicationGroup() {
return self::GROUP_ADMIN;
}
public function canUninstall() {
return false;
}
public function getEventListeners() {
return array(
new PhabricatorDaemonEventListener(),
);
}
public function getRoutes() {
return array(
'/daemon/' => array(
'' => 'PhabricatorDaemonConsoleController',
'task/(?P<id>[1-9]\d*)/' => 'PhabricatorWorkerTaskDetailController',
'log/' => array(
'' => 'PhabricatorDaemonLogListController',
'(?P<id>[1-9]\d*)/' => 'PhabricatorDaemonLogViewController',
),
'event/(?P<id>[1-9]\d*)/' => 'PhabricatorDaemonLogEventViewController',
'bulk/' => array(
'(?:query/(?P<queryKey>[^/]+)/)?' =>
'PhabricatorDaemonBulkJobListController',
'monitor/(?P<id>\d+)/' =>
'PhabricatorDaemonBulkJobMonitorController',
'view/(?P<id>\d+)/' =>
'PhabricatorDaemonBulkJobViewController',
),
),
);
}
}
diff --git a/src/applications/dashboard/application/PhabricatorDashboardApplication.php b/src/applications/dashboard/application/PhabricatorDashboardApplication.php
index 0c7304a92b..9653256630 100644
--- a/src/applications/dashboard/application/PhabricatorDashboardApplication.php
+++ b/src/applications/dashboard/application/PhabricatorDashboardApplication.php
@@ -1,59 +1,59 @@
<?php
final class PhabricatorDashboardApplication extends PhabricatorApplication {
public function getName() {
return pht('Dashboards');
}
public function getBaseURI() {
return '/dashboard/';
}
public function getShortDescription() {
return pht('Create Custom Pages');
}
- public function getFontIcon() {
+ public function getIcon() {
return 'fa-dashboard';
}
public function getRoutes() {
return array(
'/W(?P<id>\d+)' => 'PhabricatorDashboardPanelViewController',
'/dashboard/' => array(
'(?:query/(?P<queryKey>[^/]+)/)?'
=> 'PhabricatorDashboardListController',
'view/(?P<id>\d+)/' => 'PhabricatorDashboardViewController',
'archive/(?P<id>\d+)/' => 'PhabricatorDashboardArchiveController',
'manage/(?P<id>\d+)/' => 'PhabricatorDashboardManageController',
'history/(?P<id>\d+)/' => 'PhabricatorDashboardHistoryController',
'create/' => 'PhabricatorDashboardEditController',
'copy/(?:(?P<id>\d+)/)?' => 'PhabricatorDashboardCopyController',
'edit/(?:(?P<id>\d+)/)?' => 'PhabricatorDashboardEditController',
'install/(?P<id>\d+)/' => 'PhabricatorDashboardInstallController',
'uninstall/(?P<id>\d+)/' => 'PhabricatorDashboardUninstallController',
'addpanel/(?P<id>\d+)/' => 'PhabricatorDashboardAddPanelController',
'movepanel/(?P<id>\d+)/' => 'PhabricatorDashboardMovePanelController',
'removepanel/(?P<id>\d+)/'
=> 'PhabricatorDashboardRemovePanelController',
'panel/' => array(
'(?:query/(?P<queryKey>[^/]+)/)?'
=> 'PhabricatorDashboardPanelListController',
'create/' => 'PhabricatorDashboardPanelEditController',
'edit/(?:(?P<id>\d+)/)?' => 'PhabricatorDashboardPanelEditController',
'render/(?P<id>\d+)/' => 'PhabricatorDashboardPanelRenderController',
'archive/(?P<id>\d+)/'
=> 'PhabricatorDashboardPanelArchiveController',
),
),
);
}
public function getRemarkupRules() {
return array(
new PhabricatorDashboardRemarkupRule(),
);
}
}
diff --git a/src/applications/dashboard/controller/PhabricatorDashboardPanelListController.php b/src/applications/dashboard/controller/PhabricatorDashboardPanelListController.php
index 4136cad358..eaffdaa0d5 100644
--- a/src/applications/dashboard/controller/PhabricatorDashboardPanelListController.php
+++ b/src/applications/dashboard/controller/PhabricatorDashboardPanelListController.php
@@ -1,70 +1,70 @@
<?php
final class PhabricatorDashboardPanelListController
extends PhabricatorDashboardController {
private $queryKey;
public function shouldAllowPublic() {
return true;
}
public function handleRequest(AphrontRequest $request) {
$query_key = $request->getURIData('queryKey');
$controller = id(new PhabricatorApplicationSearchController())
->setQueryKey($query_key)
->setSearchEngine(new PhabricatorDashboardPanelSearchEngine())
->setNavigation($this->buildSideNavView());
return $this->delegateToController($controller);
}
public function buildSideNavView() {
$user = $this->getRequest()->getUser();
$nav = new AphrontSideNavFilterView();
$nav->setBaseURI(new PhutilURI($this->getApplicationURI()));
id(new PhabricatorDashboardPanelSearchEngine())
->setViewer($user)
->addNavigationItems($nav->getMenu());
$nav->selectFilter(null);
return $nav;
}
protected function buildApplicationCrumbs() {
$crumbs = parent::buildApplicationCrumbs();
$crumbs->addTextCrumb(pht('Panels'), $this->getApplicationURI().'panel/');
$crumbs->addAction(
id(new PHUIListItemView())
->setIcon('fa-plus-square')
->setName(pht('Create Panel'))
->setHref($this->getApplicationURI().'panel/create/'));
return $crumbs;
}
protected function getNewUserBody() {
$create_button = id(new PHUIButtonView())
->setTag('a')
->setText(pht('Create a Panel'))
->setHref('/dashboard/panel/create/')
->setColor(PHUIButtonView::GREEN);
- $icon = $this->getApplication()->getFontIcon();
+ $icon = $this->getApplication()->getIcon();
$app_name = $this->getApplication()->getName();
$view = id(new PHUIBigInfoView())
->setIcon($icon)
->setTitle(pht('Welcome to %s', $app_name))
->setDescription(
pht('Build individual panels to display on your homepage dashboard.'))
->addAction($create_button);
return $view;
}
}
diff --git a/src/applications/dashboard/query/PhabricatorDashboardSearchEngine.php b/src/applications/dashboard/query/PhabricatorDashboardSearchEngine.php
index 83557b141a..26c71c1bab 100644
--- a/src/applications/dashboard/query/PhabricatorDashboardSearchEngine.php
+++ b/src/applications/dashboard/query/PhabricatorDashboardSearchEngine.php
@@ -1,197 +1,197 @@
<?php
final class PhabricatorDashboardSearchEngine
extends PhabricatorApplicationSearchEngine {
public function getResultTypeDescription() {
return pht('Dashboards');
}
public function getApplicationClassName() {
return 'PhabricatorDashboardApplication';
}
public function newQuery() {
return id(new PhabricatorDashboardQuery())
->needProjects(true);
}
protected function buildCustomSearchFields() {
return array(
id(new PhabricatorSearchCheckboxesField())
->setKey('statuses')
->setLabel(pht('Status'))
->setOptions(PhabricatorDashboard::getStatusNameMap()),
);
}
protected function getURI($path) {
return '/dashboard/'.$path;
}
protected function getBuiltinQueryNames() {
return array(
'open' => pht('Active Dashboards'),
'all' => pht('All Dashboards'),
);
}
public function buildSavedQueryFromBuiltin($query_key) {
$query = $this->newSavedQuery();
$query->setQueryKey($query_key);
switch ($query_key) {
case 'all':
return $query;
case 'open':
return $query->setParameter(
'statuses',
array(
PhabricatorDashboard::STATUS_ACTIVE,
));
}
return parent::buildSavedQueryFromBuiltin($query_key);
}
protected function buildQueryFromParameters(array $map) {
$query = $this->newQuery();
if ($map['statuses']) {
$query->withStatuses($map['statuses']);
}
return $query;
}
protected function renderResultList(
array $dashboards,
PhabricatorSavedQuery $query,
array $handles) {
$dashboards = mpull($dashboards, null, 'getPHID');
$viewer = $this->requireViewer();
if ($dashboards) {
$installs = id(new PhabricatorDashboardInstall())
->loadAllWhere(
'objectPHID IN (%Ls) AND dashboardPHID IN (%Ls)',
array(
PhabricatorHomeApplication::DASHBOARD_DEFAULT,
$viewer->getPHID(),
),
array_keys($dashboards));
$installs = mpull($installs, null, 'getDashboardPHID');
} else {
$installs = array();
}
$proj_phids = array();
foreach ($dashboards as $dashboard) {
foreach ($dashboard->getProjectPHIDs() as $project_phid) {
$proj_phids[] = $project_phid;
}
}
$proj_handles = id(new PhabricatorHandleQuery())
->setViewer($viewer)
->withPHIDs($proj_phids)
->execute();
$list = new PHUIObjectItemListView();
$list->setUser($viewer);
$list->initBehavior('phabricator-tooltips', array());
$list->requireResource('aphront-tooltip-css');
foreach ($dashboards as $dashboard_phid => $dashboard) {
$id = $dashboard->getID();
$item = id(new PHUIObjectItemView())
->setObjectName(pht('Dashboard %d', $id))
->setHeader($dashboard->getName())
->setHref($this->getApplicationURI("view/{$id}/"))
->setObject($dashboard);
if (isset($installs[$dashboard_phid])) {
$install = $installs[$dashboard_phid];
if ($install->getObjectPHID() == $viewer->getPHID()) {
$attrs = array(
'tip' => pht(
'This dashboard is installed to your personal homepage.'),
);
$item->addIcon('fa-user', pht('Installed'), $attrs);
} else {
$attrs = array(
'tip' => pht(
'This dashboard is the default homepage for all users.'),
);
$item->addIcon('fa-globe', pht('Installed'), $attrs);
}
}
$project_handles = array_select_keys(
$proj_handles,
$dashboard->getProjectPHIDs());
$item->addAttribute(
id(new PHUIHandleTagListView())
->setLimit(4)
->setNoDataString(pht('No Projects'))
->setSlim(true)
->setHandles($project_handles));
if ($dashboard->isArchived()) {
$item->setDisabled(true);
}
$can_edit = PhabricatorPolicyFilter::hasCapability(
$viewer,
$dashboard,
PhabricatorPolicyCapability::CAN_EDIT);
$href_view = $this->getApplicationURI("manage/{$id}/");
$item->addAction(
id(new PHUIListItemView())
->setName(pht('Manage'))
->setIcon('fa-th')
->setHref($href_view));
$href_edit = $this->getApplicationURI("edit/{$id}/");
$item->addAction(
id(new PHUIListItemView())
->setName(pht('Edit'))
->setIcon('fa-pencil')
->setHref($href_edit)
->setDisabled(!$can_edit));
$list->addItem($item);
}
$result = new PhabricatorApplicationSearchResultView();
$result->setObjectList($list);
$result->setNoDataString(pht('No dashboards found.'));
return $result;
}
protected function getNewUserBody() {
$create_button = id(new PHUIButtonView())
->setTag('a')
->setText(pht('Create a Dashboard'))
->setHref('/dashboard/create/')
->setColor(PHUIButtonView::GREEN);
- $icon = $this->getApplication()->getFontIcon();
+ $icon = $this->getApplication()->getIcon();
$app_name = $this->getApplication()->getName();
$view = id(new PHUIBigInfoView())
->setIcon($icon)
->setTitle(pht('Welcome to %s', $app_name))
->setDescription(
pht('Customize your homepage with different panels and '.
'search queries.'))
->addAction($create_button);
return $view;
}
}
diff --git a/src/applications/differential/application/PhabricatorDifferentialApplication.php b/src/applications/differential/application/PhabricatorDifferentialApplication.php
index a3074d3e31..787bf52788 100644
--- a/src/applications/differential/application/PhabricatorDifferentialApplication.php
+++ b/src/applications/differential/application/PhabricatorDifferentialApplication.php
@@ -1,217 +1,217 @@
<?php
final class PhabricatorDifferentialApplication extends PhabricatorApplication {
public function getBaseURI() {
return '/differential/';
}
public function getName() {
return pht('Differential');
}
public function getShortDescription() {
return pht('Review Code');
}
- public function getFontIcon() {
+ public function getIcon() {
return 'fa-cog';
}
public function isPinnedByDefault(PhabricatorUser $viewer) {
return true;
}
public function getHelpDocumentationArticles(PhabricatorUser $viewer) {
return array(
array(
'name' => pht('Differential User Guide'),
'href' => PhabricatorEnv::getDoclink('Differential User Guide'),
),
);
}
public function getFactObjectsForAnalysis() {
return array(
new DifferentialRevision(),
);
}
public function getTitleGlyph() {
return "\xE2\x9A\x99";
}
public function getEventListeners() {
return array(
new DifferentialActionMenuEventListener(),
new DifferentialLandingActionMenuEventListener(),
);
}
public function getOverview() {
return pht(
'Differential is a **code review application** which allows '.
'engineers to review, discuss and approve changes to software.');
}
public function getRoutes() {
return array(
'/D(?P<id>[1-9]\d*)' => 'DifferentialRevisionViewController',
'/differential/' => array(
'(?:query/(?P<queryKey>[^/]+)/)?'
=> 'DifferentialRevisionListController',
'diff/' => array(
'(?P<id>[1-9]\d*)/' => 'DifferentialDiffViewController',
'create/' => 'DifferentialDiffCreateController',
),
'changeset/' => 'DifferentialChangesetViewController',
'revision/' => array(
'edit/(?:(?P<id>[1-9]\d*)/)?'
=> 'DifferentialRevisionEditController',
'land/(?:(?P<id>[1-9]\d*))/(?P<strategy>[^/]+)/'
=> 'DifferentialRevisionLandController',
'closedetails/(?P<phid>[^/]+)/'
=> 'DifferentialRevisionCloseDetailsController',
'update/(?P<revisionID>[1-9]\d*)/'
=> 'DifferentialDiffCreateController',
'operation/(?P<id>[1-9]\d*)/'
=> 'DifferentialRevisionOperationController',
),
'comment/' => array(
'preview/(?P<id>[1-9]\d*)/' => 'DifferentialCommentPreviewController',
'save/(?P<id>[1-9]\d*)/' => 'DifferentialCommentSaveController',
'inline/' => array(
'preview/(?P<id>[1-9]\d*)/'
=> 'DifferentialInlineCommentPreviewController',
'edit/(?P<id>[1-9]\d*)/'
=> 'DifferentialInlineCommentEditController',
),
),
'preview/' => 'PhabricatorMarkupPreviewController',
),
);
}
public function getApplicationOrder() {
return 0.100;
}
public function getRemarkupRules() {
return array(
new DifferentialRemarkupRule(),
);
}
public function loadStatus(PhabricatorUser $user) {
$limit = self::MAX_STATUS_ITEMS;
$revisions = id(new DifferentialRevisionQuery())
->setViewer($user)
->withResponsibleUsers(array($user->getPHID()))
->withStatus(DifferentialRevisionQuery::STATUS_OPEN)
->needRelationships(true)
->setLimit($limit)
->execute();
$status = array();
if (count($revisions) >= $limit) {
$all_count = count($revisions);
$all_count_str = pht(
'%s+ Active Review(s)',
new PhutilNumber($limit - 1));
$type = PhabricatorApplicationStatusView::TYPE_WARNING;
$status[] = id(new PhabricatorApplicationStatusView())
->setType($type)
->setText($all_count_str)
->setCount($all_count);
} else {
list($blocking, $active, $waiting) =
DifferentialRevisionQuery::splitResponsible(
$revisions,
array($user->getPHID()));
$blocking = count($blocking);
$blocking_str = pht(
'%s Review(s) Blocking Others',
new PhutilNumber($blocking));
$type = PhabricatorApplicationStatusView::TYPE_NEEDS_ATTENTION;
$status[] = id(new PhabricatorApplicationStatusView())
->setType($type)
->setText($blocking_str)
->setCount($blocking);
$active = count($active);
$active_str = pht(
'%s Review(s) Need Attention',
new PhutilNumber($active));
$type = PhabricatorApplicationStatusView::TYPE_WARNING;
$status[] = id(new PhabricatorApplicationStatusView())
->setType($type)
->setText($active_str)
->setCount($active);
$waiting = count($waiting);
$waiting_str = pht(
'%s Review(s) Waiting on Others',
new PhutilNumber($waiting));
$type = PhabricatorApplicationStatusView::TYPE_INFO;
$status[] = id(new PhabricatorApplicationStatusView())
->setType($type)
->setText($waiting_str)
->setCount($waiting);
}
return $status;
}
public function supportsEmailIntegration() {
return true;
}
public function getAppEmailBlurb() {
return pht(
'Send email to these addresses to create revisions. The body of the '.
'message and / or one or more attachments should be the output of a '.
'"diff" command. %s',
phutil_tag(
'a',
array(
'href' => $this->getInboundEmailSupportLink(),
),
pht('Learn More')));
}
protected function getCustomCapabilities() {
return array(
DifferentialDefaultViewCapability::CAPABILITY => array(
'caption' => pht('Default view policy for newly created revisions.'),
'template' => DifferentialRevisionPHIDType::TYPECONST,
'capability' => PhabricatorPolicyCapability::CAN_VIEW,
),
);
}
public function getMailCommandObjects() {
return array(
'revision' => array(
'name' => pht('Email Commands: Revisions'),
'header' => pht('Interacting with Differential Revisions'),
'object' => new DifferentialRevision(),
'summary' => pht(
'This page documents the commands you can use to interact with '.
'revisions in Differential.'),
),
);
}
public function getApplicationSearchDocumentTypes() {
return array(
DifferentialRevisionPHIDType::TYPECONST,
);
}
}
diff --git a/src/applications/differential/config/PhabricatorDifferentialConfigOptions.php b/src/applications/differential/config/PhabricatorDifferentialConfigOptions.php
index dd864d523f..bd1aa99359 100644
--- a/src/applications/differential/config/PhabricatorDifferentialConfigOptions.php
+++ b/src/applications/differential/config/PhabricatorDifferentialConfigOptions.php
@@ -1,308 +1,308 @@
<?php
final class PhabricatorDifferentialConfigOptions
extends PhabricatorApplicationConfigOptions {
public function getName() {
return pht('Differential');
}
public function getDescription() {
return pht('Configure Differential code review.');
}
- public function getFontIcon() {
+ public function getIcon() {
return 'fa-cog';
}
public function getGroup() {
return 'apps';
}
public function getOptions() {
$caches_href = PhabricatorEnv::getDoclink('Managing Caches');
$custom_field_type = 'custom:PhabricatorCustomFieldConfigOptionType';
$fields = array(
new DifferentialNextStepField(),
new DifferentialTitleField(),
new DifferentialSummaryField(),
new DifferentialTestPlanField(),
new DifferentialAuthorField(),
new DifferentialReviewersField(),
new DifferentialProjectReviewersField(),
new DifferentialReviewedByField(),
new DifferentialSubscribersField(),
new DifferentialRepositoryField(),
new DifferentialProjectsField(),
new DifferentialViewPolicyField(),
new DifferentialEditPolicyField(),
new DifferentialDependsOnField(),
new DifferentialDependenciesField(),
new DifferentialManiphestTasksField(),
new DifferentialCommitsField(),
new DifferentialJIRAIssuesField(),
new DifferentialAsanaRepresentationField(),
new DifferentialChangesSinceLastUpdateField(),
new DifferentialBranchField(),
new DifferentialBlameRevisionField(),
new DifferentialPathField(),
new DifferentialHostField(),
new DifferentialLintField(),
new DifferentialUnitField(),
new DifferentialRevertPlanField(),
new DifferentialApplyPatchField(),
new DifferentialRevisionIDField(),
);
$default_fields = array();
foreach ($fields as $field) {
$default_fields[$field->getFieldKey()] = array(
'disabled' => $field->shouldDisableByDefault(),
);
}
return array(
$this->newOption(
'differential.fields',
$custom_field_type,
$default_fields)
->setCustomData(
id(new DifferentialRevision())->getCustomFieldBaseClass())
->setDescription(
pht(
"Select and reorder revision fields.\n\n".
"NOTE: This feature is under active development and subject ".
"to change.")),
$this->newOption(
'differential.whitespace-matters',
'list<regex>',
array(
'/\.py$/',
'/\.l?hs$/',
))
->setDescription(
pht(
"List of file regexps where whitespace is meaningful and should ".
"not use 'ignore-all' by default")),
$this->newOption('differential.require-test-plan-field', 'bool', true)
->setBoolOptions(
array(
pht("Require 'Test Plan' field"),
pht("Make 'Test Plan' field optional"),
))
->setSummary(pht('Require "Test Plan" field?'))
->setDescription(
pht(
"Differential has a required 'Test Plan' field by default. You ".
"can make it optional by setting this to false. You can also ".
"completely remove it above, if you prefer.")),
$this->newOption('differential.enable-email-accept', 'bool', false)
->setBoolOptions(
array(
pht('Enable Email "!accept" Action'),
pht('Disable Email "!accept" Action'),
))
->setSummary(pht('Enable or disable "!accept" action via email.'))
->setDescription(
pht(
'If inbound email is configured, users can interact with '.
'revisions by using "!actions" in email replies (for example, '.
'"!resign" or "!rethink"). However, by default, users may not '.
'"!accept" revisions via email: email authentication can be '.
'configured to be very weak, and email "!accept" is kind of '.
'sketchy and implies the revision may not actually be receiving '.
'thorough review. You can enable "!accept" by setting this '.
'option to true.')),
$this->newOption('differential.generated-paths', 'list<regex>', array())
->setSummary(pht('File regexps to treat as automatically generated.'))
->setDescription(
pht(
'List of file regexps that should be treated as if they are '.
'generated by an automatic process, and thus be hidden by '.
'default in Differential.'.
"\n\n".
'NOTE: This property is cached, so you will need to purge the '.
'cache after making changes if you want the new configuration '.
'to affect existing revisions. For instructions, see '.
'**[[ %s | Managing Caches ]]** in the documentation.',
$caches_href))
->addExample("/config\.h$/\n#(^|/)autobuilt/#", pht('Valid Setting')),
$this->newOption('differential.sticky-accept', 'bool', true)
->setBoolOptions(
array(
pht('Accepts persist across updates'),
pht('Accepts are reset by updates'),
))
->setSummary(
pht('Should "Accepted" revisions remain "Accepted" after updates?'))
->setDescription(
pht(
'Normally, when revisions that have been "Accepted" are updated, '.
'they remain "Accepted". This allows reviewers to suggest minor '.
'alterations when accepting, and encourages authors to update '.
'if they make minor changes in response to this feedback.'.
"\n\n".
'If you want updates to always require re-review, you can disable '.
'the "stickiness" of the "Accepted" status with this option. '.
'This may make the process for minor changes much more burdensome '.
'to both authors and reviewers.')),
$this->newOption('differential.allow-self-accept', 'bool', false)
->setBoolOptions(
array(
pht('Allow self-accept'),
pht('Disallow self-accept'),
))
->setSummary(pht('Allows users to accept their own revisions.'))
->setDescription(
pht(
"If you set this to true, users can accept their own revisions. ".
"This action is disabled by default because it's most likely not ".
"a behavior you want, but it proves useful if you are working ".
"alone on a project and want to make use of all of ".
"differential's features.")),
$this->newOption('differential.always-allow-close', 'bool', false)
->setBoolOptions(
array(
pht('Allow any user'),
pht('Restrict to submitter'),
))
->setSummary(pht('Allows any user to close accepted revisions.'))
->setDescription(
pht(
'If you set this to true, any user can close any revision so '.
'long as it has been accepted. This can be useful depending on '.
'your development model. For example, github-style pull requests '.
'where the reviewer is often the actual committer can benefit '.
'from turning this option to true. If false, only the submitter '.
'can close a revision.')),
$this->newOption('differential.always-allow-abandon', 'bool', false)
->setBoolOptions(
array(
pht('Allow any user'),
pht('Restrict to submitter'),
))
->setSummary(pht('Allows any user to abandon revisions.'))
->setDescription(
pht(
'If you set this to true, any user can abandon any revision. If '.
'false, only the submitter can abandon a revision.')),
$this->newOption('differential.allow-reopen', 'bool', false)
->setBoolOptions(
array(
pht('Enable reopen'),
pht('Disable reopen'),
))
->setSummary(pht('Allows any user to reopen a closed revision.'))
->setDescription(
pht(
'If you set this to true, any user can reopen a revision so '.
'long as it has been closed. This can be useful if a revision '.
'is accidentally closed or if a developer changes his or her '.
'mind after closing a revision. If it is false, reopening '.
'is not allowed.')),
$this->newOption('differential.close-on-accept', 'bool', false)
->setBoolOptions(
array(
pht('Treat Accepted Revisions as "Closed"'),
pht('Treat Accepted Revisions as "Open"'),
))
->setSummary(pht('Allows "Accepted" to act as a closed status.'))
->setDescription(
pht(
'Normally, Differential revisions remain on the dashboard when '.
'they are "Accepted", and the author then commits the changes '.
'to "Close" the revision and move it off the dashboard.'.
"\n\n".
'If you have an unusual workflow where Differential is used for '.
'post-commit review (normally called "Audit", elsewhere in '.
'Phabricator), you can set this flag to treat the "Accepted" '.
'state as a "Closed" state and end the review workflow early.'.
"\n\n".
'This sort of workflow is very unusual. Very few installs should '.
'need to change this option.')),
$this->newOption('differential.days-fresh', 'int', 1)
->setSummary(
pht(
"For how many business days should a revision be considered ".
"'fresh'?"))
->setDescription(
pht(
'Revisions newer than this number of days are marked as fresh in '.
'Action Required and Revisions Waiting on You views. Only work '.
'days (not weekends and holidays) are included. Set to 0 to '.
'disable this feature.')),
$this->newOption('differential.days-stale', 'int', 3)
->setSummary(
pht("After this many days, a revision will be considered 'stale'."))
->setDescription(
pht(
"Similar to `%s` but marks stale revisions. ".
"If the revision is even older than it is when marked as 'old'.",
'differential.days-fresh')),
$this->newOption(
'metamta.differential.subject-prefix',
'string',
'[Differential]')
->setDescription(pht('Subject prefix for Differential mail.')),
$this->newOption(
'metamta.differential.attach-patches',
'bool',
false)
->setBoolOptions(
array(
pht('Attach Patches'),
pht('Do Not Attach Patches'),
))
->setSummary(pht('Attach patches to email, as text attachments.'))
->setDescription(
pht(
'If you set this to true, Phabricator will attach patches to '.
'Differential mail (as text attachments). This will not work if '.
'you are using SendGrid as your mail adapter.')),
$this->newOption(
'metamta.differential.inline-patches',
'int',
0)
->setSummary(pht('Inline patches in email, as body text.'))
->setDescription(
pht(
"To include patches inline in email bodies, set this to a ".
"positive integer. Patches will be inlined if they are at most ".
"that many lines. For instance, a value of 100 means 'inline ".
"patches if they are no longer than 100 lines'. By default, ".
"patches are not inlined.")),
// TODO: Implement 'enum'? Options are 'unified' or 'git'.
$this->newOption(
'metamta.differential.patch-format',
'string',
'unified')
->setDescription(
pht("Format for inlined or attached patches: 'git' or 'unified'.")),
$this->newOption(
'metamta.differential.unified-comment-context',
'bool',
false)
->setBoolOptions(
array(
pht('Show context'),
pht('Do not show context'),
))
->setSummary(pht('Show diff context around inline comments in email.'))
->setDescription(
pht(
'Normally, inline comments in emails are shown with a file and '.
'line but without any diff context. Enabling this option adds '.
'diff context and the comment thread.')),
);
}
}
diff --git a/src/applications/differential/query/DifferentialRevisionSearchEngine.php b/src/applications/differential/query/DifferentialRevisionSearchEngine.php
index 60e16b58b9..002a5df180 100644
--- a/src/applications/differential/query/DifferentialRevisionSearchEngine.php
+++ b/src/applications/differential/query/DifferentialRevisionSearchEngine.php
@@ -1,364 +1,364 @@
<?php
final class DifferentialRevisionSearchEngine
extends PhabricatorApplicationSearchEngine {
public function getResultTypeDescription() {
return pht('Differential Revisions');
}
public function getApplicationClassName() {
return 'PhabricatorDifferentialApplication';
}
public function newQuery() {
return id(new DifferentialRevisionQuery())
->needFlags(true)
->needDrafts(true)
->needRelationships(true);
}
public function getPageSize(PhabricatorSavedQuery $saved) {
if ($saved->getQueryKey() == 'active') {
return 0xFFFF;
}
return parent::getPageSize($saved);
}
public function buildSavedQueryFromRequest(AphrontRequest $request) {
$saved = new PhabricatorSavedQuery();
$saved->setParameter(
'responsiblePHIDs',
$this->readUsersFromRequest($request, 'responsibles'));
$saved->setParameter(
'authorPHIDs',
$this->readUsersFromRequest($request, 'authors'));
$saved->setParameter(
'reviewerPHIDs',
$this->readUsersFromRequest(
$request,
'reviewers',
array(
PhabricatorProjectProjectPHIDType::TYPECONST,
)));
$saved->setParameter(
'subscriberPHIDs',
$this->readSubscribersFromRequest($request, 'subscribers'));
$saved->setParameter(
'repositoryPHIDs',
$request->getArr('repositories'));
$saved->setParameter(
'projects',
$this->readProjectsFromRequest($request, 'projects'));
$saved->setParameter(
'draft',
$request->getBool('draft'));
$saved->setParameter(
'order',
$request->getStr('order'));
$saved->setParameter(
'status',
$request->getStr('status'));
return $saved;
}
public function buildQueryFromSavedQuery(PhabricatorSavedQuery $saved) {
$query = id(new DifferentialRevisionQuery())
->needFlags(true)
->needDrafts(true)
->needRelationships(true);
$user_datasource = id(new PhabricatorPeopleUserFunctionDatasource())
->setViewer($this->requireViewer());
$responsible_phids = $saved->getParameter('responsiblePHIDs', array());
$responsible_phids = $user_datasource->evaluateTokens($responsible_phids);
if ($responsible_phids) {
$query->withResponsibleUsers($responsible_phids);
}
$this->setQueryProjects($query, $saved);
$author_phids = $saved->getParameter('authorPHIDs', array());
$author_phids = $user_datasource->evaluateTokens($author_phids);
if ($author_phids) {
$query->withAuthors($author_phids);
}
$reviewer_phids = $saved->getParameter('reviewerPHIDs', array());
if ($reviewer_phids) {
$query->withReviewers($reviewer_phids);
}
$sub_datasource = id(new PhabricatorMetaMTAMailableFunctionDatasource())
->setViewer($this->requireViewer());
$subscriber_phids = $saved->getParameter('subscriberPHIDs', array());
$subscriber_phids = $sub_datasource->evaluateTokens($subscriber_phids);
if ($subscriber_phids) {
$query->withCCs($subscriber_phids);
}
$repository_phids = $saved->getParameter('repositoryPHIDs', array());
if ($repository_phids) {
$query->withRepositoryPHIDs($repository_phids);
}
$draft = $saved->getParameter('draft', false);
if ($draft && $this->requireViewer()->isLoggedIn()) {
$query->withDraftRepliesByAuthors(
array($this->requireViewer()->getPHID()));
}
$status = $saved->getParameter('status');
if (idx($this->getStatusOptions(), $status)) {
$query->withStatus($status);
}
$order = $saved->getParameter('order');
if (idx($this->getOrderOptions(), $order)) {
$query->setOrder($order);
} else {
$query->setOrder(DifferentialRevisionQuery::ORDER_CREATED);
}
return $query;
}
public function buildSearchForm(
AphrontFormView $form,
PhabricatorSavedQuery $saved) {
$responsible_phids = $saved->getParameter('responsiblePHIDs', array());
$author_phids = $saved->getParameter('authorPHIDs', array());
$reviewer_phids = $saved->getParameter('reviewerPHIDs', array());
$subscriber_phids = $saved->getParameter('subscriberPHIDs', array());
$repository_phids = $saved->getParameter('repositoryPHIDs', array());
$only_draft = $saved->getParameter('draft', false);
$projects = $saved->getParameter('projects', array());
$form
->appendControl(
id(new AphrontFormTokenizerControl())
->setLabel(pht('Responsible Users'))
->setName('responsibles')
->setDatasource(new PhabricatorPeopleUserFunctionDatasource())
->setValue($responsible_phids))
->appendControl(
id(new AphrontFormTokenizerControl())
->setLabel(pht('Authors'))
->setName('authors')
->setDatasource(new PhabricatorPeopleUserFunctionDatasource())
->setValue($author_phids))
->appendControl(
id(new AphrontFormTokenizerControl())
->setLabel(pht('Reviewers'))
->setName('reviewers')
->setDatasource(new PhabricatorProjectOrUserDatasource())
->setValue($reviewer_phids))
->appendControl(
id(new AphrontFormTokenizerControl())
->setLabel(pht('Subscribers'))
->setName('subscribers')
->setDatasource(new PhabricatorMetaMTAMailableFunctionDatasource())
->setValue($subscriber_phids))
->appendControl(
id(new AphrontFormTokenizerControl())
->setLabel(pht('Repositories'))
->setName('repositories')
->setDatasource(new DiffusionRepositoryDatasource())
->setValue($repository_phids))
->appendControl(
id(new AphrontFormTokenizerControl())
->setLabel(pht('Projects'))
->setName('projects')
->setDatasource(new PhabricatorProjectLogicalDatasource())
->setValue($projects))
->appendChild(
id(new AphrontFormSelectControl())
->setLabel(pht('Status'))
->setName('status')
->setOptions($this->getStatusOptions())
->setValue($saved->getParameter('status')));
if ($this->requireViewer()->isLoggedIn()) {
$form
->appendChild(
id(new AphrontFormCheckboxControl())
->addCheckbox(
'draft',
1,
pht('Show only revisions with a draft comment.'),
$only_draft));
}
$form
->appendChild(
id(new AphrontFormSelectControl())
->setLabel(pht('Order'))
->setName('order')
->setOptions($this->getOrderOptions())
->setValue($saved->getParameter('order')));
}
protected function getURI($path) {
return '/differential/'.$path;
}
protected function getBuiltinQueryNames() {
$names = array();
if ($this->requireViewer()->isLoggedIn()) {
$names['active'] = pht('Active Revisions');
$names['authored'] = pht('Authored');
}
$names['all'] = pht('All Revisions');
return $names;
}
public function buildSavedQueryFromBuiltin($query_key) {
$query = $this->newSavedQuery();
$query->setQueryKey($query_key);
$viewer = $this->requireViewer();
switch ($query_key) {
case 'active':
return $query
->setParameter('responsiblePHIDs', array($viewer->getPHID()))
->setParameter('status', DifferentialRevisionQuery::STATUS_OPEN);
case 'authored':
return $query
->setParameter('authorPHIDs', array($viewer->getPHID()));
case 'all':
return $query;
}
return parent::buildSavedQueryFromBuiltin($query_key);
}
private function getStatusOptions() {
return array(
DifferentialRevisionQuery::STATUS_ANY => pht('All'),
DifferentialRevisionQuery::STATUS_OPEN => pht('Open'),
DifferentialRevisionQuery::STATUS_ACCEPTED => pht('Accepted'),
DifferentialRevisionQuery::STATUS_NEEDS_REVIEW => pht('Needs Review'),
DifferentialRevisionQuery::STATUS_NEEDS_REVISION => pht('Needs Revision'),
DifferentialRevisionQuery::STATUS_CLOSED => pht('Closed'),
DifferentialRevisionQuery::STATUS_ABANDONED => pht('Abandoned'),
);
}
private function getOrderOptions() {
return array(
DifferentialRevisionQuery::ORDER_CREATED => pht('Created'),
DifferentialRevisionQuery::ORDER_MODIFIED => pht('Updated'),
);
}
protected function renderResultList(
array $revisions,
PhabricatorSavedQuery $query,
array $handles) {
assert_instances_of($revisions, 'DifferentialRevision');
$viewer = $this->requireViewer();
$template = id(new DifferentialRevisionListView())
->setUser($viewer)
->setNoBox($this->isPanelContext());
$views = array();
if ($query->getQueryKey() == 'active') {
$split = DifferentialRevisionQuery::splitResponsible(
$revisions,
$query->getParameter('responsiblePHIDs'));
list($blocking, $active, $waiting) = $split;
$views[] = id(clone $template)
->setHeader(pht('Blocking Others'))
->setNoDataString(
pht('No revisions are blocked on your action.'))
->setHighlightAge(true)
->setRevisions($blocking)
->setHandles(array());
$views[] = id(clone $template)
->setHeader(pht('Action Required'))
->setNoDataString(
pht('No revisions require your action.'))
->setHighlightAge(true)
->setRevisions($active)
->setHandles(array());
$views[] = id(clone $template)
->setHeader(pht('Waiting on Others'))
->setNoDataString(
pht('You have no revisions waiting on others.'))
->setRevisions($waiting)
->setHandles(array());
} else {
$views[] = id(clone $template)
->setRevisions($revisions)
->setHandles(array());
}
$phids = array_mergev(mpull($views, 'getRequiredHandlePHIDs'));
if ($phids) {
$handles = id(new PhabricatorHandleQuery())
->setViewer($viewer)
->withPHIDs($phids)
->execute();
} else {
$handles = array();
}
foreach ($views as $view) {
$view->setHandles($handles);
}
if (count($views) == 1) {
// Reduce this to a PHUIObjectItemListView so we can get the free
// support from ApplicationSearch.
$list = head($views)->render();
} else {
$list = $views;
}
$result = new PhabricatorApplicationSearchResultView();
$result->setContent($list);
return $result;
}
protected function getNewUserBody() {
$create_button = id(new PHUIButtonView())
->setTag('a')
->setText(pht('Create a Diff'))
->setHref('/differential/diff/create/')
->setColor(PHUIButtonView::GREEN);
- $icon = $this->getApplication()->getFontIcon();
+ $icon = $this->getApplication()->getIcon();
$app_name = $this->getApplication()->getName();
$view = id(new PHUIBigInfoView())
->setIcon($icon)
->setTitle(pht('Welcome to %s', $app_name))
->setDescription(
pht('Pre-commit code review. Revisions that are waiting on your input '.
'will appear here.'))
->addAction($create_button);
return $view;
}
}
diff --git a/src/applications/diffusion/application/PhabricatorDiffusionApplication.php b/src/applications/diffusion/application/PhabricatorDiffusionApplication.php
index 0f809e9983..fa82b4e80f 100644
--- a/src/applications/diffusion/application/PhabricatorDiffusionApplication.php
+++ b/src/applications/diffusion/application/PhabricatorDiffusionApplication.php
@@ -1,182 +1,182 @@
<?php
final class PhabricatorDiffusionApplication extends PhabricatorApplication {
public function getName() {
return pht('Diffusion');
}
public function getShortDescription() {
return pht('Host and Browse Repositories');
}
public function getBaseURI() {
return '/diffusion/';
}
- public function getFontIcon() {
+ public function getIcon() {
return 'fa-code';
}
public function isPinnedByDefault(PhabricatorUser $viewer) {
return true;
}
public function getHelpDocumentationArticles(PhabricatorUser $viewer) {
return array(
array(
'name' => pht('Diffusion User Guide'),
'href' => PhabricatorEnv::getDoclink('Diffusion User Guide'),
),
);
}
public function getFactObjectsForAnalysis() {
return array(
new PhabricatorRepositoryCommit(),
);
}
public function getRemarkupRules() {
return array(
new DiffusionCommitRemarkupRule(),
new DiffusionRepositoryRemarkupRule(),
new DiffusionRepositoryByIDRemarkupRule(),
);
}
public function getRoutes() {
return array(
'/(?:'.
'r(?P<repositoryCallsign>[A-Z]+)'.
'|'.
'R(?P<repositoryID>[1-9]\d*):'.
')(?P<commit>[a-f0-9]+)'
=> 'DiffusionCommitController',
'/diffusion/' => array(
'(?:query/(?P<queryKey>[^/]+)/)?'
=> 'DiffusionRepositoryListController',
'new/' => 'DiffusionRepositoryNewController',
'(?P<edit>create)/' => 'DiffusionRepositoryCreateController',
'(?P<edit>import)/' => 'DiffusionRepositoryCreateController',
'pushlog/' => array(
'(?:query/(?P<queryKey>[^/]+)/)?' => 'DiffusionPushLogListController',
'view/(?P<id>\d+)/' => 'DiffusionPushEventViewController',
),
'(?P<repositoryCallsign>[A-Z]+)/' => array(
'' => 'DiffusionRepositoryController',
'repository/(?P<dblob>.*)' => 'DiffusionRepositoryController',
'change/(?P<dblob>.*)' => 'DiffusionChangeController',
'history/(?P<dblob>.*)' => 'DiffusionHistoryController',
'browse/(?P<dblob>.*)' => 'DiffusionBrowseController',
'lastmodified/(?P<dblob>.*)' => 'DiffusionLastModifiedController',
'diff/' => 'DiffusionDiffController',
'tags/(?P<dblob>.*)' => 'DiffusionTagListController',
'branches/(?P<dblob>.*)' => 'DiffusionBranchTableController',
'refs/(?P<dblob>.*)' => 'DiffusionRefTableController',
'lint/(?P<dblob>.*)' => 'DiffusionLintController',
'commit/(?P<commit>[a-z0-9]+)/branches/'
=> 'DiffusionCommitBranchesController',
'commit/(?P<commit>[a-z0-9]+)/tags/'
=> 'DiffusionCommitTagsController',
'commit/(?P<commit>[a-z0-9]+)/edit/'
=> 'DiffusionCommitEditController',
'edit/' => array(
'' => 'DiffusionRepositoryEditMainController',
'basic/' => 'DiffusionRepositoryEditBasicController',
'encoding/' => 'DiffusionRepositoryEditEncodingController',
'activate/' => 'DiffusionRepositoryEditActivateController',
'dangerous/' => 'DiffusionRepositoryEditDangerousController',
'branches/' => 'DiffusionRepositoryEditBranchesController',
'subversion/' => 'DiffusionRepositoryEditSubversionController',
'actions/' => 'DiffusionRepositoryEditActionsController',
'(?P<edit>remote)/' => 'DiffusionRepositoryCreateController',
'(?P<edit>policy)/' => 'DiffusionRepositoryCreateController',
'storage/' => 'DiffusionRepositoryEditStorageController',
'delete/' => 'DiffusionRepositoryEditDeleteController',
'hosting/' => 'DiffusionRepositoryEditHostingController',
'(?P<serve>serve)/' => 'DiffusionRepositoryEditHostingController',
'update/' => 'DiffusionRepositoryEditUpdateController',
'symbol/' => 'DiffusionRepositorySymbolsController',
'staging/' => 'DiffusionRepositoryEditStagingController',
'automation/' => 'DiffusionRepositoryEditAutomationController',
'testautomation/' => 'DiffusionRepositoryTestAutomationController',
),
'pathtree/(?P<dblob>.*)' => 'DiffusionPathTreeController',
'mirror/' => array(
'edit/(?:(?P<id>\d+)/)?' => 'DiffusionMirrorEditController',
'delete/(?P<id>\d+)/' => 'DiffusionMirrorDeleteController',
),
),
// NOTE: This must come after the rule above; it just gives us a
// catch-all for serving repositories over HTTP. We must accept
// requests without the trailing "/" because SVN commands don't
// necessarily include it.
'(?P<repositoryCallsign>[A-Z]+)(?:/.*)?' =>
'DiffusionRepositoryDefaultController',
'inline/' => array(
'edit/(?P<phid>[^/]+)/' => 'DiffusionInlineCommentController',
'preview/(?P<phid>[^/]+)/'
=> 'DiffusionInlineCommentPreviewController',
),
'services/' => array(
'path/' => array(
'complete/' => 'DiffusionPathCompleteController',
'validate/' => 'DiffusionPathValidateController',
),
),
'symbol/(?P<name>[^/]+)/' => 'DiffusionSymbolController',
'external/' => 'DiffusionExternalController',
'lint/' => 'DiffusionLintController',
),
);
}
public function getApplicationOrder() {
return 0.120;
}
protected function getCustomCapabilities() {
return array(
DiffusionDefaultViewCapability::CAPABILITY => array(
'template' => PhabricatorRepositoryRepositoryPHIDType::TYPECONST,
'capability' => PhabricatorPolicyCapability::CAN_VIEW,
),
DiffusionDefaultEditCapability::CAPABILITY => array(
'default' => PhabricatorPolicies::POLICY_ADMIN,
'template' => PhabricatorRepositoryRepositoryPHIDType::TYPECONST,
'capability' => PhabricatorPolicyCapability::CAN_EDIT,
),
DiffusionDefaultPushCapability::CAPABILITY => array(
'template' => PhabricatorRepositoryRepositoryPHIDType::TYPECONST,
),
DiffusionCreateRepositoriesCapability::CAPABILITY => array(
'default' => PhabricatorPolicies::POLICY_ADMIN,
),
);
}
public function getMailCommandObjects() {
return array(
'commit' => array(
'name' => pht('Email Commands: Commits'),
'header' => pht('Interacting with Commits'),
'object' => new PhabricatorRepositoryCommit(),
'summary' => pht(
'This page documents the commands you can use to interact with '.
'commits and audits in Diffusion.'),
),
);
}
public function getApplicationSearchDocumentTypes() {
return array(
PhabricatorRepositoryCommitPHIDType::TYPECONST,
);
}
}
diff --git a/src/applications/diffusion/config/PhabricatorDiffusionConfigOptions.php b/src/applications/diffusion/config/PhabricatorDiffusionConfigOptions.php
index 9c3d7eff81..50f761eabc 100644
--- a/src/applications/diffusion/config/PhabricatorDiffusionConfigOptions.php
+++ b/src/applications/diffusion/config/PhabricatorDiffusionConfigOptions.php
@@ -1,152 +1,152 @@
<?php
final class PhabricatorDiffusionConfigOptions
extends PhabricatorApplicationConfigOptions {
public function getName() {
return pht('Diffusion');
}
public function getDescription() {
return pht('Configure Diffusion repository browsing.');
}
- public function getFontIcon() {
+ public function getIcon() {
return 'fa-code';
}
public function getGroup() {
return 'apps';
}
public function getOptions() {
$custom_field_type = 'custom:PhabricatorCustomFieldConfigOptionType';
$fields = array(
new PhabricatorCommitRepositoryField(),
new PhabricatorCommitBranchesField(),
new PhabricatorCommitTagsField(),
new PhabricatorCommitMergedCommitsField(),
);
$default_fields = array();
foreach ($fields as $field) {
$default_fields[$field->getFieldKey()] = array(
'disabled' => $field->shouldDisableByDefault(),
);
}
return array(
$this->newOption(
'metamta.diffusion.subject-prefix',
'string',
'[Diffusion]')
->setDescription(pht('Subject prefix for Diffusion mail.')),
$this->newOption(
'metamta.diffusion.attach-patches',
'bool',
false)
->setBoolOptions(
array(
pht('Attach Patches'),
pht('Do Not Attach Patches'),
))
->setDescription(
pht(
'Set this to true if you want patches to be attached to commit '.
'notifications from Diffusion.')),
$this->newOption('metamta.diffusion.inline-patches', 'int', 0)
->setSummary(pht('Include patches in Diffusion mail as body text.'))
->setDescription(
pht(
'To include patches in Diffusion email bodies, set this to a '.
'positive integer. Patches will be inlined if they are at most '.
'that many lines. By default, patches are not inlined.')),
$this->newOption('metamta.diffusion.byte-limit', 'int', 1024 * 1024)
->setDescription(pht('Hard byte limit on including patches in email.')),
$this->newOption('metamta.diffusion.time-limit', 'int', 60)
->setDescription(pht('Hard time limit on generating patches.')),
$this->newOption(
'audit.can-author-close-audit',
'bool',
false)
->setBoolOptions(
array(
pht('Enable Closing Audits'),
pht('Disable Closing Audits'),
))
->setDescription(pht('Controls whether Author can Close Audits.')),
$this->newOption('bugtraq.url', 'string', null)
->addExample('https://bugs.php.net/%BUGID%', pht('PHP bugs'))
->addExample('/%BUGID%', pht('Local Maniphest URL'))
->setDescription(
pht(
'URL of external bug tracker used by Diffusion. %s will be '.
'substituted by the bug ID.',
'%BUGID%')),
$this->newOption('bugtraq.logregex', 'list<regex>', array())
->addExample(array('/\B#([1-9]\d*)\b/'), pht('Issue #123'))
->addExample(
array('/[Ii]ssues?:?(\s*,?\s*#\d+)+/', '/(\d+)/'),
pht('Issue #123, #456'))
->addExample(array('/(?<!#)\b(T[1-9]\d*)\b/'), pht('Task T123'))
->addExample('/[A-Z]{2,}-\d+/', pht('JIRA-1234'))
->setDescription(
pht(
'Regular expression to link external bug tracker. See '.
'http://tortoisesvn.net/docs/release/TortoiseSVN_en/'.
'tsvn-dug-bugtracker.html for further explanation.')),
$this->newOption('diffusion.allow-http-auth', 'bool', false)
->setBoolOptions(
array(
pht('Allow HTTP Basic Auth'),
pht('Disable HTTP Basic Auth'),
))
->setSummary(pht('Enable HTTP Basic Auth for repositories.'))
->setDescription(
pht(
"Phabricator can serve repositories over HTTP, using HTTP basic ".
"auth.\n\n".
"Because HTTP basic auth is less secure than SSH auth, it is ".
"disabled by default. You can enable it here if you'd like to use ".
"it anyway. There's nothing fundamentally insecure about it as ".
"long as Phabricator uses HTTPS, but it presents a much lower ".
"barrier to attackers than SSH does.\n\n".
"Consider using SSH for authenticated access to repositories ".
"instead of HTTP.")),
$this->newOption('diffusion.ssh-user', 'string', null)
->setLocked(true)
->setSummary(pht('Login username for SSH connections to repositories.'))
->setDescription(
pht(
'When constructing clone URIs to show to users, Diffusion will '.
'fill in this login username. If you have configured a VCS user '.
'like `git`, you should provide it here.')),
$this->newOption('diffusion.ssh-port', 'int', null)
->setLocked(true)
->setSummary(pht('Port for SSH connections to repositories.'))
->setDescription(
pht(
'When constructing clone URIs to show to users, Diffusion by '.
'default will not display a port assuming the default for your '.
'VCS. Explicitly declare when running on a non-standard port.')),
$this->newOption('diffusion.ssh-host', 'string', null)
->setLocked(true)
->setSummary(pht('Host for SSH connections to repositories.'))
->setDescription(
pht(
'If you accept Phabricator SSH traffic on a different host '.
'from web traffic (for example, if you use different SSH and '.
'web load balancers), you can set the SSH hostname here. This '.
'is an advanced option.')),
$this->newOption('diffusion.fields', $custom_field_type, $default_fields)
->setCustomData(
id(new PhabricatorRepositoryCommit())
->getCustomFieldBaseClass())
->setDescription(
pht('Select and reorder Diffusion fields.')),
);
}
}
diff --git a/src/applications/diviner/application/PhabricatorDivinerApplication.php b/src/applications/diviner/application/PhabricatorDivinerApplication.php
index 66a8eac63d..83ca5e0dac 100644
--- a/src/applications/diviner/application/PhabricatorDivinerApplication.php
+++ b/src/applications/diviner/application/PhabricatorDivinerApplication.php
@@ -1,83 +1,83 @@
<?php
final class PhabricatorDivinerApplication extends PhabricatorApplication {
public function getBaseURI() {
return '/diviner/';
}
- public function getFontIcon() {
+ public function getIcon() {
return 'fa-sun-o';
}
public function getName() {
return pht('Diviner');
}
public function getShortDescription() {
return pht('Documentation');
}
public function getHelpDocumentationArticles(PhabricatorUser $viewer) {
return array(
array(
'name' => pht('Diviner User Guide'),
'href' => PhabricatorEnv::getDoclink('Diviner User Guide'),
),
);
}
public function getTitleGlyph() {
return "\xE2\x97\x89";
}
public function getRoutes() {
return array(
'/diviner/' => array(
'' => 'DivinerMainController',
'query/((?<queryKey>[^/]+)/)?' => 'DivinerAtomListController',
'find/' => 'DivinerFindController',
),
'/book/(?P<book>[^/]+)/' => 'DivinerBookController',
'/book/(?P<book>[^/]+)/edit/' => 'DivinerBookEditController',
'/book/'.
'(?P<book>[^/]+)/'.
'(?P<type>[^/]+)/'.
'(?:(?P<context>[^/]+)/)?'.
'(?P<name>[^/]+)/'.
'(?:(?P<index>\d+)/)?' => 'DivinerAtomController',
);
}
public function getApplicationGroup() {
return self::GROUP_UTILITIES;
}
protected function getCustomCapabilities() {
return array(
DivinerDefaultViewCapability::CAPABILITY => array(
'template' => DivinerBookPHIDType::TYPECONST,
'capability' => PhabricatorPolicyCapability::CAN_VIEW,
),
DivinerDefaultEditCapability::CAPABILITY => array(
'default' => PhabricatorPolicies::POLICY_ADMIN,
'template' => DivinerBookPHIDType::TYPECONST,
'capability' => PhabricatorPolicyCapability::CAN_EDIT,
),
);
}
public function getRemarkupRules() {
return array(
new DivinerSymbolRemarkupRule(),
);
}
public function getApplicationSearchDocumentTypes() {
return array(
DivinerAtomPHIDType::TYPECONST,
DivinerBookPHIDType::TYPECONST,
);
}
}
diff --git a/src/applications/doorkeeper/application/PhabricatorDoorkeeperApplication.php b/src/applications/doorkeeper/application/PhabricatorDoorkeeperApplication.php
index b0e155a38e..6342dd18b3 100644
--- a/src/applications/doorkeeper/application/PhabricatorDoorkeeperApplication.php
+++ b/src/applications/doorkeeper/application/PhabricatorDoorkeeperApplication.php
@@ -1,40 +1,40 @@
<?php
final class PhabricatorDoorkeeperApplication extends PhabricatorApplication {
public function canUninstall() {
return false;
}
public function isLaunchable() {
return false;
}
public function getName() {
return pht('Doorkeeper');
}
- public function getFontIcon() {
+ public function getIcon() {
return 'fa-recycle';
}
public function getShortDescription() {
return pht('Connect to Other Software');
}
public function getRemarkupRules() {
return array(
new DoorkeeperAsanaRemarkupRule(),
new DoorkeeperJIRARemarkupRule(),
);
}
public function getRoutes() {
return array(
'/doorkeeper/' => array(
'tags/' => 'DoorkeeperTagsController',
),
);
}
}
diff --git a/src/applications/doorkeeper/option/PhabricatorAsanaConfigOptions.php b/src/applications/doorkeeper/option/PhabricatorAsanaConfigOptions.php
index e7f2ef85de..991392f484 100644
--- a/src/applications/doorkeeper/option/PhabricatorAsanaConfigOptions.php
+++ b/src/applications/doorkeeper/option/PhabricatorAsanaConfigOptions.php
@@ -1,164 +1,164 @@
<?php
final class PhabricatorAsanaConfigOptions
extends PhabricatorApplicationConfigOptions {
public function getName() {
return pht('Integration with Asana');
}
public function getDescription() {
return pht('Asana integration options.');
}
- public function getFontIcon() {
+ public function getIcon() {
return 'fa-exchange';
}
public function getGroup() {
return 'core';
}
public function getOptions() {
return array(
$this->newOption('asana.workspace-id', 'string', null)
->setSummary(pht('Asana Workspace ID to publish into.'))
->setDescription(
pht(
'To enable synchronization into Asana, enter an Asana Workspace '.
'ID here.'.
"\n\n".
"NOTE: This feature is new and experimental.")),
$this->newOption('asana.project-ids', 'wild', null)
->setSummary(pht('Optional Asana projects to use as application tags.'))
->setDescription(
pht(
'When Phabricator creates tasks in Asana, it can add the tasks '.
'to Asana projects based on which application the corresponding '.
'object in Phabricator comes from. For example, you can add code '.
'reviews in Asana to a "Differential" project.'.
"\n\n".
'NOTE: This feature is new and experimental.')),
);
}
public function renderContextualDescription(
PhabricatorConfigOption $option,
AphrontRequest $request) {
switch ($option->getKey()) {
case 'asana.workspace-id':
break;
case 'asana.project-ids':
return $this->renderContextualProjectDescription($option, $request);
default:
return parent::renderContextualDescription($option, $request);
}
$viewer = $request->getUser();
$provider = PhabricatorAsanaAuthProvider::getAsanaProvider();
if (!$provider) {
return null;
}
$account = id(new PhabricatorExternalAccountQuery())
->setViewer($viewer)
->withUserPHIDs(array($viewer->getPHID()))
->withAccountTypes(array($provider->getProviderType()))
->withAccountDomains(array($provider->getProviderDomain()))
->requireCapabilities(
array(
PhabricatorPolicyCapability::CAN_VIEW,
PhabricatorPolicyCapability::CAN_EDIT,
))
->executeOne();
if (!$account) {
return null;
}
$token = $provider->getOAuthAccessToken($account);
if (!$token) {
return null;
}
try {
$workspaces = id(new PhutilAsanaFuture())
->setAccessToken($token)
->setRawAsanaQuery('workspaces')
->resolve();
} catch (Exception $ex) {
return null;
}
if (!$workspaces) {
return null;
}
$out = array();
$out[] = sprintf(
'| %s | %s |',
pht('Workspace ID'),
pht('Workspace Name'));
$out[] = '| ------------ | -------------- |';
foreach ($workspaces as $workspace) {
$out[] = sprintf('| `%s` | `%s` |', $workspace['id'], $workspace['name']);
}
$out = implode("\n", $out);
$out = pht(
"The Asana Workspaces your linked account has access to are:\n\n%s",
$out);
return PhabricatorMarkupEngine::renderOneObject(
id(new PhabricatorMarkupOneOff())->setContent($out),
'default',
$viewer);
}
private function renderContextualProjectDescription(
PhabricatorConfigOption $option,
AphrontRequest $request) {
$viewer = $request->getUser();
$publishers = id(new PhutilClassMapQuery())
->setAncestorClass('DoorkeeperFeedStoryPublisher')
->execute();
$out = array();
$out[] = pht(
'To specify projects to add tasks to, enter a JSON map with publisher '.
'class names as keys and a list of project IDs as values. For example, '.
'to put Differential tasks into Asana projects with IDs `123` and '.
'`456`, enter:'.
"\n\n".
" lang=txt\n".
" {\n".
" \"DifferentialDoorkeeperRevisionFeedStoryPublisher\" : [123, 456]\n".
" }\n");
$out[] = pht('Available publishers class names are:');
foreach ($publishers as $publisher) {
$out[] = ' - `'.get_class($publisher).'`';
}
$out[] = pht(
'You can find an Asana project ID by clicking the project in Asana and '.
'then examining the URL:'.
"\n\n".
" lang=txt\n".
" https://app.asana.com/0/12345678901234567890/111111111111111111\n".
" ^^^^^^^^^^^^^^^^^^^^\n".
" This is the ID to use.\n");
$out = implode("\n", $out);
return PhabricatorMarkupEngine::renderOneObject(
id(new PhabricatorMarkupOneOff())->setContent($out),
'default',
$viewer);
}
}
diff --git a/src/applications/drydock/application/PhabricatorDrydockApplication.php b/src/applications/drydock/application/PhabricatorDrydockApplication.php
index 6267c26f1e..d19e7cb78d 100644
--- a/src/applications/drydock/application/PhabricatorDrydockApplication.php
+++ b/src/applications/drydock/application/PhabricatorDrydockApplication.php
@@ -1,123 +1,123 @@
<?php
final class PhabricatorDrydockApplication extends PhabricatorApplication {
public function getBaseURI() {
return '/drydock/';
}
public function getName() {
return pht('Drydock');
}
public function getShortDescription() {
return pht('Allocate Software Resources');
}
- public function getFontIcon() {
+ public function getIcon() {
return 'fa-truck';
}
public function getTitleGlyph() {
return "\xE2\x98\x82";
}
public function getFlavorText() {
return pht('A nautical adventure.');
}
public function getApplicationGroup() {
return self::GROUP_UTILITIES;
}
public function isPrototype() {
return true;
}
public function getHelpDocumentationArticles(PhabricatorUser $viewer) {
return array(
array(
'name' => pht('Drydock User Guide'),
'href' => PhabricatorEnv::getDoclink('Drydock User Guide'),
),
);
}
public function getRoutes() {
return array(
'/drydock/' => array(
'' => 'DrydockConsoleController',
'(?P<type>blueprint)/' => array(
'(?:query/(?P<queryKey>[^/]+)/)?' => 'DrydockBlueprintListController',
'(?P<id>[1-9]\d*)/' => array(
'' => 'DrydockBlueprintViewController',
'(?P<action>disable|enable)/' =>
'DrydockBlueprintDisableController',
'resources/(?:query/(?P<queryKey>[^/]+)/)?' =>
'DrydockResourceListController',
'logs/(?:query/(?P<queryKey>[^/]+)/)?' =>
'DrydockLogListController',
'authorizations/(?:query/(?P<queryKey>[^/]+)/)?' =>
'DrydockAuthorizationListController',
),
'create/' => 'DrydockBlueprintCreateController',
'edit/(?:(?P<id>[1-9]\d*)/)?' => 'DrydockBlueprintEditController',
),
'(?P<type>resource)/' => array(
'(?:query/(?P<queryKey>[^/]+)/)?' => 'DrydockResourceListController',
'(?P<id>[1-9]\d*)/' => array(
'' => 'DrydockResourceViewController',
'release/' => 'DrydockResourceReleaseController',
'leases/(?:query/(?P<queryKey>[^/]+)/)?' =>
'DrydockLeaseListController',
'logs/(?:query/(?P<queryKey>[^/]+)/)?' =>
'DrydockLogListController',
),
),
'(?P<type>lease)/' => array(
'(?:query/(?P<queryKey>[^/]+)/)?' => 'DrydockLeaseListController',
'(?P<id>[1-9]\d*)/' => array(
'' => 'DrydockLeaseViewController',
'release/' => 'DrydockLeaseReleaseController',
'logs/(?:query/(?P<queryKey>[^/]+)/)?' =>
'DrydockLogListController',
),
),
'(?P<type>authorization)/' => array(
'(?P<id>[1-9]\d*)/' => array(
'' => 'DrydockAuthorizationViewController',
'(?P<action>authorize|decline)/' =>
'DrydockAuthorizationAuthorizeController',
),
),
'(?P<type>operation)/' => array(
'(?:query/(?P<queryKey>[^/]+)/)?'
=> 'DrydockRepositoryOperationListController',
'(?P<id>[1-9]\d*)/' => array(
'' => 'DrydockRepositoryOperationViewController',
'status/' => 'DrydockRepositoryOperationStatusController',
'dismiss/' => 'DrydockRepositoryOperationDismissController',
),
),
),
);
}
protected function getCustomCapabilities() {
return array(
DrydockDefaultViewCapability::CAPABILITY => array(
'template' => DrydockBlueprintPHIDType::TYPECONST,
'capability' => PhabricatorPolicyCapability::CAN_VIEW,
),
DrydockDefaultEditCapability::CAPABILITY => array(
'default' => PhabricatorPolicies::POLICY_ADMIN,
'template' => DrydockBlueprintPHIDType::TYPECONST,
'capability' => PhabricatorPolicyCapability::CAN_EDIT,
),
DrydockCreateBlueprintsCapability::CAPABILITY => array(
'default' => PhabricatorPolicies::POLICY_ADMIN,
),
);
}
}
diff --git a/src/applications/drydock/controller/DrydockConsoleController.php b/src/applications/drydock/controller/DrydockConsoleController.php
index 77346cea94..c6a8e25fd6 100644
--- a/src/applications/drydock/controller/DrydockConsoleController.php
+++ b/src/applications/drydock/controller/DrydockConsoleController.php
@@ -1,80 +1,80 @@
<?php
final class DrydockConsoleController extends DrydockController {
public function shouldAllowPublic() {
return true;
}
public function buildSideNavView() {
$nav = new AphrontSideNavFilterView();
$nav->setBaseURI(new PhutilURI($this->getApplicationURI()));
// These are only used on mobile.
$nav->addFilter('blueprint', pht('Blueprints'));
$nav->addFilter('resource', pht('Resources'));
$nav->addFilter('lease', pht('Leases'));
$nav->addFilter('operation', pht('Repository Operations'));
$nav->selectFilter(null);
return $nav;
}
public function handleRequest(AphrontRequest $request) {
$viewer = $request->getViewer();
$menu = id(new PHUIObjectItemListView())
->setUser($viewer);
$menu->addItem(
id(new PHUIObjectItemView())
->setHeader(pht('Blueprints'))
- ->setFontIcon('fa-map-o')
+ ->setIcon('fa-map-o')
->setHref($this->getApplicationURI('blueprint/'))
->addAttribute(
pht(
'Configure blueprints so Drydock can build resources, like '.
'hosts and working copies.')));
$menu->addItem(
id(new PHUIObjectItemView())
->setHeader(pht('Resources'))
- ->setFontIcon('fa-map')
+ ->setIcon('fa-map')
->setHref($this->getApplicationURI('resource/'))
->addAttribute(
pht('View and manage resources Drydock has built, like hosts.')));
$menu->addItem(
id(new PHUIObjectItemView())
->setHeader(pht('Leases'))
- ->setFontIcon('fa-link')
+ ->setIcon('fa-link')
->setHref($this->getApplicationURI('lease/'))
->addAttribute(pht('Manage leases on resources.')));
$menu->addItem(
id(new PHUIObjectItemView())
->setHeader(pht('Repository Operations'))
- ->setFontIcon('fa-fighter-jet')
+ ->setIcon('fa-fighter-jet')
->setHref($this->getApplicationURI('operation/'))
->addAttribute(pht('Review the repository operation queue.')));
$crumbs = $this->buildApplicationCrumbs();
$crumbs->addTextCrumb(pht('Console'));
$box = id(new PHUIObjectBoxView())
->setHeaderText(pht('Drydock Console'))
->setObjectList($menu);
return $this->buildApplicationPage(
array(
$crumbs,
$box,
),
array(
'title' => pht('Drydock Console'),
));
}
}
diff --git a/src/applications/fact/application/PhabricatorFactApplication.php b/src/applications/fact/application/PhabricatorFactApplication.php
index 5967778c71..305ed3abc9 100644
--- a/src/applications/fact/application/PhabricatorFactApplication.php
+++ b/src/applications/fact/application/PhabricatorFactApplication.php
@@ -1,38 +1,38 @@
<?php
final class PhabricatorFactApplication extends PhabricatorApplication {
public function getShortDescription() {
return pht('Chart and Analyze Data');
}
public function getName() {
return pht('Facts');
}
public function getBaseURI() {
return '/fact/';
}
- public function getFontIcon() {
+ public function getIcon() {
return 'fa-line-chart';
}
public function getApplicationGroup() {
return self::GROUP_UTILITIES;
}
public function isPrototype() {
return true;
}
public function getRoutes() {
return array(
'/fact/' => array(
'' => 'PhabricatorFactHomeController',
'chart/' => 'PhabricatorFactChartController',
),
);
}
}
diff --git a/src/applications/feed/application/PhabricatorFeedApplication.php b/src/applications/feed/application/PhabricatorFeedApplication.php
index ac8c21cda2..f24ff76fe4 100644
--- a/src/applications/feed/application/PhabricatorFeedApplication.php
+++ b/src/applications/feed/application/PhabricatorFeedApplication.php
@@ -1,34 +1,34 @@
<?php
final class PhabricatorFeedApplication extends PhabricatorApplication {
public function getBaseURI() {
return '/feed/';
}
public function getName() {
return pht('Feed');
}
public function getShortDescription() {
return pht('Review Recent Activity');
}
- public function getFontIcon() {
+ public function getIcon() {
return 'fa-newspaper-o';
}
public function canUninstall() {
return false;
}
public function getRoutes() {
return array(
'/feed/' => array(
'(?P<id>\d+)/' => 'PhabricatorFeedDetailController',
'(?:query/(?P<queryKey>[^/]+)/)?' => 'PhabricatorFeedListController',
),
);
}
}
diff --git a/src/applications/feed/config/PhabricatorFeedConfigOptions.php b/src/applications/feed/config/PhabricatorFeedConfigOptions.php
index 5e6926f357..4b6612f931 100644
--- a/src/applications/feed/config/PhabricatorFeedConfigOptions.php
+++ b/src/applications/feed/config/PhabricatorFeedConfigOptions.php
@@ -1,42 +1,42 @@
<?php
final class PhabricatorFeedConfigOptions
extends PhabricatorApplicationConfigOptions {
public function getName() {
return pht('Feed');
}
public function getDescription() {
return pht('Feed options.');
}
- public function getFontIcon() {
+ public function getIcon() {
return 'fa-newspaper-o';
}
public function getGroup() {
return 'apps';
}
public function getOptions() {
return array(
$this->newOption('feed.http-hooks', 'list<string>', array())
->setLocked(true)
->setSummary(pht('POST notifications of feed events.'))
->setDescription(
pht(
"If you set this to a list of HTTP URIs, when a feed story is ".
"published a task will be created for each URI that posts the ".
"story data to the URI. Daemons automagically retry failures 100 ".
"times, waiting `\$fail_count * 60s` between each subsequent ".
"failure. Be sure to keep the daemon console (`%s`) open ".
"while developing and testing your end points. You may need to".
"restart your daemons to start sending HTTP requests.\n\n".
"NOTE: URIs are not validated, the URI must return HTTP status ".
"200 within 30 seconds, and no permission checks are performed.",
'/daemon/')),
);
}
}
diff --git a/src/applications/files/application/PhabricatorFilesApplication.php b/src/applications/files/application/PhabricatorFilesApplication.php
index 7447ed728d..4cdcd76041 100644
--- a/src/applications/files/application/PhabricatorFilesApplication.php
+++ b/src/applications/files/application/PhabricatorFilesApplication.php
@@ -1,130 +1,130 @@
<?php
final class PhabricatorFilesApplication extends PhabricatorApplication {
public function getBaseURI() {
return '/file/';
}
public function getName() {
return pht('Files');
}
public function getShortDescription() {
return pht('Store and Share Files');
}
- public function getFontIcon() {
+ public function getIcon() {
return 'fa-file';
}
public function getTitleGlyph() {
return "\xE2\x87\xAA";
}
public function getFlavorText() {
return pht('Blob store for Pokemon pictures.');
}
public function getApplicationGroup() {
return self::GROUP_UTILITIES;
}
public function canUninstall() {
return false;
}
public function getRemarkupRules() {
return array(
new PhabricatorEmbedFileRemarkupRule(),
);
}
public function supportsEmailIntegration() {
return true;
}
public function getAppEmailBlurb() {
return pht(
'Send emails with file attachments to these addresses to upload '.
'files. %s',
phutil_tag(
'a',
array(
'href' => $this->getInboundEmailSupportLink(),
),
pht('Learn More')));
}
protected function getCustomCapabilities() {
return array(
FilesDefaultViewCapability::CAPABILITY => array(
'caption' => pht('Default view policy for newly created files.'),
'template' => PhabricatorFileFilePHIDType::TYPECONST,
'capability' => PhabricatorPolicyCapability::CAN_VIEW,
),
);
}
public function getRoutes() {
return array(
'/F(?P<id>[1-9]\d*)' => 'PhabricatorFileInfoController',
'/file/' => array(
'(query/(?P<queryKey>[^/]+)/)?' => 'PhabricatorFileListController',
'upload/' => 'PhabricatorFileUploadController',
'dropupload/' => 'PhabricatorFileDropUploadController',
'compose/' => 'PhabricatorFileComposeController',
'comment/(?P<id>[1-9]\d*)/' => 'PhabricatorFileCommentController',
'delete/(?P<id>[1-9]\d*)/' => 'PhabricatorFileDeleteController',
'edit/(?P<id>[1-9]\d*)/' => 'PhabricatorFileEditController',
'info/(?P<phid>[^/]+)/' => 'PhabricatorFileInfoController',
'proxy/' => 'PhabricatorFileProxyController',
'transforms/(?P<id>[1-9]\d*)/' =>
'PhabricatorFileTransformListController',
'uploaddialog/' => 'PhabricatorFileUploadDialogController',
'download/(?P<phid>[^/]+)/' => 'PhabricatorFileDialogController',
'iconset/(?P<key>[^/]+)/' => array(
'select/' => 'PhabricatorFileIconSetSelectController',
),
) + $this->getResourceSubroutes(),
);
}
public function getResourceRoutes() {
return array(
'/file/' => $this->getResourceSubroutes(),
);
}
private function getResourceSubroutes() {
return array(
'data/'.
'(?:@(?P<instance>[^/]+)/)?'.
'(?P<key>[^/]+)/'.
'(?P<phid>[^/]+)/'.
'(?:(?P<token>[^/]+)/)?'.
'.*'
=> 'PhabricatorFileDataController',
'xform/'.
'(?:@(?P<instance>[^/]+)/)?'.
'(?P<transform>[^/]+)/'.
'(?P<phid>[^/]+)/'.
'(?P<key>[^/]+)/'
=> 'PhabricatorFileTransformController',
);
}
public function getMailCommandObjects() {
return array(
'file' => array(
'name' => pht('Email Commands: Files'),
'header' => pht('Interacting with Files'),
'object' => new PhabricatorFile(),
'summary' => pht(
'This page documents the commands you can use to interact with '.
'files.'),
),
);
}
}
diff --git a/src/applications/files/config/PhabricatorFilesConfigOptions.php b/src/applications/files/config/PhabricatorFilesConfigOptions.php
index e9d899f658..43e12eddec 100644
--- a/src/applications/files/config/PhabricatorFilesConfigOptions.php
+++ b/src/applications/files/config/PhabricatorFilesConfigOptions.php
@@ -1,183 +1,183 @@
<?php
final class PhabricatorFilesConfigOptions
extends PhabricatorApplicationConfigOptions {
public function getName() {
return pht('Files');
}
public function getDescription() {
return pht('Configure files and file storage.');
}
- public function getFontIcon() {
+ public function getIcon() {
return 'fa-file';
}
public function getGroup() {
return 'apps';
}
public function getOptions() {
$viewable_default = array(
'image/jpeg' => 'image/jpeg',
'image/jpg' => 'image/jpg',
'image/png' => 'image/png',
'image/gif' => 'image/gif',
'text/plain' => 'text/plain; charset=utf-8',
'text/x-diff' => 'text/plain; charset=utf-8',
// ".ico" favicon files, which have mime type diversity. See:
// http://en.wikipedia.org/wiki/ICO_(file_format)#MIME_type
'image/x-ico' => 'image/x-icon',
'image/x-icon' => 'image/x-icon',
'image/vnd.microsoft.icon' => 'image/x-icon',
'audio/x-wav' => 'audio/x-wav',
'application/ogg' => 'application/ogg',
'audio/mpeg' => 'audio/mpeg',
);
$image_default = array(
'image/jpeg' => true,
'image/jpg' => true,
'image/png' => true,
'image/gif' => true,
'image/x-ico' => true,
'image/x-icon' => true,
'image/vnd.microsoft.icon' => true,
);
$audio_default = array(
'audio/x-wav' => true,
'application/ogg' => true,
'audio/mpeg' => true,
);
// largely lifted from http://en.wikipedia.org/wiki/Internet_media_type
$icon_default = array(
// audio file icon
'audio/basic' => 'fa-file-audio-o',
'audio/L24' => 'fa-file-audio-o',
'audio/mp4' => 'fa-file-audio-o',
'audio/mpeg' => 'fa-file-audio-o',
'audio/ogg' => 'fa-file-audio-o',
'audio/vorbis' => 'fa-file-audio-o',
'audio/vnd.rn-realaudio' => 'fa-file-audio-o',
'audio/vnd.wave' => 'fa-file-audio-o',
'audio/webm' => 'fa-file-audio-o',
// movie file icon
'video/mpeg' => 'fa-file-movie-o',
'video/mp4' => 'fa-file-movie-o',
'video/ogg' => 'fa-file-movie-o',
'video/quicktime' => 'fa-file-movie-o',
'video/webm' => 'fa-file-movie-o',
'video/x-matroska' => 'fa-file-movie-o',
'video/x-ms-wmv' => 'fa-file-movie-o',
'video/x-flv' => 'fa-file-movie-o',
// pdf file icon
'application/pdf' => 'fa-file-pdf-o',
// zip file icon
'application/zip' => 'fa-file-zip-o',
// msword icon
'application/msword' => 'fa-file-word-o',
// msexcel
'application/vnd.ms-excel' => 'fa-file-excel-o',
// mspowerpoint
'application/vnd.ms-powerpoint' => 'fa-file-powerpoint-o',
) + array_fill_keys(array_keys($image_default), 'fa-file-image-o');
// NOTE: These options are locked primarily because adding "text/plain"
// as an image MIME type increases SSRF vulnerability by allowing users
// to load text files from remote servers as "images" (see T6755 for
// discussion).
return array(
$this->newOption('files.viewable-mime-types', 'wild', $viewable_default)
->setLocked(true)
->setSummary(
pht('Configure which MIME types are viewable in the browser.'))
->setDescription(
pht(
"Configure which uploaded file types may be viewed directly ".
"in the browser. Other file types will be downloaded instead ".
"of displayed. This is mainly a usability consideration, since ".
"browsers tend to freak out when viewing enormous binary files.".
"\n\n".
"The keys in this map are viewable MIME types; the values are ".
"the MIME types they are delivered as when they are viewed in ".
"the browser.")),
$this->newOption('files.image-mime-types', 'set', $image_default)
->setLocked(true)
->setSummary(pht('Configure which MIME types are images.'))
->setDescription(
pht(
'List of MIME types which can be used as the `%s` for an `%s` tag.',
'src',
'<img />')),
$this->newOption('files.audio-mime-types', 'set', $audio_default)
->setLocked(true)
->setSummary(pht('Configure which MIME types are audio.'))
->setDescription(
pht(
'List of MIME types which can be used to render an `%s` tag.',
'<audio />')),
$this->newOption('files.icon-mime-types', 'wild', $icon_default)
->setLocked(true)
->setSummary(pht('Configure which MIME types map to which icons.'))
->setDescription(
pht(
'Map of MIME type to icon name. MIME types which can not be '.
'found default to icon `%s`.',
'doc_files')),
$this->newOption('storage.mysql-engine.max-size', 'int', 1000000)
->setSummary(
pht(
'Configure the largest file which will be put into the MySQL '.
'storage engine.')),
$this->newOption('storage.local-disk.path', 'string', null)
->setLocked(true)
->setSummary(pht('Local storage disk path.'))
->setDescription(
pht(
"Phabricator provides a local disk storage engine, which just ".
"writes files to some directory on local disk. The webserver ".
"must have read/write permissions on this directory. This is ".
"straightforward and suitable for most installs, but will not ".
"scale past one web frontend unless the path is actually an NFS ".
"mount, since you'll end up with some of the files written to ".
"each web frontend and no way for them to share. To use the ".
"local disk storage engine, specify the path to a directory ".
"here. To disable it, specify null.")),
$this->newOption('storage.s3.bucket', 'string', null)
->setSummary(pht('Amazon S3 bucket.'))
->setDescription(
pht(
"Set this to a valid Amazon S3 bucket to store files there. You ".
"must also configure S3 access keys in the 'Amazon Web Services' ".
"group.")),
$this->newOption(
'metamta.files.subject-prefix',
'string',
'[File]')
->setDescription(pht('Subject prefix for Files email.')),
$this->newOption('files.enable-imagemagick', 'bool', false)
->setBoolOptions(
array(
pht('Enable'),
pht('Disable'),
))
->setDescription(
pht(
'This option will use Imagemagick to rescale images, so animated '.
'GIFs can be thumbnailed and set as profile pictures. Imagemagick '.
'must be installed and the "%s" binary must be available to '.
'the webserver for this to work.',
'convert')),
);
}
}
diff --git a/src/applications/files/query/PhabricatorFileSearchEngine.php b/src/applications/files/query/PhabricatorFileSearchEngine.php
index 31e03f02b9..f2193d3beb 100644
--- a/src/applications/files/query/PhabricatorFileSearchEngine.php
+++ b/src/applications/files/query/PhabricatorFileSearchEngine.php
@@ -1,200 +1,200 @@
<?php
final class PhabricatorFileSearchEngine
extends PhabricatorApplicationSearchEngine {
public function getResultTypeDescription() {
return pht('Files');
}
public function getApplicationClassName() {
return 'PhabricatorFilesApplication';
}
public function newQuery() {
return new PhabricatorFileQuery();
}
protected function buildCustomSearchFields() {
return array(
id(new PhabricatorUsersSearchField())
->setKey('authorPHIDs')
->setAliases(array('author', 'authors'))
->setLabel(pht('Authors')),
id(new PhabricatorSearchThreeStateField())
->setKey('explicit')
->setLabel(pht('Upload Source'))
->setOptions(
pht('(Show All)'),
pht('Show Only Manually Uploaded Files'),
pht('Hide Manually Uploaded Files')),
id(new PhabricatorSearchDateField())
->setKey('createdStart')
->setLabel(pht('Created After')),
id(new PhabricatorSearchDateField())
->setKey('createdEnd')
->setLabel(pht('Created Before')),
);
}
protected function getDefaultFieldOrder() {
return array(
'...',
'createdStart',
'createdEnd',
);
}
protected function buildQueryFromParameters(array $map) {
$query = $this->newQuery();
if ($map['authorPHIDs']) {
$query->withAuthorPHIDs($map['authorPHIDs']);
}
if ($map['explicit'] !== null) {
$query->showOnlyExplicitUploads($map['explicit']);
}
if ($map['createdStart']) {
$query->withDateCreatedAfter($map['createdStart']);
}
if ($map['createdEnd']) {
$query->withDateCreatedBefore($map['createdEnd']);
}
return $query;
}
protected function getURI($path) {
return '/file/'.$path;
}
protected function getBuiltinQueryNames() {
$names = array();
if ($this->requireViewer()->isLoggedIn()) {
$names['authored'] = pht('Authored');
}
$names += array(
'all' => pht('All'),
);
return $names;
}
public function buildSavedQueryFromBuiltin($query_key) {
$query = $this->newSavedQuery();
$query->setQueryKey($query_key);
switch ($query_key) {
case 'all':
return $query;
case 'authored':
$author_phid = array($this->requireViewer()->getPHID());
return $query
->setParameter('authorPHIDs', $author_phid)
->setParameter('explicit', true);
}
return parent::buildSavedQueryFromBuiltin($query_key);
}
protected function getRequiredHandlePHIDsForResultList(
array $files,
PhabricatorSavedQuery $query) {
return mpull($files, 'getAuthorPHID');
}
protected function renderResultList(
array $files,
PhabricatorSavedQuery $query,
array $handles) {
assert_instances_of($files, 'PhabricatorFile');
$request = $this->getRequest();
if ($request) {
$highlighted_ids = $request->getStrList('h');
} else {
$highlighted_ids = array();
}
$viewer = $this->requireViewer();
$highlighted_ids = array_fill_keys($highlighted_ids, true);
$list_view = id(new PHUIObjectItemListView())
->setUser($viewer);
foreach ($files as $file) {
$id = $file->getID();
$phid = $file->getPHID();
$name = $file->getName();
$file_uri = $this->getApplicationURI("/info/{$phid}/");
$date_created = phabricator_date($file->getDateCreated(), $viewer);
$author_phid = $file->getAuthorPHID();
if ($author_phid) {
$author_link = $handles[$author_phid]->renderLink();
$uploaded = pht('Uploaded by %s on %s', $author_link, $date_created);
} else {
$uploaded = pht('Uploaded on %s', $date_created);
}
$item = id(new PHUIObjectItemView())
->setObject($file)
->setObjectName("F{$id}")
->setHeader($name)
->setHref($file_uri)
->addAttribute($uploaded)
->addIcon('none', phutil_format_bytes($file->getByteSize()));
$ttl = $file->getTTL();
if ($ttl !== null) {
$item->addIcon('blame', pht('Temporary'));
}
if ($file->getIsPartial()) {
$item->addIcon('fa-exclamation-triangle orange', pht('Partial'));
}
if (isset($highlighted_ids[$id])) {
$item->setEffect('highlighted');
}
$list_view->addItem($item);
}
$list_view->appendChild(id(new PhabricatorGlobalUploadTargetView())
->setUser($viewer));
$result = new PhabricatorApplicationSearchResultView();
$result->setContent($list_view);
return $result;
}
protected function getNewUserBody() {
$create_button = id(new PHUIButtonView())
->setTag('a')
->setText(pht('Upload a File'))
->setHref('/file/upload/')
->setColor(PHUIButtonView::GREEN);
- $icon = $this->getApplication()->getFontIcon();
+ $icon = $this->getApplication()->getIcon();
$app_name = $this->getApplication()->getName();
$view = id(new PHUIBigInfoView())
->setIcon($icon)
->setTitle(pht('Welcome to %s', $app_name))
->setDescription(
pht('Just a place for files.'))
->addAction($create_button);
return $view;
}
}
diff --git a/src/applications/flag/application/PhabricatorFlagsApplication.php b/src/applications/flag/application/PhabricatorFlagsApplication.php
index fad4c0bc8e..c7e2cb3b67 100644
--- a/src/applications/flag/application/PhabricatorFlagsApplication.php
+++ b/src/applications/flag/application/PhabricatorFlagsApplication.php
@@ -1,72 +1,72 @@
<?php
final class PhabricatorFlagsApplication extends PhabricatorApplication {
public function getName() {
return pht('Flags');
}
public function getShortDescription() {
return pht('Personal Bookmarks');
}
public function getBaseURI() {
return '/flag/';
}
- public function getFontIcon() {
+ public function getIcon() {
return 'fa-flag';
}
public function getEventListeners() {
return array(
new PhabricatorFlagsUIEventListener(),
);
}
public function getTitleGlyph() {
return "\xE2\x9A\x90";
}
public function getApplicationGroup() {
return self::GROUP_UTILITIES;
}
public function loadStatus(PhabricatorUser $user) {
$status = array();
$limit = self::MAX_STATUS_ITEMS;
$flags = id(new PhabricatorFlagQuery())
->setViewer($user)
->withOwnerPHIDs(array($user->getPHID()))
->setLimit(self::MAX_STATUS_ITEMS)
->execute();
$count = count($flags);
if ($count >= $limit) {
$count_str = pht('%s+ Flagged Object(s)', new PhutilNumber($limit - 1));
} else {
$count_str = pht('%s Flagged Object(s)', new PhutilNumber($count));
}
$type = PhabricatorApplicationStatusView::TYPE_WARNING;
$status[] = id(new PhabricatorApplicationStatusView())
->setType($type)
->setText($count_str)
->setCount($count);
return $status;
}
public function getRoutes() {
return array(
'/flag/' => array(
'(?:query/(?P<queryKey>[^/]+)/)?' => 'PhabricatorFlagListController',
'view/(?P<view>[^/]+)/' => 'PhabricatorFlagListController',
'edit/(?P<phid>[^/]+)/' => 'PhabricatorFlagEditController',
'delete/(?P<id>[1-9]\d*)/' => 'PhabricatorFlagDeleteController',
),
);
}
}
diff --git a/src/applications/fund/application/PhabricatorFundApplication.php b/src/applications/fund/application/PhabricatorFundApplication.php
index ed36cc783b..889baca20e 100644
--- a/src/applications/fund/application/PhabricatorFundApplication.php
+++ b/src/applications/fund/application/PhabricatorFundApplication.php
@@ -1,72 +1,72 @@
<?php
final class PhabricatorFundApplication extends PhabricatorApplication {
public function getName() {
return pht('Fund');
}
public function getBaseURI() {
return '/fund/';
}
public function getShortDescription() {
return pht('Donate');
}
- public function getFontIcon() {
+ public function getIcon() {
return 'fa-heart';
}
public function getTitleGlyph() {
return "\xE2\x99\xA5";
}
public function getApplicationGroup() {
return self::GROUP_UTILITIES;
}
public function isPrototype() {
return true;
}
public function getRemarkupRules() {
return array(
new FundInitiativeRemarkupRule(),
);
}
public function getRoutes() {
return array(
'/I(?P<id>[1-9]\d*)' => 'FundInitiativeViewController',
'/fund/' => array(
'(?:query/(?P<queryKey>[^/]+)/)?' => 'FundInitiativeListController',
'create/' => 'FundInitiativeEditController',
'edit/(?:(?P<id>\d+)/)?' => 'FundInitiativeEditController',
'close/(?P<id>\d+)/' => 'FundInitiativeCloseController',
'back/(?P<id>\d+)/' => 'FundInitiativeBackController',
'backers/(?:(?P<id>\d+)/)?(?:query/(?P<queryKey>[^/]+)/)?'
=> 'FundBackerListController',
),
);
}
protected function getCustomCapabilities() {
return array(
FundDefaultViewCapability::CAPABILITY => array(
'caption' => pht('Default view policy for newly created initiatives.'),
'tempate' => FundInitiativePHIDType::TYPECONST,
),
FundCreateInitiativesCapability::CAPABILITY => array(
'default' => PhabricatorPolicies::POLICY_ADMIN,
),
);
}
public function getApplicationSearchDocumentTypes() {
return array(
FundInitiativePHIDType::TYPECONST,
);
}
}
diff --git a/src/applications/harbormaster/application/PhabricatorHarbormasterApplication.php b/src/applications/harbormaster/application/PhabricatorHarbormasterApplication.php
index c9026e722f..97fa40dee8 100644
--- a/src/applications/harbormaster/application/PhabricatorHarbormasterApplication.php
+++ b/src/applications/harbormaster/application/PhabricatorHarbormasterApplication.php
@@ -1,114 +1,114 @@
<?php
final class PhabricatorHarbormasterApplication extends PhabricatorApplication {
public function getBaseURI() {
return '/harbormaster/';
}
public function getName() {
return pht('Harbormaster');
}
public function getShortDescription() {
return pht('Build/CI');
}
- public function getFontIcon() {
+ public function getIcon() {
return 'fa-ship';
}
public function getTitleGlyph() {
return "\xE2\x99\xBB";
}
public function getFlavorText() {
return pht('Ship Some Freight');
}
public function getApplicationGroup() {
return self::GROUP_UTILITIES;
}
public function getEventListeners() {
return array(
new HarbormasterUIEventListener(),
);
}
public function getRemarkupRules() {
return array(
new HarbormasterRemarkupRule(),
);
}
public function getHelpDocumentationArticles(PhabricatorUser $viewer) {
return array(
array(
'name' => pht('Harbormaster User Guide'),
'href' => PhabricatorEnv::getDoclink('Harbormaster User Guide'),
),
);
}
public function getRoutes() {
return array(
'/B(?P<id>[1-9]\d*)' => 'HarbormasterBuildableViewController',
'/harbormaster/' => array(
'(?:query/(?P<queryKey>[^/]+)/)?'
=> 'HarbormasterBuildableListController',
'step/' => array(
'add/(?:(?P<id>\d+)/)?' => 'HarbormasterStepAddController',
'new/(?P<plan>\d+)/(?P<class>[^/]+)/'
=> 'HarbormasterStepEditController',
'view/(?P<id>\d+)/' => 'HarbormasterStepViewController',
'edit/(?:(?P<id>\d+)/)?' => 'HarbormasterStepEditController',
'delete/(?:(?P<id>\d+)/)?' => 'HarbormasterStepDeleteController',
),
'buildable/' => array(
'(?P<id>\d+)/(?P<action>pause|resume|restart|abort)/'
=> 'HarbormasterBuildableActionController',
),
'build/' => array(
'(?P<id>\d+)/' => 'HarbormasterBuildViewController',
'(?P<action>pause|resume|restart|abort)/'.
'(?P<id>\d+)/(?:(?P<via>[^/]+)/)?'
=> 'HarbormasterBuildActionController',
),
'plan/' => array(
'(?:query/(?P<queryKey>[^/]+)/)?'
=> 'HarbormasterPlanListController',
'edit/(?:(?P<id>\d+)/)?' => 'HarbormasterPlanEditController',
'order/(?:(?P<id>\d+)/)?' => 'HarbormasterPlanOrderController',
'disable/(?P<id>\d+)/' => 'HarbormasterPlanDisableController',
'run/(?P<id>\d+)/' => 'HarbormasterPlanRunController',
'(?P<id>\d+)/' => 'HarbormasterPlanViewController',
),
'unit/' => array(
'(?P<id>\d+)/' => 'HarbormasterUnitMessagesController',
),
'lint/' => array(
'(?P<id>\d+)/' => 'HarbormasterLintMessagesController',
),
),
);
}
protected function getCustomCapabilities() {
return array(
HarbormasterCreatePlansCapability::CAPABILITY => array(
'default' => PhabricatorPolicies::POLICY_ADMIN,
),
HarbormasterBuildPlanDefaultViewCapability::CAPABILITY => array(
'template' => HarbormasterBuildPlanPHIDType::TYPECONST,
'capability' => PhabricatorPolicyCapability::CAN_VIEW,
),
HarbormasterBuildPlanDefaultEditCapability::CAPABILITY => array(
'template' => HarbormasterBuildPlanPHIDType::TYPECONST,
'capability' => PhabricatorPolicyCapability::CAN_EDIT,
'default' => PhabricatorPolicies::POLICY_ADMIN,
),
);
}
}
diff --git a/src/applications/harbormaster/config/PhabricatorHarbormasterConfigOptions.php b/src/applications/harbormaster/config/PhabricatorHarbormasterConfigOptions.php
index 0471984dbc..bab1e6de85 100644
--- a/src/applications/harbormaster/config/PhabricatorHarbormasterConfigOptions.php
+++ b/src/applications/harbormaster/config/PhabricatorHarbormasterConfigOptions.php
@@ -1,26 +1,26 @@
<?php
final class PhabricatorHarbormasterConfigOptions
extends PhabricatorApplicationConfigOptions {
public function getName() {
return pht('Harbormaster');
}
public function getDescription() {
return pht('Configure Harbormaster build engine.');
}
- public function getFontIcon() {
+ public function getIcon() {
return 'fa-ship';
}
public function getGroup() {
return 'apps';
}
public function getOptions() {
return array();
}
}
diff --git a/src/applications/herald/application/PhabricatorHeraldApplication.php b/src/applications/herald/application/PhabricatorHeraldApplication.php
index d6f0fd47b6..9160b0e9d9 100644
--- a/src/applications/herald/application/PhabricatorHeraldApplication.php
+++ b/src/applications/herald/application/PhabricatorHeraldApplication.php
@@ -1,78 +1,78 @@
<?php
final class PhabricatorHeraldApplication extends PhabricatorApplication {
public function getBaseURI() {
return '/herald/';
}
- public function getFontIcon() {
+ public function getIcon() {
return 'fa-bullhorn';
}
public function getName() {
return pht('Herald');
}
public function getShortDescription() {
return pht('Create Notification Rules');
}
public function getTitleGlyph() {
return "\xE2\x98\xBF";
}
public function getHelpDocumentationArticles(PhabricatorUser $viewer) {
return array(
array(
'name' => pht('Herald User Guide'),
'href' => PhabricatorEnv::getDoclink('Herald User Guide'),
),
);
}
public function getFlavorText() {
return pht('Watch for danger!');
}
public function getApplicationGroup() {
return self::GROUP_UTILITIES;
}
public function getRemarkupRules() {
return array(
new HeraldRemarkupRule(),
);
}
public function getRoutes() {
return array(
'/H(?P<id>[1-9]\d*)' => 'HeraldRuleViewController',
'/herald/' => array(
'(?:query/(?P<queryKey>[^/]+)/)?' => 'HeraldRuleListController',
'new/' => 'HeraldNewController',
'create/' => 'HeraldNewController',
'edit/(?:(?P<id>[1-9]\d*)/)?' => 'HeraldRuleController',
'disable/(?P<id>[1-9]\d*)/(?P<action>\w+)/'
=> 'HeraldDisableController',
'test/' => 'HeraldTestConsoleController',
'transcript/' => array(
'' => 'HeraldTranscriptListController',
'(?:query/(?P<queryKey>[^/]+)/)?' => 'HeraldTranscriptListController',
'(?P<id>[1-9]\d*)/'
=> 'HeraldTranscriptController',
),
),
);
}
protected function getCustomCapabilities() {
return array(
HeraldManageGlobalRulesCapability::CAPABILITY => array(
'caption' => pht('Global rules can bypass access controls.'),
'default' => PhabricatorPolicies::POLICY_ADMIN,
),
);
}
}
diff --git a/src/applications/herald/query/HeraldRuleSearchEngine.php b/src/applications/herald/query/HeraldRuleSearchEngine.php
index b71f8e6278..3b8196c13a 100644
--- a/src/applications/herald/query/HeraldRuleSearchEngine.php
+++ b/src/applications/herald/query/HeraldRuleSearchEngine.php
@@ -1,234 +1,234 @@
<?php
final class HeraldRuleSearchEngine extends PhabricatorApplicationSearchEngine {
public function getResultTypeDescription() {
return pht('Herald Rules');
}
public function getApplicationClassName() {
return 'PhabricatorHeraldApplication';
}
public function buildSavedQueryFromRequest(AphrontRequest $request) {
$saved = new PhabricatorSavedQuery();
$saved->setParameter(
'authorPHIDs',
$this->readUsersFromRequest($request, 'authors'));
$saved->setParameter('contentType', $request->getStr('contentType'));
$saved->setParameter('ruleType', $request->getStr('ruleType'));
$saved->setParameter(
'disabled',
$this->readBoolFromRequest($request, 'disabled'));
return $saved;
}
public function buildQueryFromSavedQuery(PhabricatorSavedQuery $saved) {
$query = id(new HeraldRuleQuery());
$author_phids = $saved->getParameter('authorPHIDs');
if ($author_phids) {
$query->withAuthorPHIDs($author_phids);
}
$content_type = $saved->getParameter('contentType');
$content_type = idx($this->getContentTypeValues(), $content_type);
if ($content_type) {
$query->withContentTypes(array($content_type));
}
$rule_type = $saved->getParameter('ruleType');
$rule_type = idx($this->getRuleTypeValues(), $rule_type);
if ($rule_type) {
$query->withRuleTypes(array($rule_type));
}
$disabled = $saved->getParameter('disabled');
if ($disabled !== null) {
$query->withDisabled($disabled);
}
return $query;
}
public function buildSearchForm(
AphrontFormView $form,
PhabricatorSavedQuery $saved_query) {
$author_phids = $saved_query->getParameter('authorPHIDs', array());
$content_type = $saved_query->getParameter('contentType');
$rule_type = $saved_query->getParameter('ruleType');
$form
->appendControl(
id(new AphrontFormTokenizerControl())
->setDatasource(new PhabricatorPeopleDatasource())
->setName('authors')
->setLabel(pht('Authors'))
->setValue($author_phids))
->appendChild(
id(new AphrontFormSelectControl())
->setName('contentType')
->setLabel(pht('Content Type'))
->setValue($content_type)
->setOptions($this->getContentTypeOptions()))
->appendChild(
id(new AphrontFormSelectControl())
->setName('ruleType')
->setLabel(pht('Rule Type'))
->setValue($rule_type)
->setOptions($this->getRuleTypeOptions()))
->appendChild(
id(new AphrontFormSelectControl())
->setName('disabled')
->setLabel(pht('Rule Status'))
->setValue($this->getBoolFromQuery($saved_query, 'disabled'))
->setOptions(
array(
'' => pht('Show Enabled and Disabled Rules'),
'false' => pht('Show Only Enabled Rules'),
'true' => pht('Show Only Disabled Rules'),
)));
}
protected function getURI($path) {
return '/herald/'.$path;
}
protected function getBuiltinQueryNames() {
$names = array();
if ($this->requireViewer()->isLoggedIn()) {
$names['authored'] = pht('Authored');
}
$names['active'] = pht('Active');
$names['all'] = pht('All');
return $names;
}
public function buildSavedQueryFromBuiltin($query_key) {
$query = $this->newSavedQuery();
$query->setQueryKey($query_key);
$viewer_phid = $this->requireViewer()->getPHID();
switch ($query_key) {
case 'all':
return $query;
case 'active':
return $query->setParameter('disabled', false);
case 'authored':
return $query
->setParameter('authorPHIDs', array($viewer_phid))
->setParameter('disabled', false);
}
return parent::buildSavedQueryFromBuiltin($query_key);
}
private function getContentTypeOptions() {
return array(
'' => pht('(All Content Types)'),
) + HeraldAdapter::getEnabledAdapterMap($this->requireViewer());
}
private function getContentTypeValues() {
return array_fuse(
array_keys(
HeraldAdapter::getEnabledAdapterMap($this->requireViewer())));
}
private function getRuleTypeOptions() {
return array(
'' => pht('(All Rule Types)'),
) + HeraldRuleTypeConfig::getRuleTypeMap();
}
private function getRuleTypeValues() {
return array_fuse(array_keys(HeraldRuleTypeConfig::getRuleTypeMap()));
}
protected function getRequiredHandlePHIDsForResultList(
array $rules,
PhabricatorSavedQuery $query) {
return mpull($rules, 'getAuthorPHID');
}
protected function renderResultList(
array $rules,
PhabricatorSavedQuery $query,
array $handles) {
assert_instances_of($rules, 'HeraldRule');
$viewer = $this->requireViewer();
$content_type_map = HeraldAdapter::getEnabledAdapterMap($viewer);
$list = id(new PHUIObjectItemListView())
->setUser($viewer);
foreach ($rules as $rule) {
$monogram = $rule->getMonogram();
$item = id(new PHUIObjectItemView())
->setObjectName($monogram)
->setHeader($rule->getName())
->setHref("/{$monogram}");
if ($rule->isPersonalRule()) {
$item->addIcon('fa-user', pht('Personal Rule'));
$item->addByline(
pht(
'Authored by %s',
$handles[$rule->getAuthorPHID()]->renderLink()));
} else if ($rule->isObjectRule()) {
$item->addIcon('fa-briefcase', pht('Object Rule'));
} else {
$item->addIcon('fa-globe', pht('Global Rule'));
}
if ($rule->getIsDisabled()) {
$item->setDisabled(true);
$item->addIcon('fa-lock grey', pht('Disabled'));
}
$content_type_name = idx($content_type_map, $rule->getContentType());
$item->addAttribute(pht('Affects: %s', $content_type_name));
$list->addItem($item);
}
$result = new PhabricatorApplicationSearchResultView();
$result->setObjectList($list);
$result->setNoDataString(pht('No rules found.'));
return $result;
}
protected function getNewUserBody() {
$create_button = id(new PHUIButtonView())
->setTag('a')
->setText(pht('Create Herald Rule'))
->setHref('/herald/create/')
->setColor(PHUIButtonView::GREEN);
- $icon = $this->getApplication()->getFontIcon();
+ $icon = $this->getApplication()->getIcon();
$app_name = $this->getApplication()->getName();
$view = id(new PHUIBigInfoView())
->setIcon($icon)
->setTitle(pht('Welcome to %s', $app_name))
->setDescription(
pht('A flexible rules engine that can notify and act on '.
'other actions such as tasks, diffs, and commits.'))
->addAction($create_button);
return $view;
}
}
diff --git a/src/applications/home/application/PhabricatorHomeApplication.php b/src/applications/home/application/PhabricatorHomeApplication.php
index c4fa1c646c..481ade105f 100644
--- a/src/applications/home/application/PhabricatorHomeApplication.php
+++ b/src/applications/home/application/PhabricatorHomeApplication.php
@@ -1,119 +1,119 @@
<?php
final class PhabricatorHomeApplication extends PhabricatorApplication {
const DASHBOARD_DEFAULT = 'dashboard:default';
public function getBaseURI() {
return '/home/';
}
public function getName() {
return pht('Home');
}
public function getShortDescription() {
return pht('Command Center');
}
- public function getFontIcon() {
+ public function getIcon() {
return 'fa-home';
}
public function getRoutes() {
return array(
'/' => 'PhabricatorHomeMainController',
'/(?P<only>home)/' => 'PhabricatorHomeMainController',
'/home/' => array(
'create/' => 'PhabricatorHomeQuickCreateController',
),
);
}
public function isLaunchable() {
return false;
}
public function getApplicationOrder() {
return 9;
}
public function buildMainMenuItems(
PhabricatorUser $user,
PhabricatorController $controller = null) {
$quick_create_items = $this->loadAllQuickCreateItems($user);
$items = array();
if ($user->isLoggedIn() &&
$user->isUserActivated() &&
$quick_create_items) {
$create_id = celerity_generate_unique_node_id();
Javelin::initBehavior(
'aphlict-dropdown',
array(
'bubbleID' => $create_id,
'dropdownID' => 'phabricator-quick-create-menu',
'local' => true,
'desktop' => true,
'right' => true,
));
$item = id(new PHUIListItemView())
->setName(pht('Create New...'))
->setIcon('fa-plus')
->addClass('core-menu-item')
->setHref('/home/create/')
->addSigil('quick-create-menu')
->setID($create_id)
->setAural(pht('Quick Create'))
->setOrder(300);
$items[] = $item;
}
return $items;
}
public function loadAllQuickCreateItems(PhabricatorUser $viewer) {
$applications = id(new PhabricatorApplicationQuery())
->setViewer($viewer)
->withInstalled(true)
->execute();
$items = array();
foreach ($applications as $application) {
$app_items = $application->getQuickCreateItems($viewer);
foreach ($app_items as $app_item) {
$items[] = $app_item;
}
}
return $items;
}
public function buildMainMenuExtraNodes(
PhabricatorUser $viewer,
PhabricatorController $controller = null) {
$items = $this->loadAllQuickCreateItems($viewer);
$view = null;
if ($items) {
$view = new PHUIListView();
foreach ($items as $item) {
$view->addMenuItem($item);
}
return phutil_tag(
'div',
array(
'id' => 'phabricator-quick-create-menu',
'class' => 'phabricator-main-menu-dropdown phui-list-sidenav',
'style' => 'display: none',
),
$view);
}
return $view;
}
}
diff --git a/src/applications/legalpad/application/PhabricatorLegalpadApplication.php b/src/applications/legalpad/application/PhabricatorLegalpadApplication.php
index e47049ef30..709fd7cc07 100644
--- a/src/applications/legalpad/application/PhabricatorLegalpadApplication.php
+++ b/src/applications/legalpad/application/PhabricatorLegalpadApplication.php
@@ -1,102 +1,102 @@
<?php
final class PhabricatorLegalpadApplication extends PhabricatorApplication {
public function getBaseURI() {
return '/legalpad/';
}
public function getName() {
return pht('Legalpad');
}
public function getShortDescription() {
return pht('Agreements and Signatures');
}
- public function getFontIcon() {
+ public function getIcon() {
return 'fa-gavel';
}
public function getTitleGlyph() {
return "\xC2\xA9";
}
public function getApplicationGroup() {
return self::GROUP_UTILITIES;
}
public function getRemarkupRules() {
return array(
new LegalpadDocumentRemarkupRule(),
);
}
public function getHelpDocumentationArticles(PhabricatorUser $viewer) {
return array(
array(
'name' => pht('Legalpad User Guide'),
'href' => PhabricatorEnv::getDoclink('Legalpad User Guide'),
),
);
}
public function getOverview() {
return pht(
'**Legalpad** is a simple application for tracking signatures and '.
'legal agreements. At the moment, it is primarily intended to help '.
'open source projects keep track of Contributor License Agreements.');
}
public function getRoutes() {
return array(
'/L(?P<id>\d+)' => 'LegalpadDocumentSignController',
'/legalpad/' => array(
'' => 'LegalpadDocumentListController',
'(?:query/(?P<queryKey>[^/]+)/)?' => 'LegalpadDocumentListController',
'create/' => 'LegalpadDocumentEditController',
'edit/(?P<id>\d+)/' => 'LegalpadDocumentEditController',
'comment/(?P<id>\d+)/' => 'LegalpadDocumentCommentController',
'view/(?P<id>\d+)/' => 'LegalpadDocumentManageController',
'done/' => 'LegalpadDocumentDoneController',
'verify/(?P<code>[^/]+)/'
=> 'LegalpadDocumentSignatureVerificationController',
'signatures/(?:(?P<id>\d+)/)?(?:query/(?P<queryKey>[^/]+)/)?'
=> 'LegalpadDocumentSignatureListController',
'addsignature/(?P<id>\d+)/' => 'LegalpadDocumentSignatureAddController',
'signature/(?P<id>\d+)/' => 'LegalpadDocumentSignatureViewController',
'document/' => array(
'preview/' => 'PhabricatorMarkupPreviewController',
),
),
);
}
protected function getCustomCapabilities() {
return array(
LegalpadCreateDocumentsCapability::CAPABILITY => array(),
LegalpadDefaultViewCapability::CAPABILITY => array(
'template' => PhabricatorLegalpadDocumentPHIDType::TYPECONST,
'capability' => PhabricatorPolicyCapability::CAN_VIEW,
),
LegalpadDefaultEditCapability::CAPABILITY => array(
'template' => PhabricatorLegalpadDocumentPHIDType::TYPECONST,
'capability' => PhabricatorPolicyCapability::CAN_EDIT,
),
);
}
public function getMailCommandObjects() {
return array(
'document' => array(
'name' => pht('Email Commands: Legalpad Documents'),
'header' => pht('Interacting with Legalpad Documents'),
'object' => new LegalpadDocument(),
'summary' => pht(
'This page documents the commands you can use to interact with '.
'documents in Legalpad.'),
),
);
}
}
diff --git a/src/applications/legalpad/config/PhabricatorLegalpadConfigOptions.php b/src/applications/legalpad/config/PhabricatorLegalpadConfigOptions.php
index e88ecb98f1..a9584fc94b 100644
--- a/src/applications/legalpad/config/PhabricatorLegalpadConfigOptions.php
+++ b/src/applications/legalpad/config/PhabricatorLegalpadConfigOptions.php
@@ -1,32 +1,32 @@
<?php
final class PhabricatorLegalpadConfigOptions
extends PhabricatorApplicationConfigOptions {
public function getName() {
return pht('Legalpad');
}
public function getDescription() {
return pht('Configure Legalpad.');
}
- public function getFontIcon() {
+ public function getIcon() {
return 'fa-gavel';
}
public function getGroup() {
return 'apps';
}
public function getOptions() {
return array(
$this->newOption(
'metamta.legalpad.subject-prefix',
'string',
'[Legalpad]')
->setDescription(pht('Subject prefix for Legalpad email.')),
);
}
}
diff --git a/src/applications/legalpad/query/LegalpadDocumentSearchEngine.php b/src/applications/legalpad/query/LegalpadDocumentSearchEngine.php
index 5e562a06c7..8b218cf821 100644
--- a/src/applications/legalpad/query/LegalpadDocumentSearchEngine.php
+++ b/src/applications/legalpad/query/LegalpadDocumentSearchEngine.php
@@ -1,239 +1,239 @@
<?php
final class LegalpadDocumentSearchEngine
extends PhabricatorApplicationSearchEngine {
public function getResultTypeDescription() {
return pht('Legalpad Documents');
}
public function getApplicationClassName() {
return 'PhabricatorLegalpadApplication';
}
public function buildSavedQueryFromRequest(AphrontRequest $request) {
$saved = new PhabricatorSavedQuery();
$saved->setParameter(
'creatorPHIDs',
$this->readUsersFromRequest($request, 'creators'));
$saved->setParameter(
'contributorPHIDs',
$this->readUsersFromRequest($request, 'contributors'));
$saved->setParameter(
'withViewerSignature',
$request->getBool('withViewerSignature'));
$saved->setParameter('createdStart', $request->getStr('createdStart'));
$saved->setParameter('createdEnd', $request->getStr('createdEnd'));
return $saved;
}
public function buildQueryFromSavedQuery(PhabricatorSavedQuery $saved) {
$query = id(new LegalpadDocumentQuery())
->needViewerSignatures(true);
$creator_phids = $saved->getParameter('creatorPHIDs', array());
if ($creator_phids) {
$query->withCreatorPHIDs($creator_phids);
}
$contributor_phids = $saved->getParameter('contributorPHIDs', array());
if ($contributor_phids) {
$query->withContributorPHIDs($contributor_phids);
}
if ($saved->getParameter('withViewerSignature')) {
$viewer_phid = $this->requireViewer()->getPHID();
if ($viewer_phid) {
$query->withSignerPHIDs(array($viewer_phid));
}
}
$start = $this->parseDateTime($saved->getParameter('createdStart'));
$end = $this->parseDateTime($saved->getParameter('createdEnd'));
if ($start) {
$query->withDateCreatedAfter($start);
}
if ($end) {
$query->withDateCreatedBefore($end);
}
return $query;
}
public function buildSearchForm(
AphrontFormView $form,
PhabricatorSavedQuery $saved_query) {
$creator_phids = $saved_query->getParameter('creatorPHIDs', array());
$contributor_phids = $saved_query->getParameter(
'contributorPHIDs', array());
$viewer_signature = $saved_query->getParameter('withViewerSignature');
if (!$this->requireViewer()->getPHID()) {
$viewer_signature = false;
}
$form
->appendChild(
id(new AphrontFormCheckboxControl())
->addCheckbox(
'withViewerSignature',
1,
pht('Show only documents I have signed.'),
$viewer_signature)
->setDisabled(!$this->requireViewer()->getPHID()))
->appendControl(
id(new AphrontFormTokenizerControl())
->setDatasource(new PhabricatorPeopleDatasource())
->setName('creators')
->setLabel(pht('Creators'))
->setValue($creator_phids))
->appendControl(
id(new AphrontFormTokenizerControl())
->setDatasource(new PhabricatorPeopleDatasource())
->setName('contributors')
->setLabel(pht('Contributors'))
->setValue($contributor_phids));
$this->buildDateRange(
$form,
$saved_query,
'createdStart',
pht('Created After'),
'createdEnd',
pht('Created Before'));
}
protected function getURI($path) {
return '/legalpad/'.$path;
}
protected function getBuiltinQueryNames() {
$names = array();
if ($this->requireViewer()->isLoggedIn()) {
$names['signed'] = pht('Signed Documents');
}
$names['all'] = pht('All Documents');
return $names;
}
public function buildSavedQueryFromBuiltin($query_key) {
$query = $this->newSavedQuery();
$query->setQueryKey($query_key);
switch ($query_key) {
case 'signed':
return $query
->setParameter('withViewerSignature', true);
case 'all':
return $query;
}
return parent::buildSavedQueryFromBuiltin($query_key);
}
protected function getRequiredHandlePHIDsForResultList(
array $documents,
PhabricatorSavedQuery $query) {
return array();
}
protected function renderResultList(
array $documents,
PhabricatorSavedQuery $query,
array $handles) {
assert_instances_of($documents, 'LegalpadDocument');
$viewer = $this->requireViewer();
$list = new PHUIObjectItemListView();
$list->setUser($viewer);
foreach ($documents as $document) {
$last_updated = phabricator_date($document->getDateModified(), $viewer);
$title = $document->getTitle();
$item = id(new PHUIObjectItemView())
->setObjectName($document->getMonogram())
->setHeader($title)
->setHref('/'.$document->getMonogram())
->setObject($document);
$no_signatures = LegalpadDocument::SIGNATURE_TYPE_NONE;
if ($document->getSignatureType() == $no_signatures) {
$item->addIcon('none', pht('Not Signable'));
} else {
$type_name = $document->getSignatureTypeName();
$type_icon = $document->getSignatureTypeIcon();
$item->addIcon($type_icon, $type_name);
if ($viewer->getPHID()) {
$signature = $document->getUserSignature($viewer->getPHID());
} else {
$signature = null;
}
if ($signature) {
$item->addAttribute(
array(
id(new PHUIIconView())->setIcon('fa-check-square-o', 'green'),
' ',
pht(
'Signed on %s',
phabricator_date($signature->getDateCreated(), $viewer)),
));
} else {
$item->addAttribute(
array(
id(new PHUIIconView())->setIcon('fa-square-o', 'grey'),
' ',
pht('Not Signed'),
));
}
}
$item->addIcon(
'fa-pencil grey',
pht('Version %d (%s)', $document->getVersions(), $last_updated));
$list->addItem($item);
}
$result = new PhabricatorApplicationSearchResultView();
$result->setObjectList($list);
$result->setNoDataString(pht('No documents found.'));
return $result;
}
protected function getNewUserBody() {
$create_button = id(new PHUIButtonView())
->setTag('a')
->setText(pht('Create a Document'))
->setHref('/legalpad/create/')
->setColor(PHUIButtonView::GREEN);
- $icon = $this->getApplication()->getFontIcon();
+ $icon = $this->getApplication()->getIcon();
$app_name = $this->getApplication()->getName();
$view = id(new PHUIBigInfoView())
->setIcon($icon)
->setTitle(pht('Welcome to %s', $app_name))
->setDescription(
pht('Create documents and track signatures. Can also be re-used in '.
'other areas of Phabricator, like CLAs.'))
->addAction($create_button);
return $view;
}
}
diff --git a/src/applications/macro/application/PhabricatorMacroApplication.php b/src/applications/macro/application/PhabricatorMacroApplication.php
index dabf285fd3..fc7dcabab6 100644
--- a/src/applications/macro/application/PhabricatorMacroApplication.php
+++ b/src/applications/macro/application/PhabricatorMacroApplication.php
@@ -1,73 +1,73 @@
<?php
final class PhabricatorMacroApplication extends PhabricatorApplication {
public function getBaseURI() {
return '/macro/';
}
public function getName() {
return pht('Macro');
}
public function getShortDescription() {
return pht('Image Macros and Memes');
}
- public function getFontIcon() {
+ public function getIcon() {
return 'fa-file-image-o';
}
public function getTitleGlyph() {
return "\xE2\x9A\x98";
}
public function getApplicationGroup() {
return self::GROUP_UTILITIES;
}
public function getRoutes() {
return array(
'/macro/' => array(
'(query/(?P<key>[^/]+)/)?' => 'PhabricatorMacroListController',
'create/' => 'PhabricatorMacroEditController',
'view/(?P<id>[1-9]\d*)/' => 'PhabricatorMacroViewController',
'comment/(?P<id>[1-9]\d*)/' => 'PhabricatorMacroCommentController',
'edit/(?P<id>[1-9]\d*)/' => 'PhabricatorMacroEditController',
'audio/(?P<id>[1-9]\d*)/' => 'PhabricatorMacroAudioController',
'disable/(?P<id>[1-9]\d*)/' => 'PhabricatorMacroDisableController',
'meme/' => 'PhabricatorMacroMemeController',
'meme/create/' => 'PhabricatorMacroMemeDialogController',
),
);
}
public function getRemarkupRules() {
return array(
new PhabricatorIconRemarkupRule(),
new PhabricatorEmojiRemarkupRule(),
);
}
protected function getCustomCapabilities() {
return array(
PhabricatorMacroManageCapability::CAPABILITY => array(
'caption' => pht('Allows creating and editing macros.'),
),
);
}
public function getMailCommandObjects() {
return array(
'macro' => array(
'name' => pht('Email Commands: Macros'),
'header' => pht('Interacting with Macros'),
'object' => new PhabricatorFileImageMacro(),
'summary' => pht(
'This page documents the commands you can use to interact with '.
'image macros.'),
),
);
}
}
diff --git a/src/applications/macro/config/PhabricatorMacroConfigOptions.php b/src/applications/macro/config/PhabricatorMacroConfigOptions.php
index 2ab913a733..2cb01ff29f 100644
--- a/src/applications/macro/config/PhabricatorMacroConfigOptions.php
+++ b/src/applications/macro/config/PhabricatorMacroConfigOptions.php
@@ -1,29 +1,29 @@
<?php
final class PhabricatorMacroConfigOptions
extends PhabricatorApplicationConfigOptions {
public function getName() {
return pht('Macro');
}
public function getDescription() {
return pht('Configure Macro.');
}
- public function getFontIcon() {
+ public function getIcon() {
return 'fa-file-image-o';
}
public function getGroup() {
return 'apps';
}
public function getOptions() {
return array(
$this->newOption('metamta.macro.subject-prefix', 'string', '[Macro]')
->setDescription(pht('Subject prefix for Macro email.')),
);
}
}
diff --git a/src/applications/macro/markup/PhabricatorIconRemarkupRule.php b/src/applications/macro/markup/PhabricatorIconRemarkupRule.php
index fe0c4f60b2..e1e6cede07 100644
--- a/src/applications/macro/markup/PhabricatorIconRemarkupRule.php
+++ b/src/applications/macro/markup/PhabricatorIconRemarkupRule.php
@@ -1,88 +1,88 @@
<?php
final class PhabricatorIconRemarkupRule extends PhutilRemarkupRule {
public function getPriority() {
return 200.0;
}
public function apply($text) {
return preg_replace_callback(
'@{icon\b((?:[^}\\\\]+|\\\\.)*)}@m',
array($this, 'markupIcon'),
$text);
}
public function markupIcon(array $matches) {
$engine = $this->getEngine();
$text_mode = $engine->isTextMode();
$mail_mode = $engine->isHTMLMailMode();
if (!$this->isFlatText($matches[0]) || $text_mode || $mail_mode) {
return $matches[0];
}
$extra = idx($matches, 1);
// We allow various forms, like these:
//
// {icon}
// {icon camera}
// {icon,camera}
// {icon camera color=red}
// {icon, camera, color=red}
$extra = ltrim($extra, ", \n");
$extra = preg_split('/[\s,]+/', $extra, 2);
// Choose some arbitrary default icon so that previews render in a mostly
// reasonable way as you're typing the syntax.
$icon = idx($extra, 0, 'paw');
$defaults = array(
'color' => null,
'spin' => false,
);
$options = idx($extra, 1, '');
$parser = new PhutilSimpleOptions();
$options = $parser->parse($options) + $defaults;
// NOTE: We're validating icon and color names to prevent users from
// adding arbitrary CSS classes to the document. Although this probably
// isn't dangerous, it's safer to validate.
static $icon_names;
if (!$icon_names) {
- $icon_names = array_fuse(PHUIIconView::getFontIcons());
+ $icon_names = array_fuse(PHUIIconView::getIcons());
}
static $color_names;
if (!$color_names) {
- $color_names = array_fuse(PHUIIconView::getFontIconColors());
+ $color_names = array_fuse(PHUIIconView::getIconColors());
}
if (empty($icon_names['fa-'.$icon])) {
$icon = 'paw';
}
$color = $options['color'];
if (empty($color_names[$color])) {
$color = null;
}
$classes = array();
$classes[] = $color;
$spin = $options['spin'];
if ($spin) {
$classes[] = 'ph-spin';
}
$icon_view = id(new PHUIIconView())
->setIcon('fa-'.$icon, implode(' ', $classes));
return $this->getEngine()->storeText($icon_view);
}
}
diff --git a/src/applications/macro/query/PhabricatorMacroSearchEngine.php b/src/applications/macro/query/PhabricatorMacroSearchEngine.php
index 1619f8185a..7ef57a6a10 100644
--- a/src/applications/macro/query/PhabricatorMacroSearchEngine.php
+++ b/src/applications/macro/query/PhabricatorMacroSearchEngine.php
@@ -1,211 +1,211 @@
<?php
final class PhabricatorMacroSearchEngine
extends PhabricatorApplicationSearchEngine {
public function getResultTypeDescription() {
return pht('Macros');
}
public function getApplicationClassName() {
return 'PhabricatorMacroApplication';
}
public function newQuery() {
return id(new PhabricatorMacroQuery())
->needFiles(true);
}
protected function buildCustomSearchFields() {
return array(
id(new PhabricatorSearchSelectField())
->setLabel(pht('Status'))
->setKey('status')
->setOptions(PhabricatorMacroQuery::getStatusOptions()),
id(new PhabricatorUsersSearchField())
->setLabel(pht('Authors'))
->setKey('authorPHIDs')
->setAliases(array('author', 'authors')),
id(new PhabricatorSearchTextField())
->setLabel(pht('Name Contains'))
->setKey('nameLike'),
id(new PhabricatorSearchStringListField())
->setLabel(pht('Exact Names'))
->setKey('names'),
id(new PhabricatorSearchSelectField())
->setLabel(pht('Marked with Flag'))
->setKey('flagColor')
->setDefault('-1')
->setOptions(PhabricatorMacroQuery::getFlagColorsOptions()),
id(new PhabricatorSearchDateField())
->setLabel(pht('Created After'))
->setKey('createdStart'),
id(new PhabricatorSearchDateField())
->setLabel(pht('Created Before'))
->setKey('createdEnd'),
);
}
protected function getDefaultFieldOrder() {
return array(
'...',
'createdStart',
'createdEnd',
);
}
protected function buildQueryFromParameters(array $map) {
$query = $this->newQuery();
if ($map['authorPHIDs']) {
$query->withAuthorPHIDs($map['authorPHIDs']);
}
if ($map['status']) {
$query->withStatus($map['status']);
}
if ($map['names']) {
$query->withNames($map['names']);
}
if (strlen($map['nameLike'])) {
$query->withNameLike($map['nameLike']);
}
if ($map['createdStart']) {
$query->withDateCreatedAfter($map['createdStart']);
}
if ($map['createdEnd']) {
$query->withDateCreatedBefore($map['createdEnd']);
}
if ($map['flagColor'] !== null) {
$query->withFlagColor($map['flagColor']);
}
return $query;
}
protected function getURI($path) {
return '/macro/'.$path;
}
protected function getBuiltinQueryNames() {
$names = array(
'active' => pht('Active'),
'all' => pht('All'),
);
if ($this->requireViewer()->isLoggedIn()) {
$names['authored'] = pht('Authored');
}
return $names;
}
public function buildSavedQueryFromBuiltin($query_key) {
$query = $this->newSavedQuery();
$query->setQueryKey($query_key);
switch ($query_key) {
case 'active':
return $query->setParameter(
'status',
PhabricatorMacroQuery::STATUS_ACTIVE);
case 'all':
return $query->setParameter(
'status',
PhabricatorMacroQuery::STATUS_ANY);
case 'authored':
return $query->setParameter(
'authorPHIDs',
array($this->requireViewer()->getPHID()));
}
return parent::buildSavedQueryFromBuiltin($query_key);
}
protected function renderResultList(
array $macros,
PhabricatorSavedQuery $query,
array $handles) {
assert_instances_of($macros, 'PhabricatorFileImageMacro');
$viewer = $this->requireViewer();
$handles = $viewer->loadHandles(mpull($macros, 'getAuthorPHID'));
$xform = PhabricatorFileTransform::getTransformByKey(
PhabricatorFileThumbnailTransform::TRANSFORM_PINBOARD);
$pinboard = new PHUIPinboardView();
foreach ($macros as $macro) {
$file = $macro->getFile();
$item = id(new PHUIPinboardItemView())
->setUser($viewer)
->setObject($macro);
if ($file) {
$item->setImageURI($file->getURIForTransform($xform));
list($x, $y) = $xform->getTransformedDimensions($file);
$item->setImageSize($x, $y);
}
if ($macro->getDateCreated()) {
$datetime = phabricator_date($macro->getDateCreated(), $viewer);
$item->appendChild(
phutil_tag(
'div',
array(),
pht('Created on %s', $datetime)));
} else {
// Very old macros don't have a creation date. Rendering something
// keeps all the pins at the same height and avoids flow issues.
$item->appendChild(
phutil_tag(
'div',
array(),
pht('Created in ages long past')));
}
if ($macro->getAuthorPHID()) {
$author_handle = $handles[$macro->getAuthorPHID()];
$item->appendChild(
pht('Created by %s', $author_handle->renderLink()));
}
$item->setURI($this->getApplicationURI('/view/'.$macro->getID().'/'));
$item->setDisabled($macro->getisDisabled());
$item->setHeader($macro->getName());
$pinboard->addItem($item);
}
$result = new PhabricatorApplicationSearchResultView();
$result->setContent($pinboard);
return $result;
}
protected function getNewUserBody() {
$create_button = id(new PHUIButtonView())
->setTag('a')
->setText(pht('Create a Macro'))
->setHref('/macro/create/')
->setColor(PHUIButtonView::GREEN);
- $icon = $this->getApplication()->getFontIcon();
+ $icon = $this->getApplication()->getIcon();
$app_name = $this->getApplication()->getName();
$view = id(new PHUIBigInfoView())
->setIcon($icon)
->setTitle(pht('Welcome to %s', $app_name))
->setDescription(
pht('Create easy to remember shortcuts to images and memes.'))
->addAction($create_button);
return $view;
}
}
diff --git a/src/applications/maniphest/application/PhabricatorManiphestApplication.php b/src/applications/maniphest/application/PhabricatorManiphestApplication.php
index 3fcbbf49f0..61186c7b8d 100644
--- a/src/applications/maniphest/application/PhabricatorManiphestApplication.php
+++ b/src/applications/maniphest/application/PhabricatorManiphestApplication.php
@@ -1,155 +1,155 @@
<?php
final class PhabricatorManiphestApplication extends PhabricatorApplication {
public function getName() {
return pht('Maniphest');
}
public function getShortDescription() {
return pht('Tasks and Bugs');
}
public function getBaseURI() {
return '/maniphest/';
}
- public function getFontIcon() {
+ public function getIcon() {
return 'fa-anchor';
}
public function getTitleGlyph() {
return "\xE2\x9A\x93";
}
public function isPinnedByDefault(PhabricatorUser $viewer) {
return true;
}
public function getApplicationOrder() {
return 0.110;
}
public function getFactObjectsForAnalysis() {
return array(
new ManiphestTask(),
);
}
public function getRemarkupRules() {
return array(
new ManiphestRemarkupRule(),
);
}
public function getRoutes() {
return array(
'/T(?P<id>[1-9]\d*)' => 'ManiphestTaskDetailController',
'/maniphest/' => array(
'(?:query/(?P<queryKey>[^/]+)/)?' => 'ManiphestTaskListController',
'report/(?:(?P<view>\w+)/)?' => 'ManiphestReportController',
'batch/' => 'ManiphestBatchEditController',
'task/' => array(
$this->getEditRoutePattern('edit/')
=> 'ManiphestTaskEditController',
),
'export/(?P<key>[^/]+)/' => 'ManiphestExportController',
'subpriority/' => 'ManiphestSubpriorityController',
),
);
}
public function loadStatus(PhabricatorUser $user) {
$status = array();
if (!$user->isLoggedIn()) {
return $status;
}
$limit = self::MAX_STATUS_ITEMS;
$query = id(new ManiphestTaskQuery())
->setViewer($user)
->withStatuses(ManiphestTaskStatus::getOpenStatusConstants())
->withOwners(array($user->getPHID()))
->setLimit($limit);
$count = count($query->execute());
if ($count >= $limit) {
$count_str = pht('%s+ Assigned Task(s)', new PhutilNumber($limit - 1));
} else {
$count_str = pht('%s Assigned Task(s)', new PhutilNumber($count));
}
$type = PhabricatorApplicationStatusView::TYPE_WARNING;
$status[] = id(new PhabricatorApplicationStatusView())
->setType($type)
->setText($count_str)
->setCount($count);
return $status;
}
public function getQuickCreateItems(PhabricatorUser $viewer) {
return id(new ManiphestEditEngine())
->setViewer($viewer)
->loadQuickCreateItems();
}
public function supportsEmailIntegration() {
return true;
}
public function getAppEmailBlurb() {
return pht(
'Send email to these addresses to create tasks. %s',
phutil_tag(
'a',
array(
'href' => $this->getInboundEmailSupportLink(),
),
pht('Learn More')));
}
protected function getCustomCapabilities() {
return array(
ManiphestDefaultViewCapability::CAPABILITY => array(
'caption' => pht('Default view policy for newly created tasks.'),
'template' => ManiphestTaskPHIDType::TYPECONST,
'capability' => PhabricatorPolicyCapability::CAN_VIEW,
),
ManiphestDefaultEditCapability::CAPABILITY => array(
'caption' => pht('Default edit policy for newly created tasks.'),
'template' => ManiphestTaskPHIDType::TYPECONST,
'capability' => PhabricatorPolicyCapability::CAN_EDIT,
),
ManiphestEditStatusCapability::CAPABILITY => array(),
ManiphestEditAssignCapability::CAPABILITY => array(),
ManiphestEditPoliciesCapability::CAPABILITY => array(),
ManiphestEditPriorityCapability::CAPABILITY => array(),
ManiphestEditProjectsCapability::CAPABILITY => array(),
ManiphestBulkEditCapability::CAPABILITY => array(),
);
}
public function getMailCommandObjects() {
return array(
'task' => array(
'name' => pht('Email Commands: Tasks'),
'header' => pht('Interacting with Maniphest Tasks'),
'object' => new ManiphestTask(),
'summary' => pht(
'This page documents the commands you can use to interact with '.
'tasks in Maniphest. These commands work when creating new tasks '.
'via email and when replying to existing tasks.'),
),
);
}
public function getApplicationSearchDocumentTypes() {
return array(
ManiphestTaskPHIDType::TYPECONST,
);
}
}
diff --git a/src/applications/maniphest/config/PhabricatorManiphestConfigOptions.php b/src/applications/maniphest/config/PhabricatorManiphestConfigOptions.php
index a6f1cb79bf..3d47c59e1c 100644
--- a/src/applications/maniphest/config/PhabricatorManiphestConfigOptions.php
+++ b/src/applications/maniphest/config/PhabricatorManiphestConfigOptions.php
@@ -1,343 +1,343 @@
<?php
final class PhabricatorManiphestConfigOptions
extends PhabricatorApplicationConfigOptions {
public function getName() {
return pht('Maniphest');
}
public function getDescription() {
return pht('Configure Maniphest.');
}
- public function getFontIcon() {
+ public function getIcon() {
return 'fa-anchor';
}
public function getGroup() {
return 'apps';
}
public function getOptions() {
$priority_type = 'custom:ManiphestPriorityConfigOptionType';
$priority_defaults = array(
100 => array(
'name' => pht('Unbreak Now!'),
'short' => pht('Unbreak!'),
'color' => 'pink',
'keywords' => array('unbreak'),
),
90 => array(
'name' => pht('Needs Triage'),
'short' => pht('Triage'),
'color' => 'violet',
'keywords' => array('triage'),
),
80 => array(
'name' => pht('High'),
'short' => pht('High'),
'color' => 'red',
'keywords' => array('high'),
),
50 => array(
'name' => pht('Normal'),
'short' => pht('Normal'),
'color' => 'orange',
'keywords' => array('normal'),
),
25 => array(
'name' => pht('Low'),
'short' => pht('Low'),
'color' => 'yellow',
'keywords' => array('low'),
),
0 => array(
'name' => pht('Wishlist'),
'short' => pht('Wish'),
'color' => 'sky',
'keywords' => array('wish', 'wishlist'),
),
);
$status_type = 'custom:ManiphestStatusConfigOptionType';
$status_defaults = array(
'open' => array(
'name' => pht('Open'),
'special' => ManiphestTaskStatus::SPECIAL_DEFAULT,
'prefixes' => array(
'open',
'opens',
'reopen',
'reopens',
),
),
'resolved' => array(
'name' => pht('Resolved'),
'name.full' => pht('Closed, Resolved'),
'closed' => true,
'special' => ManiphestTaskStatus::SPECIAL_CLOSED,
'prefixes' => array(
'closed',
'closes',
'close',
'fix',
'fixes',
'fixed',
'resolve',
'resolves',
'resolved',
),
'suffixes' => array(
'as resolved',
'as fixed',
),
'keywords' => array('closed', 'fixed', 'resolved'),
),
'wontfix' => array(
'name' => pht('Wontfix'),
'name.full' => pht('Closed, Wontfix'),
'closed' => true,
'prefixes' => array(
'wontfix',
'wontfixes',
'wontfixed',
),
'suffixes' => array(
'as wontfix',
),
),
'invalid' => array(
'name' => pht('Invalid'),
'name.full' => pht('Closed, Invalid'),
'closed' => true,
'prefixes' => array(
'invalidate',
'invalidates',
'invalidated',
),
'suffixes' => array(
'as invalid',
),
),
'duplicate' => array(
'name' => pht('Duplicate'),
'name.full' => pht('Closed, Duplicate'),
'transaction.icon' => 'fa-files-o',
'special' => ManiphestTaskStatus::SPECIAL_DUPLICATE,
'closed' => true,
),
'spite' => array(
'name' => pht('Spite'),
'name.full' => pht('Closed, Spite'),
'name.action' => pht('Spited'),
'transaction.icon' => 'fa-thumbs-o-down',
'silly' => true,
'closed' => true,
'prefixes' => array(
'spite',
'spites',
'spited',
),
'suffixes' => array(
'out of spite',
'as spite',
),
),
);
$status_description = $this->deformat(pht(<<<EOTEXT
Allows you to edit, add, or remove the task statuses available in Maniphest,
like "Open", "Resolved" and "Invalid". The configuration should contain a map
of status constants to status specifications (see defaults below for examples).
The constant for each status should be 1-12 characters long and contain only
lowercase letters and digits. Valid examples are "open", "closed", and
"invalid". Users will not normally see these values.
The keys you can provide in a specification are:
- `name` //Required string.// Name of the status, like "Invalid".
- `name.full` //Optional string.// Longer name, like "Closed, Invalid". This
appears on the task detail view in the header.
- `name.action` //Optional string.// Action name for email subjects, like
"Marked Invalid".
- `closed` //Optional bool.// Statuses are either "open" or "closed".
Specifying `true` here will mark the status as closed (like "Resolved" or
"Invalid"). By default, statuses are open.
- `special` //Optional string.// Mark this status as special. The special
statuses are:
- `default` This is the default status for newly created tasks. You must
designate one status as default, and it must be an open status.
- `closed` This is the default status for closed tasks (for example, tasks
closed via the "!close" action in email or via the quick close button in
Maniphest). You must designate one status as the default closed status,
and it must be a closed status.
- `duplicate` This is the status used when tasks are merged into one
another as duplicates. You must designate one status for duplicates,
and it must be a closed status.
- `transaction.icon` //Optional string.// Allows you to choose a different
icon to use for this status when showing status changes in the transaction
log. Please see UIExamples, Icons and Images for a list.
- `transaction.color` //Optional string.// Allows you to choose a different
color to use for this status when showing status changes in the transaction
log.
- `silly` //Optional bool.// Marks this status as silly, and thus wholly
inappropriate for use by serious businesses.
- `prefixes` //Optional list<string>.// Allows you to specify a list of
text prefixes which will trigger a task transition into this status
when mentioned in a commit message. For example, providing "closes" here
will allow users to move tasks to this status by writing `Closes T123` in
commit messages.
- `suffixes` //Optional list<string>.// Allows you to specify a list of
text suffixes which will trigger a task transition into this status
when mentioned in a commit message, after a valid prefix. For example,
providing "as invalid" here will allow users to move tasks
to this status by writing `Closes T123 as invalid`, even if another status
is selected by the "Closes" prefix.
- `keywords` //Optional list<string>.// Allows you to specify a list
of keywords which can be used with `!status` commands in email to select
this status.
- `disabled` //Optional bool.// Marks this status as no longer in use so
tasks can not be created or edited to have this status. Existing tasks with
this status will not be affected, but you can batch edit them or let them
die out on their own.
Statuses will appear in the UI in the order specified. Note the status marked
`special` as `duplicate` is not settable directly and will not appear in UI
elements, and that any status marked `silly` does not appear if Phabricator
is configured with `phabricator.serious-business` set to true.
Examining the default configuration and examples below will probably be helpful
in understanding these options.
EOTEXT
));
$status_example = array(
'open' => array(
'name' => pht('Open'),
'special' => 'default',
),
'closed' => array(
'name' => pht('Closed'),
'special' => 'closed',
'closed' => true,
),
'duplicate' => array(
'name' => pht('Duplicate'),
'special' => 'duplicate',
'closed' => true,
),
);
$json = new PhutilJSON();
$status_example = $json->encodeFormatted($status_example);
// This is intentionally blank for now, until we can move more Maniphest
// logic to custom fields.
$default_fields = array();
foreach ($default_fields as $key => $enabled) {
$default_fields[$key] = array(
'disabled' => !$enabled,
);
}
$custom_field_type = 'custom:PhabricatorCustomFieldConfigOptionType';
$fields_example = array(
'mycompany.estimated-hours' => array(
'name' => pht('Estimated Hours'),
'type' => 'int',
'caption' => pht('Estimated number of hours this will take.'),
),
);
$fields_json = id(new PhutilJSON())->encodeFormatted($fields_example);
return array(
$this->newOption('maniphest.custom-field-definitions', 'wild', array())
->setSummary(pht('Custom Maniphest fields.'))
->setDescription(
pht(
'Array of custom fields for Maniphest tasks. For details on '.
'adding custom fields to Maniphest, see "Configuring Custom '.
'Fields" in the documentation.'))
->addExample($fields_json, pht('Valid setting')),
$this->newOption('maniphest.fields', $custom_field_type, $default_fields)
->setCustomData(id(new ManiphestTask())->getCustomFieldBaseClass())
->setDescription(pht('Select and reorder task fields.')),
$this->newOption(
'maniphest.priorities',
$priority_type,
$priority_defaults)
->setSummary(pht('Configure Maniphest priority names.'))
->setDescription(
pht(
'Allows you to edit or override the default priorities available '.
'in Maniphest, like "High", "Normal" and "Low". The configuration '.
'should contain a map of priority constants to priority '.
'specifications (see defaults below for examples).'.
"\n\n".
'The keys you can define for a priority are:'.
"\n\n".
' - `name` Name of the priority.'."\n".
' - `short` Alternate shorter name, used in UIs where there is '.
' not much space available.'."\n".
' - `color` A color for this priority, like "red" or "blue".'.
' - `keywords` An optional list of keywords which can '.
' be used to select this priority when using `!priority` '.
' commands in email.'."\n".
' - `disabled` Optional boolean to prevent users from choosing '.
' this priority when creating or editing tasks. Existing '.
' tasks will be unaffected, and can be batch edited to a '.
' different priority or left to eventually die out.'.
"\n\n".
'You can choose which priority is the default for newly created '.
'tasks with `%s`.',
'maniphest.default-priority')),
$this->newOption('maniphest.statuses', $status_type, $status_defaults)
->setSummary(pht('Configure Maniphest task statuses.'))
->setDescription($status_description)
->addExample($status_example, pht('Minimal Valid Config')),
$this->newOption('maniphest.default-priority', 'int', 90)
->setSummary(pht('Default task priority for create flows.'))
->setDescription(
pht(
'Choose a default priority for newly created tasks. You can '.
'review and adjust available priorities by using the '.
'%s configuration option. The default value (`90`) '.
'corresponds to the default "Needs Triage" priority.',
'maniphest.priorities')),
$this->newOption(
'metamta.maniphest.subject-prefix',
'string',
'[Maniphest]')
->setDescription(pht('Subject prefix for Maniphest mail.')),
$this->newOption(
'maniphest.priorities.unbreak-now',
'int',
100)
->setSummary(pht('Priority used to populate "Unbreak Now" on home.'))
->setDescription(
pht(
'Temporary setting. If set, this priority is used to populate the '.
'"Unbreak Now" panel on the home page. You should adjust this if '.
'you adjust priorities using `%s`.',
'maniphest.priorities')),
$this->newOption(
'maniphest.priorities.needs-triage',
'int',
90)
->setSummary(pht('Priority used to populate "Needs Triage" on home.'))
->setDescription(
pht(
'Temporary setting. If set, this priority is used to populate the '.
'"Needs Triage" panel on the home page. You should adjust this if '.
'you adjust priorities using `%s`.',
'maniphest.priorities')),
);
}
}
diff --git a/src/applications/maniphest/query/ManiphestTaskSearchEngine.php b/src/applications/maniphest/query/ManiphestTaskSearchEngine.php
index 8e2f295f1a..4c92f9d642 100644
--- a/src/applications/maniphest/query/ManiphestTaskSearchEngine.php
+++ b/src/applications/maniphest/query/ManiphestTaskSearchEngine.php
@@ -1,408 +1,408 @@
<?php
final class ManiphestTaskSearchEngine
extends PhabricatorApplicationSearchEngine {
private $showBatchControls;
private $baseURI;
private $isBoardView;
public function setIsBoardView($is_board_view) {
$this->isBoardView = $is_board_view;
return $this;
}
public function getIsBoardView() {
return $this->isBoardView;
}
public function setBaseURI($base_uri) {
$this->baseURI = $base_uri;
return $this;
}
public function getBaseURI() {
return $this->baseURI;
}
public function setShowBatchControls($show_batch_controls) {
$this->showBatchControls = $show_batch_controls;
return $this;
}
public function getResultTypeDescription() {
return pht('Tasks');
}
public function getApplicationClassName() {
return 'PhabricatorManiphestApplication';
}
public function newQuery() {
return id(new ManiphestTaskQuery())
->needProjectPHIDs(true);
}
protected function buildCustomSearchFields() {
return array(
id(new PhabricatorOwnersSearchField())
->setLabel(pht('Assigned To'))
->setKey('assignedPHIDs')
->setConduitKey('assigned')
->setAliases(array('assigned'))
->setDescription(
pht('Search for tasks owned by a user from a list.')),
id(new PhabricatorUsersSearchField())
->setLabel(pht('Authors'))
->setKey('authorPHIDs')
->setAliases(array('author', 'authors'))
->setDescription(
pht('Search for tasks with given authors.')),
id(new PhabricatorSearchDatasourceField())
->setLabel(pht('Statuses'))
->setKey('statuses')
->setAliases(array('status'))
->setDescription(
pht('Search for tasks with given statuses.'))
->setDatasource(new ManiphestTaskStatusFunctionDatasource()),
id(new PhabricatorSearchDatasourceField())
->setLabel(pht('Priorities'))
->setKey('priorities')
->setAliases(array('priority'))
->setDescription(
pht('Search for tasks with given priorities.'))
->setConduitParameterType(new ConduitIntListParameterType())
->setDatasource(new ManiphestTaskPriorityDatasource()),
id(new PhabricatorSearchTextField())
->setLabel(pht('Contains Words'))
->setKey('fulltext'),
id(new PhabricatorSearchThreeStateField())
->setLabel(pht('Blocking'))
->setKey('blocking')
->setOptions(
pht('(Show All)'),
pht('Show Only Tasks Blocking Other Tasks'),
pht('Hide Tasks Blocking Other Tasks')),
id(new PhabricatorSearchThreeStateField())
->setLabel(pht('Blocked'))
->setKey('blocked')
->setOptions(
pht('(Show All)'),
pht('Show Only Task Blocked By Other Tasks'),
pht('Hide Tasks Blocked By Other Tasks')),
id(new PhabricatorSearchSelectField())
->setLabel(pht('Group By'))
->setKey('group')
->setOptions($this->getGroupOptions()),
id(new PhabricatorSearchDateField())
->setLabel(pht('Created After'))
->setKey('createdStart'),
id(new PhabricatorSearchDateField())
->setLabel(pht('Created Before'))
->setKey('createdEnd'),
id(new PhabricatorSearchDateField())
->setLabel(pht('Updated After'))
->setKey('modifiedStart'),
id(new PhabricatorSearchDateField())
->setLabel(pht('Updated Before'))
->setKey('modifiedEnd'),
id(new PhabricatorSearchTextField())
->setLabel(pht('Page Size'))
->setKey('limit'),
);
}
protected function getDefaultFieldOrder() {
return array(
'assignedPHIDs',
'projectPHIDs',
'authorPHIDs',
'subscriberPHIDs',
'statuses',
'priorities',
'fulltext',
'blocking',
'blocked',
'group',
'order',
'ids',
'...',
'createdStart',
'createdEnd',
'modifiedStart',
'modifiedEnd',
'limit',
);
}
protected function getHiddenFields() {
$keys = array();
if ($this->getIsBoardView()) {
$keys[] = 'group';
$keys[] = 'order';
$keys[] = 'limit';
}
return $keys;
}
protected function buildQueryFromParameters(array $map) {
$query = id(new ManiphestTaskQuery())
->needProjectPHIDs(true);
if ($map['assignedPHIDs']) {
$query->withOwners($map['assignedPHIDs']);
}
if ($map['authorPHIDs']) {
$query->withAuthors($map['authorPHIDs']);
}
if ($map['statuses']) {
$query->withStatuses($map['statuses']);
}
if ($map['priorities']) {
$query->withPriorities($map['priorities']);
}
if ($map['createdStart']) {
$query->withDateCreatedAfter($map['createdStart']);
}
if ($map['createdEnd']) {
$query->withDateCreatedBefore($map['createdEnd']);
}
if ($map['modifiedStart']) {
$query->withDateModifiedAfter($map['modifiedStart']);
}
if ($map['modifiedEnd']) {
$query->withDateModifiedBefore($map['modifiedEnd']);
}
if ($map['blocking'] !== null) {
$query->withBlockingTasks($map['blocking']);
}
if ($map['blocked'] !== null) {
$query->withBlockedTasks($map['blocked']);
}
if (strlen($map['fulltext'])) {
$query->withFullTextSearch($map['fulltext']);
}
$group = idx($map, 'group');
$group = idx($this->getGroupValues(), $group);
if ($group) {
$query->setGroupBy($group);
} else {
$query->setGroupBy(head($this->getGroupValues()));
}
if ($map['ids']) {
$ids = $map['ids'];
foreach ($ids as $key => $id) {
$id = trim($id, ' Tt');
if (!$id || !is_numeric($id)) {
unset($ids[$key]);
} else {
$ids[$key] = $id;
}
}
if ($ids) {
$query->withIDs($ids);
}
}
return $query;
}
protected function getURI($path) {
if ($this->baseURI) {
return $this->baseURI.$path;
}
return '/maniphest/'.$path;
}
protected function getBuiltinQueryNames() {
$names = array();
if ($this->requireViewer()->isLoggedIn()) {
$names['assigned'] = pht('Assigned');
$names['authored'] = pht('Authored');
$names['subscribed'] = pht('Subscribed');
}
$names['open'] = pht('Open Tasks');
$names['all'] = pht('All Tasks');
return $names;
}
public function buildSavedQueryFromBuiltin($query_key) {
$query = $this->newSavedQuery();
$query->setQueryKey($query_key);
$viewer_phid = $this->requireViewer()->getPHID();
switch ($query_key) {
case 'all':
return $query;
case 'assigned':
return $query
->setParameter('assignedPHIDs', array($viewer_phid))
->setParameter(
'statuses',
ManiphestTaskStatus::getOpenStatusConstants());
case 'subscribed':
return $query
->setParameter('subscriberPHIDs', array($viewer_phid))
->setParameter(
'statuses',
ManiphestTaskStatus::getOpenStatusConstants());
case 'open':
return $query
->setParameter(
'statuses',
ManiphestTaskStatus::getOpenStatusConstants());
case 'authored':
return $query
->setParameter('authorPHIDs', array($viewer_phid))
->setParameter('order', 'created')
->setParameter('group', 'none');
}
return parent::buildSavedQueryFromBuiltin($query_key);
}
private function getGroupOptions() {
return array(
'priority' => pht('Priority'),
'assigned' => pht('Assigned'),
'status' => pht('Status'),
'project' => pht('Project'),
'none' => pht('None'),
);
}
private function getGroupValues() {
return array(
'priority' => ManiphestTaskQuery::GROUP_PRIORITY,
'assigned' => ManiphestTaskQuery::GROUP_OWNER,
'status' => ManiphestTaskQuery::GROUP_STATUS,
'project' => ManiphestTaskQuery::GROUP_PROJECT,
'none' => ManiphestTaskQuery::GROUP_NONE,
);
}
protected function renderResultList(
array $tasks,
PhabricatorSavedQuery $saved,
array $handles) {
$viewer = $this->requireViewer();
if ($this->isPanelContext()) {
$can_edit_priority = false;
$can_bulk_edit = false;
} else {
$can_edit_priority = PhabricatorPolicyFilter::hasCapability(
$viewer,
$this->getApplication(),
ManiphestEditPriorityCapability::CAPABILITY);
$can_bulk_edit = PhabricatorPolicyFilter::hasCapability(
$viewer,
$this->getApplication(),
ManiphestBulkEditCapability::CAPABILITY);
}
$list = id(new ManiphestTaskResultListView())
->setUser($viewer)
->setTasks($tasks)
->setSavedQuery($saved)
->setCanEditPriority($can_edit_priority)
->setCanBatchEdit($can_bulk_edit)
->setShowBatchControls($this->showBatchControls);
$result = new PhabricatorApplicationSearchResultView();
$result->setContent($list);
return $result;
}
protected function willUseSavedQuery(PhabricatorSavedQuery $saved) {
// The 'withUnassigned' parameter may be present in old saved queries from
// before parameterized typeaheads, and is retained for compatibility. We
// could remove it by migrating old saved queries.
$assigned_phids = $saved->getParameter('assignedPHIDs', array());
if ($saved->getParameter('withUnassigned')) {
$assigned_phids[] = PhabricatorPeopleNoOwnerDatasource::FUNCTION_TOKEN;
}
$saved->setParameter('assignedPHIDs', $assigned_phids);
// The 'projects' and other parameters may be present in old saved queries
// from before parameterized typeaheads.
$project_phids = $saved->getParameter('projectPHIDs', array());
$old = $saved->getParameter('projects', array());
foreach ($old as $phid) {
$project_phids[] = $phid;
}
$all = $saved->getParameter('allProjectPHIDs', array());
foreach ($all as $phid) {
$project_phids[] = $phid;
}
$any = $saved->getParameter('anyProjectPHIDs', array());
foreach ($any as $phid) {
$project_phids[] = 'any('.$phid.')';
}
$not = $saved->getParameter('excludeProjectPHIDs', array());
foreach ($not as $phid) {
$project_phids[] = 'not('.$phid.')';
}
$users = $saved->getParameter('userProjectPHIDs', array());
foreach ($users as $phid) {
$project_phids[] = 'projects('.$phid.')';
}
$no = $saved->getParameter('withNoProject');
if ($no) {
$project_phids[] = 'null()';
}
$saved->setParameter('projectPHIDs', $project_phids);
}
protected function getNewUserBody() {
$create_button = id(new PHUIButtonView())
->setTag('a')
->setText(pht('Create a Task'))
->setHref('/maniphest/task/edit/')
->setColor(PHUIButtonView::GREEN);
- $icon = $this->getApplication()->getFontIcon();
+ $icon = $this->getApplication()->getIcon();
$app_name = $this->getApplication()->getName();
$view = id(new PHUIBigInfoView())
->setIcon($icon)
->setTitle(pht('Welcome to %s', $app_name))
->setDescription(
pht('Use Maniphest to track bugs, features, todos, or anything else '.
'you need to get done. Tasks assigned to you will appear here.'))
->addAction($create_button);
return $view;
}
}
diff --git a/src/applications/meta/application/PhabricatorApplicationsApplication.php b/src/applications/meta/application/PhabricatorApplicationsApplication.php
index 1b354213be..fc26eb1e27 100644
--- a/src/applications/meta/application/PhabricatorApplicationsApplication.php
+++ b/src/applications/meta/application/PhabricatorApplicationsApplication.php
@@ -1,54 +1,54 @@
<?php
final class PhabricatorApplicationsApplication extends PhabricatorApplication {
public function getName() {
return pht('Applications');
}
public function canUninstall() {
return false;
}
public function isLaunchable() {
// This application is launchable in the traditional sense, but showing it
// on the application launch list is confusing.
return false;
}
public function getBaseURI() {
return '/applications/';
}
public function getShortDescription() {
return pht('Explore More Applications');
}
- public function getFontIcon() {
+ public function getIcon() {
return 'fa-globe';
}
public function getTitleGlyph() {
return "\xE0\xBC\x84";
}
public function getRoutes() {
return array(
'/applications/' => array(
'(?:query/(?P<queryKey>[^/]+)/)?'
=> 'PhabricatorApplicationsListController',
'view/(?P<application>\w+)/'
=> 'PhabricatorApplicationDetailViewController',
'edit/(?P<application>\w+)/'
=> 'PhabricatorApplicationEditController',
'mailcommands/(?P<application>\w+)/(?P<type>\w+)/'
=> 'PhabricatorApplicationEmailCommandsController',
'(?P<application>\w+)/(?P<action>install|uninstall)/'
=> 'PhabricatorApplicationUninstallController',
'panel/(?P<application>\w+)/(?P<panel>\w+)/(?P<path>.*)'
=> 'PhabricatorApplicationPanelController',
),
);
}
}
diff --git a/src/applications/meta/query/PhabricatorAppSearchEngine.php b/src/applications/meta/query/PhabricatorAppSearchEngine.php
index 9dcc0a4399..98a9495fa0 100644
--- a/src/applications/meta/query/PhabricatorAppSearchEngine.php
+++ b/src/applications/meta/query/PhabricatorAppSearchEngine.php
@@ -1,273 +1,273 @@
<?php
final class PhabricatorAppSearchEngine
extends PhabricatorApplicationSearchEngine {
public function getResultTypeDescription() {
return pht('Applications');
}
public function getApplicationClassName() {
return 'PhabricatorApplicationsApplication';
}
public function getPageSize(PhabricatorSavedQuery $saved) {
return INF;
}
public function buildSavedQueryFromRequest(AphrontRequest $request) {
$saved = new PhabricatorSavedQuery();
$saved->setParameter('name', $request->getStr('name'));
$saved->setParameter(
'installed',
$this->readBoolFromRequest($request, 'installed'));
$saved->setParameter(
'prototypes',
$this->readBoolFromRequest($request, 'prototypes'));
$saved->setParameter(
'firstParty',
$this->readBoolFromRequest($request, 'firstParty'));
$saved->setParameter(
'launchable',
$this->readBoolFromRequest($request, 'launchable'));
$saved->setParameter(
'appemails',
$this->readBoolFromRequest($request, 'appemails'));
return $saved;
}
public function buildQueryFromSavedQuery(PhabricatorSavedQuery $saved) {
$query = id(new PhabricatorApplicationQuery())
->setOrder(PhabricatorApplicationQuery::ORDER_NAME)
->withUnlisted(false);
$name = $saved->getParameter('name');
if (strlen($name)) {
$query->withNameContains($name);
}
$installed = $saved->getParameter('installed');
if ($installed !== null) {
$query->withInstalled($installed);
}
$prototypes = $saved->getParameter('prototypes');
if ($prototypes === null) {
// NOTE: This is the old name of the 'prototypes' option, see T6084.
$prototypes = $saved->getParameter('beta');
$saved->setParameter('prototypes', $prototypes);
}
if ($prototypes !== null) {
$query->withPrototypes($prototypes);
}
$first_party = $saved->getParameter('firstParty');
if ($first_party !== null) {
$query->withFirstParty($first_party);
}
$launchable = $saved->getParameter('launchable');
if ($launchable !== null) {
$query->withLaunchable($launchable);
}
$appemails = $saved->getParameter('appemails');
if ($appemails !== null) {
$query->withApplicationEmailSupport($appemails);
}
return $query;
}
public function buildSearchForm(
AphrontFormView $form,
PhabricatorSavedQuery $saved) {
$form
->appendChild(
id(new AphrontFormTextControl())
->setLabel(pht('Name Contains'))
->setName('name')
->setValue($saved->getParameter('name')))
->appendChild(
id(new AphrontFormSelectControl())
->setLabel(pht('Installed'))
->setName('installed')
->setValue($this->getBoolFromQuery($saved, 'installed'))
->setOptions(
array(
'' => pht('Show All Applications'),
'true' => pht('Show Installed Applications'),
'false' => pht('Show Uninstalled Applications'),
)))
->appendChild(
id(new AphrontFormSelectControl())
->setLabel(pht('Prototypes'))
->setName('prototypes')
->setValue($this->getBoolFromQuery($saved, 'prototypes'))
->setOptions(
array(
'' => pht('Show All Applications'),
'true' => pht('Show Prototype Applications'),
'false' => pht('Show Released Applications'),
)))
->appendChild(
id(new AphrontFormSelectControl())
->setLabel(pht('Provenance'))
->setName('firstParty')
->setValue($this->getBoolFromQuery($saved, 'firstParty'))
->setOptions(
array(
'' => pht('Show All Applications'),
'true' => pht('Show First-Party Applications'),
'false' => pht('Show Third-Party Applications'),
)))
->appendChild(
id(new AphrontFormSelectControl())
->setLabel(pht('Launchable'))
->setName('launchable')
->setValue($this->getBoolFromQuery($saved, 'launchable'))
->setOptions(
array(
'' => pht('Show All Applications'),
'true' => pht('Show Launchable Applications'),
'false' => pht('Show Non-Launchable Applications'),
)))
->appendChild(
id(new AphrontFormSelectControl())
->setLabel(pht('Application Emails'))
->setName('appemails')
->setValue($this->getBoolFromQuery($saved, 'appemails'))
->setOptions(
array(
'' => pht('Show All Applications'),
'true' => pht('Show Applications w/ App Email Support'),
'false' => pht('Show Applications w/o App Email Support'),
)));
}
protected function getURI($path) {
return '/applications/'.$path;
}
protected function getBuiltinQueryNames() {
return array(
'launcher' => pht('Launcher'),
'all' => pht('All Applications'),
);
}
public function buildSavedQueryFromBuiltin($query_key) {
$query = $this->newSavedQuery();
$query->setQueryKey($query_key);
switch ($query_key) {
case 'launcher':
return $query
->setParameter('installed', true)
->setParameter('launchable', true);
case 'all':
return $query;
}
return parent::buildSavedQueryFromBuiltin($query_key);
}
protected function renderResultList(
array $all_applications,
PhabricatorSavedQuery $query,
array $handle) {
assert_instances_of($all_applications, 'PhabricatorApplication');
$all_applications = msort($all_applications, 'getName');
if ($query->getQueryKey() == 'launcher') {
$groups = mgroup($all_applications, 'getApplicationGroup');
} else {
$groups = array($all_applications);
}
$group_names = PhabricatorApplication::getApplicationGroups();
$groups = array_select_keys($groups, array_keys($group_names)) + $groups;
$results = array();
foreach ($groups as $group => $applications) {
if (count($groups) > 1) {
$results[] = phutil_tag(
'h1',
array(
'class' => 'phui-object-item-list-header',
),
idx($group_names, $group, $group));
}
$list = new PHUIObjectItemListView();
foreach ($applications as $application) {
- $icon = $application->getFontIcon();
+ $icon = $application->getIcon();
if (!$icon) {
$icon = 'application';
}
// TODO: This sheet doesn't work the same way other sheets do so it
// ends up with the wrong classes if we try to use PHUIIconView. This
// is probably all changing in the redesign anyway.
$icon_view = javelin_tag(
'span',
array(
'class' => 'phui-icon-view phui-font-fa '.$icon,
'aural' => false,
),
'');
$description = $application->getShortDescription();
$configure = id(new PHUIButtonView())
->setTag('a')
->setHref('/applications/view/'.get_class($application).'/')
->setText(pht('Configure'))
->setColor(PHUIButtonView::GREY);
$name = $application->getName();
if ($application->isPrototype()) {
$name = $name.' '.pht('(Prototype)');
}
$item = id(new PHUIObjectItemView())
->setHeader($name)
->setImageIcon($icon_view)
->setSubhead($description)
->setLaunchButton($configure);
if ($application->getBaseURI() && $application->isInstalled()) {
$item->setHref($application->getBaseURI());
}
if (!$application->isInstalled()) {
$item->addAttribute(pht('Uninstalled'));
$item->setDisabled(true);
}
if (!$application->isFirstParty()) {
$item->addAttribute(pht('Extension'));
}
$list->addItem($item);
}
$results[] = $list;
}
$result = new PhabricatorApplicationSearchResultView();
$result->setContent($results);
return $result;
}
}
diff --git a/src/applications/meta/typeahead/PhabricatorApplicationDatasource.php b/src/applications/meta/typeahead/PhabricatorApplicationDatasource.php
index b6d4aa3f18..176c3554cf 100644
--- a/src/applications/meta/typeahead/PhabricatorApplicationDatasource.php
+++ b/src/applications/meta/typeahead/PhabricatorApplicationDatasource.php
@@ -1,47 +1,47 @@
<?php
final class PhabricatorApplicationDatasource
extends PhabricatorTypeaheadDatasource {
public function getBrowseTitle() {
return pht('Browse Applications');
}
public function getPlaceholderText() {
return pht('Type an application name...');
}
public function getDatasourceApplicationClass() {
return 'PhabricatorApplicationsApplication';
}
public function loadResults() {
$viewer = $this->getViewer();
$raw_query = $this->getRawQuery();
$results = array();
$applications = PhabricatorApplication::getAllInstalledApplications();
foreach ($applications as $application) {
$uri = $application->getTypeaheadURI();
if (!$uri) {
continue;
}
$name = $application->getName().' '.$application->getShortDescription();
- $img = 'phui-font-fa phui-icon-view '.$application->getFontIcon();
+ $img = 'phui-font-fa phui-icon-view '.$application->getIcon();
$results[] = id(new PhabricatorTypeaheadResult())
->setName($name)
->setURI($uri)
->setPHID($application->getPHID())
->setPriorityString($application->getName())
->setDisplayName($application->getName())
->setDisplayType($application->getShortDescription())
->setImageuRI($application->getIconURI())
->setPriorityType('apps')
->setImageSprite('phabricator-search-icon '.$img);
}
return $this->filterResultsAgainstTokens($results);
}
}
diff --git a/src/applications/meta/view/PhabricatorApplicationLaunchView.php b/src/applications/meta/view/PhabricatorApplicationLaunchView.php
index c714e0daa6..95c3777d4e 100644
--- a/src/applications/meta/view/PhabricatorApplicationLaunchView.php
+++ b/src/applications/meta/view/PhabricatorApplicationLaunchView.php
@@ -1,145 +1,145 @@
<?php
final class PhabricatorApplicationLaunchView extends AphrontTagView {
private $application;
private $status;
public function setApplication(PhabricatorApplication $application) {
$this->application = $application;
return $this;
}
public function setApplicationStatus(array $status) {
$this->status = $status;
return $this;
}
protected function getTagName() {
return $this->application ? 'a' : 'div';
}
protected function getTagAttributes() {
$application = $this->application;
return array(
'class' => array('phabricator-application-launch-container'),
'href' => $application ? $application->getBaseURI() : null,
);
}
protected function getTagContent() {
$application = $this->application;
require_celerity_resource('phabricator-application-launch-view-css');
$content = array();
$icon = null;
if ($application) {
$content[] = phutil_tag(
'span',
array(
'class' => 'phabricator-application-launch-name',
),
$application->getName());
$content[] = phutil_tag(
'span',
array(
'class' => 'phabricator-application-launch-description',
),
$application->getShortDescription());
$counts = array();
$text = array();
if ($this->status) {
foreach ($this->status as $status) {
$type = $status->getType();
$counts[$type] = idx($counts, $type, 0) + $status->getCount();
if ($status->getCount()) {
$text[] = $status->getText();
}
}
}
$attention = PhabricatorApplicationStatusView::TYPE_NEEDS_ATTENTION;
$warning = PhabricatorApplicationStatusView::TYPE_WARNING;
if (!empty($counts[$attention]) || !empty($counts[$warning])) {
$count = idx($counts, $attention, 0);
$count1 = $count2 = '';
if ($count > 0) {
$count1 = phutil_tag(
'span',
array(
'class' => 'phabricator-application-attention-count',
),
$this->formatStatusItemCount($count));
}
if (!empty($counts[$warning])) {
$count2 = phutil_tag(
'span',
array(
'class' => 'phabricator-application-warning-count',
),
$this->formatStatusItemCount($counts[$warning]));
}
if (nonempty($count1) && nonempty($count2)) {
$numbers = array($count1, ' / ', $count2);
} else {
$numbers = array($count1, $count2);
}
Javelin::initBehavior('phabricator-tooltips');
$content[] = javelin_tag(
'span',
array(
'sigil' => 'has-tooltip',
'meta' => array(
'tip' => implode("\n", $text),
'size' => 300,
'align' => 'E',
),
'class' => 'phabricator-application-launch-attention',
),
$numbers);
}
$classes = array();
$classes[] = 'phabricator-application-launch-icon';
$styles = array();
if ($application->getIconURI()) {
$styles[] = 'background-image: url('.$application->getIconURI().')';
} else {
- $classes[] = $application->getFontIcon();
+ $classes[] = $application->getIcon();
$classes[] = 'phui-icon-view';
$classes[] = 'phui-font-fa';
}
$icon = phutil_tag(
'span',
array(
'class' => implode(' ', $classes),
'style' => nonempty(implode('; ', $styles), null),
),
'');
}
return array(
$icon,
$content,
);
}
private function formatStatusItemCount($count) {
$limit = PhabricatorApplication::MAX_STATUS_ITEMS;
if ($count >= $limit) {
return pht('%s+', new PhutilNumber($limit - 1));
} else {
return pht('%s', new PhutilNumber($count));
}
}
}
diff --git a/src/applications/metamta/application/PhabricatorMetaMTAApplication.php b/src/applications/metamta/application/PhabricatorMetaMTAApplication.php
index 5617c39c35..adb08aaa24 100644
--- a/src/applications/metamta/application/PhabricatorMetaMTAApplication.php
+++ b/src/applications/metamta/application/PhabricatorMetaMTAApplication.php
@@ -1,53 +1,53 @@
<?php
final class PhabricatorMetaMTAApplication extends PhabricatorApplication {
public function getName() {
return pht('Mail');
}
public function getBaseURI() {
return '/mail/';
}
- public function getFontIcon() {
+ public function getIcon() {
return 'fa-send';
}
public function getShortDescription() {
return pht('Send and Receive Mail');
}
public function getFlavorText() {
return pht('Every program attempts to expand until it can read mail.');
}
public function getApplicationGroup() {
return self::GROUP_ADMIN;
}
public function canUninstall() {
return false;
}
public function getTypeaheadURI() {
return '/mail/';
}
public function getRoutes() {
return array(
'/mail/' => array(
'(query/(?P<queryKey>[^/]+)/)?' =>
'PhabricatorMetaMTAMailListController',
'detail/(?P<id>[1-9]\d*)/' => 'PhabricatorMetaMTAMailViewController',
'sendgrid/' => 'PhabricatorMetaMTASendGridReceiveController',
'mailgun/' => 'PhabricatorMetaMTAMailgunReceiveController',
),
);
}
public function getTitleGlyph() {
return '@';
}
}
diff --git a/src/applications/multimeter/application/PhabricatorMultimeterApplication.php b/src/applications/multimeter/application/PhabricatorMultimeterApplication.php
index fdac449bd2..4965ae761d 100644
--- a/src/applications/multimeter/application/PhabricatorMultimeterApplication.php
+++ b/src/applications/multimeter/application/PhabricatorMultimeterApplication.php
@@ -1,55 +1,55 @@
<?php
final class PhabricatorMultimeterApplication
extends PhabricatorApplication {
public function getName() {
return pht('Multimeter');
}
public function getBaseURI() {
return '/multimeter/';
}
- public function getFontIcon() {
+ public function getIcon() {
return 'fa-motorcycle';
}
public function isPrototype() {
return true;
}
public function getTitleGlyph() {
return "\xE2\x8F\xB3";
}
public function getApplicationGroup() {
return self::GROUP_DEVELOPER;
}
public function getShortDescription() {
return pht('Performance Sampler');
}
public function getRemarkupRules() {
return array();
}
public function getRoutes() {
return array(
'/multimeter/' => array(
'' => 'MultimeterSampleController',
),
);
}
public function getHelpDocumentationArticles(PhabricatorUser $viewer) {
return array(
array(
'name' => pht('Multimeter User Guide'),
'href' => PhabricatorEnv::getDoclink('Multimeter User Guide'),
),
);
}
}
diff --git a/src/applications/notification/application/PhabricatorNotificationsApplication.php b/src/applications/notification/application/PhabricatorNotificationsApplication.php
index 0228b471b1..b4cc2b45b6 100644
--- a/src/applications/notification/application/PhabricatorNotificationsApplication.php
+++ b/src/applications/notification/application/PhabricatorNotificationsApplication.php
@@ -1,39 +1,39 @@
<?php
final class PhabricatorNotificationsApplication extends PhabricatorApplication {
public function getName() {
return pht('Notifications');
}
public function getBaseURI() {
return '/notification/';
}
public function getShortDescription() {
return pht('Real-Time Updates and Alerts');
}
- public function getFontIcon() {
+ public function getIcon() {
return 'fa-bell';
}
public function getRoutes() {
return array(
'/notification/' => array(
'(?:query/(?P<queryKey>[^/]+)/)?'
=> 'PhabricatorNotificationListController',
'panel/' => 'PhabricatorNotificationPanelController',
'individual/' => 'PhabricatorNotificationIndividualController',
'status/' => 'PhabricatorNotificationStatusController',
'clear/' => 'PhabricatorNotificationClearController',
'test/' => 'PhabricatorNotificationTestController',
),
);
}
public function isLaunchable() {
return false;
}
}
diff --git a/src/applications/nuance/application/PhabricatorNuanceApplication.php b/src/applications/nuance/application/PhabricatorNuanceApplication.php
index ce19afcd11..e3d5825d4e 100644
--- a/src/applications/nuance/application/PhabricatorNuanceApplication.php
+++ b/src/applications/nuance/application/PhabricatorNuanceApplication.php
@@ -1,88 +1,88 @@
<?php
final class PhabricatorNuanceApplication extends PhabricatorApplication {
public function getName() {
return pht('Nuance');
}
- public function getFontIcon() {
+ public function getIcon() {
return 'fa-fax';
}
public function getTitleGlyph() {
return "\xE2\x98\x8E";
}
public function isPrototype() {
return true;
}
public function isLaunchable() {
// Try to hide this even more for now.
return false;
}
public function canUninstall() {
return true;
}
public function getBaseURI() {
return '/nuance/';
}
public function getShortDescription() {
return pht('High-Volume Task Queues');
}
public function getRoutes() {
return array(
'/nuance/' => array(
'' => 'NuanceConsoleController',
'item/' => array(
'view/(?P<id>[1-9]\d*)/' => 'NuanceItemViewController',
'edit/(?P<id>[1-9]\d*)/' => 'NuanceItemEditController',
'new/' => 'NuanceItemEditController',
),
'source/' => array(
'(?:query/(?P<queryKey>[^/]+)/)?' => 'NuanceSourceListController',
'view/(?P<id>[1-9]\d*)/' => 'NuanceSourceViewController',
'edit/(?P<id>[1-9]\d*)/' => 'NuanceSourceEditController',
'new/(?P<type>[^/]+)/' => 'NuanceSourceEditController',
'create/' => 'NuanceSourceCreateController',
),
'queue/' => array(
'(?:query/(?P<queryKey>[^/]+)/)?' => 'NuanceQueueListController',
'view/(?P<id>[1-9]\d*)/' => 'NuanceQueueViewController',
'edit/(?P<id>[1-9]\d*)/' => 'NuanceQueueEditController',
'new/' => 'NuanceQueueEditController',
),
'requestor/' => array(
'view/(?P<id>[1-9]\d*)/' => 'NuanceRequestorViewController',
'edit/(?P<id>[1-9]\d*)/' => 'NuanceRequestorEditController',
'new/' => 'NuanceRequestorEditController',
),
),
'/action/' => array(
'(?P<id>[1-9]\d*)/(?P<path>.*)' => 'NuanceSourceActionController',
),
);
}
protected function getCustomCapabilities() {
return array(
NuanceSourceDefaultViewCapability::CAPABILITY => array(
'caption' => pht('Default view policy for newly created sources.'),
'template' => NuanceSourcePHIDType::TYPECONST,
'capability' => PhabricatorPolicyCapability::CAN_VIEW,
),
NuanceSourceDefaultEditCapability::CAPABILITY => array(
'caption' => pht('Default edit policy for newly created sources.'),
'template' => NuanceSourcePHIDType::TYPECONST,
'capability' => PhabricatorPolicyCapability::CAN_EDIT,
),
NuanceSourceManageCapability::CAPABILITY => array(),
);
}
}
diff --git a/src/applications/nuance/controller/NuanceConsoleController.php b/src/applications/nuance/controller/NuanceConsoleController.php
index 78ab474fb6..ffcde21ba3 100644
--- a/src/applications/nuance/controller/NuanceConsoleController.php
+++ b/src/applications/nuance/controller/NuanceConsoleController.php
@@ -1,46 +1,46 @@
<?php
final class NuanceConsoleController extends NuanceController {
public function shouldAllowPublic() {
return true;
}
public function handleRequest(AphrontRequest $request) {
$viewer = $request->getViewer();
$menu = id(new PHUIObjectItemListView())
->setUser($viewer);
$menu->addItem(
id(new PHUIObjectItemView())
->setHeader(pht('Queues'))
->setHref($this->getApplicationURI('queue/'))
- ->setFontIcon('fa-align-left')
+ ->setIcon('fa-align-left')
->addAttribute(pht('Manage Nuance queues.')));
$menu->addItem(
id(new PHUIObjectItemView())
->setHeader(pht('Sources'))
->setHref($this->getApplicationURI('source/'))
- ->setFontIcon('fa-filter')
+ ->setIcon('fa-filter')
->addAttribute(pht('Manage Nuance sources.')));
$crumbs = $this->buildApplicationCrumbs();
$crumbs->addTextCrumb(pht('Console'));
$box = id(new PHUIObjectBoxView())
->setHeaderText(pht('Console'))
->setObjectList($menu);
return $this->buildApplicationPage(
array(
$crumbs,
$box,
),
array(
'title' => pht('Nuance Console'),
));
}
}
diff --git a/src/applications/oauthserver/application/PhabricatorOAuthServerApplication.php b/src/applications/oauthserver/application/PhabricatorOAuthServerApplication.php
index 08e5e207f6..7bd7eed9ac 100644
--- a/src/applications/oauthserver/application/PhabricatorOAuthServerApplication.php
+++ b/src/applications/oauthserver/application/PhabricatorOAuthServerApplication.php
@@ -1,74 +1,74 @@
<?php
final class PhabricatorOAuthServerApplication extends PhabricatorApplication {
public function getName() {
return pht('OAuth Server');
}
public function getBaseURI() {
return '/oauthserver/';
}
public function getShortDescription() {
return pht('OAuth Login Provider');
}
- public function getFontIcon() {
+ public function getIcon() {
return 'fa-hotel';
}
public function getTitleGlyph() {
return "\xE2\x99\x86";
}
public function getFlavorText() {
return pht('Login with Phabricator');
}
public function getApplicationGroup() {
return self::GROUP_ADMIN;
}
public function isPrototype() {
return true;
}
public function getHelpDocumentationArticles(PhabricatorUser $viewer) {
return array(
array(
'name' => pht('Using the Phabricator OAuth Server'),
'href' => PhabricatorEnv::getDoclink(
'Using the Phabricator OAuth Server'),
),
);
}
public function getRoutes() {
return array(
'/oauthserver/' => array(
'(?:query/(?P<queryKey>[^/]+)/)?'
=> 'PhabricatorOAuthClientListController',
'auth/' => 'PhabricatorOAuthServerAuthController',
'test/(?P<id>\d+)/' => 'PhabricatorOAuthServerTestController',
'token/' => 'PhabricatorOAuthServerTokenController',
'client/' => array(
'create/' => 'PhabricatorOAuthClientEditController',
'delete/(?P<phid>[^/]+)/' => 'PhabricatorOAuthClientDeleteController',
'edit/(?P<phid>[^/]+)/' => 'PhabricatorOAuthClientEditController',
'view/(?P<phid>[^/]+)/' => 'PhabricatorOAuthClientViewController',
'secret/(?P<phid>[^/]+)/' => 'PhabricatorOAuthClientSecretController',
),
),
);
}
protected function getCustomCapabilities() {
return array(
PhabricatorOAuthServerCreateClientsCapability::CAPABILITY => array(
'default' => PhabricatorPolicies::POLICY_ADMIN,
),
);
}
}
diff --git a/src/applications/owners/application/PhabricatorOwnersApplication.php b/src/applications/owners/application/PhabricatorOwnersApplication.php
index 8511ce401d..574dd6ff7e 100644
--- a/src/applications/owners/application/PhabricatorOwnersApplication.php
+++ b/src/applications/owners/application/PhabricatorOwnersApplication.php
@@ -1,57 +1,57 @@
<?php
final class PhabricatorOwnersApplication extends PhabricatorApplication {
public function getName() {
return pht('Owners');
}
public function getBaseURI() {
return '/owners/';
}
- public function getFontIcon() {
+ public function getIcon() {
return 'fa-gift';
}
public function getShortDescription() {
return pht('Own Source Code');
}
public function getTitleGlyph() {
return "\xE2\x98\x81";
}
public function getHelpDocumentationArticles(PhabricatorUser $viewer) {
return array(
array(
'name' => pht('Owners User Guide'),
'href' => PhabricatorEnv::getDoclink('Owners User Guide'),
),
);
}
public function getFlavorText() {
return pht('Adopt today!');
}
public function getApplicationGroup() {
return self::GROUP_UTILITIES;
}
public function getRoutes() {
return array(
'/owners/' => array(
'(?:query/(?P<queryKey>[^/]+)/)?' => 'PhabricatorOwnersListController',
'new/' => 'PhabricatorOwnersEditController',
'package/(?P<id>[1-9]\d*)/' => 'PhabricatorOwnersDetailController',
'archive/(?P<id>[1-9]\d*)/' => 'PhabricatorOwnersArchiveController',
'paths/(?P<id>[1-9]\d*)/' => 'PhabricatorOwnersPathsController',
$this->getEditRoutePattern('edit/')
=> 'PhabricatorOwnersEditController',
),
);
}
}
diff --git a/src/applications/owners/config/PhabricatorOwnersConfigOptions.php b/src/applications/owners/config/PhabricatorOwnersConfigOptions.php
index 5c5766a43a..0f827672b7 100644
--- a/src/applications/owners/config/PhabricatorOwnersConfigOptions.php
+++ b/src/applications/owners/config/PhabricatorOwnersConfigOptions.php
@@ -1,55 +1,55 @@
<?php
final class PhabricatorOwnersConfigOptions
extends PhabricatorApplicationConfigOptions {
public function getName() {
return pht('Owners');
}
public function getDescription() {
return pht('Configure Owners.');
}
- public function getFontIcon() {
+ public function getIcon() {
return 'fa-gift';
}
public function getGroup() {
return 'apps';
}
public function getOptions() {
$custom_field_type = 'custom:PhabricatorCustomFieldConfigOptionType';
$default_fields = array();
$field_base_class = id(new PhabricatorOwnersPackage())
->getCustomFieldBaseClass();
$fields_example = array(
'mycompany:lore' => array(
'name' => pht('Package Lore'),
'type' => 'remarkup',
'caption' => pht('Tales of adventure for this package.'),
),
);
$fields_example = id(new PhutilJSON())->encodeFormatted($fields_example);
return array(
$this->newOption('metamta.package.subject-prefix', 'string', '[Package]')
->setDescription(pht('Subject prefix for Owners email.')),
$this->newOption('owners.fields', $custom_field_type, $default_fields)
->setCustomData($field_base_class)
->setDescription(pht('Select and reorder package fields.')),
$this->newOption('owners.custom-field-definitions', 'wild', array())
->setSummary(pht('Custom Owners fields.'))
->setDescription(
pht(
'Map of custom fields for Owners packages. For details on '.
'adding custom fields to Owners, see "Configuring Custom '.
'Fields" in the documentation.'))
->addExample($fields_example, pht('Valid Setting')),
);
}
}
diff --git a/src/applications/owners/query/PhabricatorOwnersPackageSearchEngine.php b/src/applications/owners/query/PhabricatorOwnersPackageSearchEngine.php
index f67b82b7b5..f92817d79e 100644
--- a/src/applications/owners/query/PhabricatorOwnersPackageSearchEngine.php
+++ b/src/applications/owners/query/PhabricatorOwnersPackageSearchEngine.php
@@ -1,178 +1,178 @@
<?php
final class PhabricatorOwnersPackageSearchEngine
extends PhabricatorApplicationSearchEngine {
public function getResultTypeDescription() {
return pht('Owners Packages');
}
public function getApplicationClassName() {
return 'PhabricatorOwnersApplication';
}
public function newQuery() {
return new PhabricatorOwnersPackageQuery();
}
protected function buildCustomSearchFields() {
return array(
id(new PhabricatorSearchDatasourceField())
->setLabel(pht('Authority'))
->setKey('authorityPHIDs')
->setAliases(array('authority', 'authorities'))
->setConduitKey('owners')
->setDescription(
pht('Search for packages with specific owners.'))
->setDatasource(new PhabricatorProjectOrUserDatasource()),
id(new PhabricatorSearchTextField())
->setLabel(pht('Name Contains'))
->setKey('name')
->setDescription(pht('Search for packages by name substrings.')),
id(new PhabricatorSearchDatasourceField())
->setLabel(pht('Repositories'))
->setKey('repositoryPHIDs')
->setConduitKey('repositories')
->setAliases(array('repository', 'repositories'))
->setDescription(
pht('Search for packages by included repositories.'))
->setDatasource(new DiffusionRepositoryDatasource()),
id(new PhabricatorSearchStringListField())
->setLabel(pht('Paths'))
->setKey('paths')
->setAliases(array('path'))
->setDescription(
pht('Search for packages affecting specific paths.')),
id(new PhabricatorSearchCheckboxesField())
->setKey('statuses')
->setLabel(pht('Status'))
->setDescription(
pht('Search for active or archived packages.'))
->setOptions(
id(new PhabricatorOwnersPackage())
->getStatusNameMap()),
);
}
protected function buildQueryFromParameters(array $map) {
$query = $this->newQuery();
if ($map['authorityPHIDs']) {
$query->withAuthorityPHIDs($map['authorityPHIDs']);
}
if ($map['repositoryPHIDs']) {
$query->withRepositoryPHIDs($map['repositoryPHIDs']);
}
if ($map['paths']) {
$query->withPaths($map['paths']);
}
if ($map['statuses']) {
$query->withStatuses($map['statuses']);
}
if (strlen($map['name'])) {
$query->withNameNgrams($map['name']);
}
return $query;
}
protected function getURI($path) {
return '/owners/'.$path;
}
protected function getBuiltinQueryNames() {
$names = array();
if ($this->requireViewer()->isLoggedIn()) {
$names['authority'] = pht('Owned');
}
$names += array(
'active' => pht('Active Packages'),
'all' => pht('All Packages'),
);
return $names;
}
public function buildSavedQueryFromBuiltin($query_key) {
$query = $this->newSavedQuery();
$query->setQueryKey($query_key);
switch ($query_key) {
case 'all':
return $query;
case 'active':
return $query->setParameter(
'statuses',
array(
PhabricatorOwnersPackage::STATUS_ACTIVE,
));
case 'authority':
return $query->setParameter(
'authorityPHIDs',
array($this->requireViewer()->getPHID()));
}
return parent::buildSavedQueryFromBuiltin($query_key);
}
protected function renderResultList(
array $packages,
PhabricatorSavedQuery $query,
array $handles) {
assert_instances_of($packages, 'PhabricatorOwnersPackage');
$viewer = $this->requireViewer();
$list = id(new PHUIObjectItemListView())
->setUser($viewer);
foreach ($packages as $package) {
$id = $package->getID();
$item = id(new PHUIObjectItemView())
->setObject($package)
->setObjectName(pht('Package %d', $id))
->setHeader($package->getName())
->setHref('/owners/package/'.$id.'/');
if ($package->isArchived()) {
$item->setDisabled(true);
}
$list->addItem($item);
}
$result = new PhabricatorApplicationSearchResultView();
$result->setObjectList($list);
$result->setNoDataString(pht('No packages found.'));
return $result;
}
protected function getNewUserBody() {
$create_button = id(new PHUIButtonView())
->setTag('a')
->setText(pht('Create a Package'))
->setHref('/owners/edit/')
->setColor(PHUIButtonView::GREEN);
- $icon = $this->getApplication()->getFontIcon();
+ $icon = $this->getApplication()->getIcon();
$app_name = $this->getApplication()->getName();
$view = id(new PHUIBigInfoView())
->setIcon($icon)
->setTitle(pht('Welcome to %s', $app_name))
->setDescription(
pht('Group sections of a codebase into packages for re-use in other '.
'areas of Phabricator, like Herald rules.'))
->addAction($create_button);
return $view;
}
}
diff --git a/src/applications/passphrase/application/PhabricatorPassphraseApplication.php b/src/applications/passphrase/application/PhabricatorPassphraseApplication.php
index daf794180f..2ab4f1e33d 100644
--- a/src/applications/passphrase/application/PhabricatorPassphraseApplication.php
+++ b/src/applications/passphrase/application/PhabricatorPassphraseApplication.php
@@ -1,86 +1,86 @@
<?php
final class PhabricatorPassphraseApplication extends PhabricatorApplication {
public function getName() {
return pht('Passphrase');
}
public function getBaseURI() {
return '/passphrase/';
}
public function getShortDescription() {
return pht('Credential Store');
}
- public function getFontIcon() {
+ public function getIcon() {
return 'fa-user-secret';
}
public function getTitleGlyph() {
return "\xE2\x97\x88";
}
public function getFlavorText() {
return pht('Put your secrets in a lockbox.');
}
public function getApplicationGroup() {
return self::GROUP_UTILITIES;
}
public function canUninstall() {
return false;
}
public function getRoutes() {
return array(
'/K(?P<id>\d+)' => 'PassphraseCredentialViewController',
'/passphrase/' => array(
'(?:query/(?P<queryKey>[^/]+)/)?'
=> 'PassphraseCredentialListController',
'create/' => 'PassphraseCredentialCreateController',
'edit/(?:(?P<id>\d+)/)?' => 'PassphraseCredentialEditController',
'destroy/(?P<id>\d+)/' => 'PassphraseCredentialDestroyController',
'reveal/(?P<id>\d+)/' => 'PassphraseCredentialRevealController',
'public/(?P<id>\d+)/' => 'PassphraseCredentialPublicController',
'lock/(?P<id>\d+)/' => 'PassphraseCredentialLockController',
'conduit/(?P<id>\d+)/' => 'PassphraseCredentialConduitController',
),
);
}
public function getRemarkupRules() {
return array(
new PassphraseRemarkupRule(),
);
}
public function getApplicationSearchDocumentTypes() {
return array(
PassphraseCredentialPHIDType::TYPECONST,
);
}
protected function getCustomCapabilities() {
$policy_key = id(new PassphraseCredentialAuthorPolicyRule())
->getObjectPolicyFullKey();
return array(
PassphraseDefaultViewCapability::CAPABILITY => array(
'caption' => pht('Default view policy for newly created credentials.'),
'template' => PassphraseCredentialPHIDType::TYPECONST,
'capability' => PhabricatorPolicyCapability::CAN_VIEW,
'default' => $policy_key,
),
PassphraseDefaultEditCapability::CAPABILITY => array(
'caption' => pht('Default edit policy for newly created credentials.'),
'template' => PassphraseCredentialPHIDType::TYPECONST,
'capability' => PhabricatorPolicyCapability::CAN_EDIT,
'default' => $policy_key,
),
);
}
}
diff --git a/src/applications/passphrase/query/PassphraseCredentialSearchEngine.php b/src/applications/passphrase/query/PassphraseCredentialSearchEngine.php
index d6d34baef1..ac4cbec9bf 100644
--- a/src/applications/passphrase/query/PassphraseCredentialSearchEngine.php
+++ b/src/applications/passphrase/query/PassphraseCredentialSearchEngine.php
@@ -1,134 +1,134 @@
<?php
final class PassphraseCredentialSearchEngine
extends PhabricatorApplicationSearchEngine {
public function getResultTypeDescription() {
return pht('Passphrase Credentials');
}
public function getApplicationClassName() {
return 'PhabricatorPassphraseApplication';
}
public function newQuery() {
return new PassphraseCredentialQuery();
}
protected function buildCustomSearchFields() {
return array(
id(new PhabricatorSearchThreeStateField())
->setLabel(pht('Status'))
->setKey('isDestroyed')
->setOptions(
pht('Show All'),
pht('Show Only Destroyed Credentials'),
pht('Show Only Active Credentials')),
id(new PhabricatorSearchTextField())
->setLabel(pht('Name Contains'))
->setKey('name'),
);
}
protected function buildQueryFromParameters(array $map) {
$query = $this->newQuery();
if ($map['isDestroyed'] !== null) {
$query->withIsDestroyed($map['isDestroyed']);
}
if (strlen($map['name'])) {
$query->withNameContains($map['name']);
}
return $query;
}
protected function getURI($path) {
return '/passphrase/'.$path;
}
protected function getBuiltinQueryNames() {
return array(
'active' => pht('Active Credentials'),
'all' => pht('All Credentials'),
);
}
public function buildSavedQueryFromBuiltin($query_key) {
$query = $this->newSavedQuery();
$query->setQueryKey($query_key);
switch ($query_key) {
case 'all':
return $query;
case 'active':
return $query->setParameter('isDestroyed', false);
}
return parent::buildSavedQueryFromBuiltin($query_key);
}
protected function renderResultList(
array $credentials,
PhabricatorSavedQuery $query,
array $handles) {
assert_instances_of($credentials, 'PassphraseCredential');
$viewer = $this->requireViewer();
$list = new PHUIObjectItemListView();
$list->setUser($viewer);
foreach ($credentials as $credential) {
$item = id(new PHUIObjectItemView())
->setObjectName('K'.$credential->getID())
->setHeader($credential->getName())
->setHref('/K'.$credential->getID())
->setObject($credential);
$item->addAttribute(
pht('Login: %s', $credential->getUsername()));
if ($credential->getIsDestroyed()) {
$item->addIcon('fa-ban', pht('Destroyed'));
$item->setDisabled(true);
}
$type = PassphraseCredentialType::getTypeByConstant(
$credential->getCredentialType());
if ($type) {
$item->addIcon('fa-wrench', $type->getCredentialTypeName());
}
$list->addItem($item);
}
$result = new PhabricatorApplicationSearchResultView();
$result->setObjectList($list);
$result->setNoDataString(pht('No credentials found.'));
return $result;
}
protected function getNewUserBody() {
$create_button = id(new PHUIButtonView())
->setTag('a')
->setText(pht('Create a Credential'))
->setHref('/passphrase/create/')
->setColor(PHUIButtonView::GREEN);
- $icon = $this->getApplication()->getFontIcon();
+ $icon = $this->getApplication()->getIcon();
$app_name = $this->getApplication()->getName();
$view = id(new PHUIBigInfoView())
->setIcon($icon)
->setTitle(pht('Welcome to %s', $app_name))
->setDescription(
pht('Credential management for re-use in other areas of Phabricator '.
'or general storage of shared secrets.'))
->addAction($create_button);
return $view;
}
}
diff --git a/src/applications/paste/application/PhabricatorPasteApplication.php b/src/applications/paste/application/PhabricatorPasteApplication.php
index 881ea8283a..1947c5377b 100644
--- a/src/applications/paste/application/PhabricatorPasteApplication.php
+++ b/src/applications/paste/application/PhabricatorPasteApplication.php
@@ -1,98 +1,98 @@
<?php
final class PhabricatorPasteApplication extends PhabricatorApplication {
public function getName() {
return pht('Paste');
}
public function getBaseURI() {
return '/paste/';
}
- public function getFontIcon() {
+ public function getIcon() {
return 'fa-paste';
}
public function getTitleGlyph() {
return "\xE2\x9C\x8E";
}
public function getApplicationGroup() {
return self::GROUP_UTILITIES;
}
public function getShortDescription() {
return pht('Share Text Snippets');
}
public function getRemarkupRules() {
return array(
new PhabricatorPasteRemarkupRule(),
);
}
public function getRoutes() {
return array(
'/P(?P<id>[1-9]\d*)(?:\$(?P<lines>\d+(?:-\d+)?))?'
=> 'PhabricatorPasteViewController',
'/paste/' => array(
'(query/(?P<queryKey>[^/]+)/)?' => 'PhabricatorPasteListController',
'create/' => 'PhabricatorPasteEditController',
$this->getEditRoutePattern('edit/') => 'PhabricatorPasteEditController',
'raw/(?P<id>[1-9]\d*)/' => 'PhabricatorPasteRawController',
'archive/(?P<id>[1-9]\d*)/' => 'PhabricatorPasteArchiveController',
),
);
}
public function supportsEmailIntegration() {
return true;
}
public function getAppEmailBlurb() {
return pht(
'Send email to these addresses to create pastes. %s',
phutil_tag(
'a',
array(
'href' => $this->getInboundEmailSupportLink(),
),
pht('Learn More')));
}
protected function getCustomCapabilities() {
return array(
PasteDefaultViewCapability::CAPABILITY => array(
'caption' => pht('Default view policy for newly created pastes.'),
'template' => PhabricatorPastePastePHIDType::TYPECONST,
'capability' => PhabricatorPolicyCapability::CAN_VIEW,
),
PasteDefaultEditCapability::CAPABILITY => array(
'caption' => pht('Default edit policy for newly created pastes.'),
'template' => PhabricatorPastePastePHIDType::TYPECONST,
'capability' => PhabricatorPolicyCapability::CAN_EDIT,
),
);
}
public function getQuickCreateItems(PhabricatorUser $viewer) {
return id(new PhabricatorPasteEditEngine())
->setViewer($viewer)
->loadQuickCreateItems();
}
public function getMailCommandObjects() {
return array(
'paste' => array(
'name' => pht('Email Commands: Pastes'),
'header' => pht('Interacting with Pastes'),
'object' => new PhabricatorPaste(),
'summary' => pht(
'This page documents the commands you can use to interact with '.
'pastes.'),
),
);
}
}
diff --git a/src/applications/paste/config/PhabricatorPasteConfigOptions.php b/src/applications/paste/config/PhabricatorPasteConfigOptions.php
index bb970905c4..15b32eeb04 100644
--- a/src/applications/paste/config/PhabricatorPasteConfigOptions.php
+++ b/src/applications/paste/config/PhabricatorPasteConfigOptions.php
@@ -1,32 +1,32 @@
<?php
final class PhabricatorPasteConfigOptions
extends PhabricatorApplicationConfigOptions {
public function getName() {
return pht('Paste');
}
public function getDescription() {
return pht('Configure Paste.');
}
- public function getFontIcon() {
+ public function getIcon() {
return 'fa-paste';
}
public function getGroup() {
return 'apps';
}
public function getOptions() {
return array(
$this->newOption(
'metamta.paste.subject-prefix',
'string',
'[Paste]')
->setDescription(pht('Subject prefix for Paste email.')),
);
}
}
diff --git a/src/applications/paste/query/PhabricatorPasteSearchEngine.php b/src/applications/paste/query/PhabricatorPasteSearchEngine.php
index fdf7824f07..da1f04ae09 100644
--- a/src/applications/paste/query/PhabricatorPasteSearchEngine.php
+++ b/src/applications/paste/query/PhabricatorPasteSearchEngine.php
@@ -1,224 +1,224 @@
<?php
final class PhabricatorPasteSearchEngine
extends PhabricatorApplicationSearchEngine {
public function getResultTypeDescription() {
return pht('Pastes');
}
public function getApplicationClassName() {
return 'PhabricatorPasteApplication';
}
public function newQuery() {
return id(new PhabricatorPasteQuery())
->needSnippets(true);
}
protected function buildQueryFromParameters(array $map) {
$query = $this->newQuery();
if ($map['authorPHIDs']) {
$query->withAuthorPHIDs($map['authorPHIDs']);
}
if ($map['languages']) {
$query->withLanguages($map['languages']);
}
if ($map['createdStart']) {
$query->withDateCreatedAfter($map['createdStart']);
}
if ($map['createdEnd']) {
$query->withDateCreatedBefore($map['createdEnd']);
}
if ($map['statuses']) {
$query->withStatuses($map['statuses']);
}
return $query;
}
protected function buildCustomSearchFields() {
return array(
id(new PhabricatorUsersSearchField())
->setAliases(array('authors'))
->setKey('authorPHIDs')
->setConduitKey('authors')
->setLabel(pht('Authors'))
->setDescription(
pht('Search for pastes with specific authors.')),
id(new PhabricatorSearchStringListField())
->setKey('languages')
->setLabel(pht('Languages'))
->setDescription(
pht('Search for pastes highlighted in specific languages.')),
id(new PhabricatorSearchDateField())
->setKey('createdStart')
->setLabel(pht('Created After'))
->setDescription(
pht('Search for pastes created after a given time.')),
id(new PhabricatorSearchDateField())
->setKey('createdEnd')
->setLabel(pht('Created Before'))
->setDescription(
pht('Search for pastes created before a given time.')),
id(new PhabricatorSearchCheckboxesField())
->setKey('statuses')
->setLabel(pht('Status'))
->setDescription(
pht('Search for archived or active pastes.'))
->setOptions(
id(new PhabricatorPaste())
->getStatusNameMap()),
);
}
protected function getDefaultFieldOrder() {
return array(
'...',
'createdStart',
'createdEnd',
);
}
protected function getURI($path) {
return '/paste/'.$path;
}
protected function getBuiltinQueryNames() {
$names = array(
'active' => pht('Active Pastes'),
'all' => pht('All Pastes'),
);
if ($this->requireViewer()->isLoggedIn()) {
$names['authored'] = pht('Authored');
}
return $names;
}
public function buildSavedQueryFromBuiltin($query_key) {
$query = $this->newSavedQuery();
$query->setQueryKey($query_key);
switch ($query_key) {
case 'active':
return $query->setParameter(
'statuses',
array(
PhabricatorPaste::STATUS_ACTIVE,
));
case 'all':
return $query;
case 'authored':
return $query->setParameter(
'authorPHIDs',
array($this->requireViewer()->getPHID()));
}
return parent::buildSavedQueryFromBuiltin($query_key);
}
protected function getRequiredHandlePHIDsForResultList(
array $pastes,
PhabricatorSavedQuery $query) {
return mpull($pastes, 'getAuthorPHID');
}
protected function renderResultList(
array $pastes,
PhabricatorSavedQuery $query,
array $handles) {
assert_instances_of($pastes, 'PhabricatorPaste');
$viewer = $this->requireViewer();
$lang_map = PhabricatorEnv::getEnvConfig('pygments.dropdown-choices');
$list = new PHUIObjectItemListView();
$list->setUser($viewer);
foreach ($pastes as $paste) {
$created = phabricator_date($paste->getDateCreated(), $viewer);
$author = $handles[$paste->getAuthorPHID()]->renderLink();
$snippet_type = $paste->getSnippet()->getType();
$lines = phutil_split_lines($paste->getSnippet()->getContent());
$preview = id(new PhabricatorSourceCodeView())
->setLines($lines)
->setTruncatedFirstBytes(
$snippet_type == PhabricatorPasteSnippet::FIRST_BYTES)
->setTruncatedFirstLines(
$snippet_type == PhabricatorPasteSnippet::FIRST_LINES)
->setURI(new PhutilURI($paste->getURI()));
$source_code = phutil_tag(
'div',
array(
'class' => 'phabricator-source-code-summary',
),
$preview);
$created = phabricator_datetime($paste->getDateCreated(), $viewer);
$line_count = count($lines);
$line_count = pht(
'%s Line(s)',
new PhutilNumber($line_count));
$title = nonempty($paste->getTitle(), pht('(An Untitled Masterwork)'));
$item = id(new PHUIObjectItemView())
->setObjectName('P'.$paste->getID())
->setHeader($title)
->setHref('/P'.$paste->getID())
->setObject($paste)
->addByline(pht('Author: %s', $author))
->addIcon('none', $created)
->addIcon('none', $line_count)
->appendChild($source_code);
if ($paste->isArchived()) {
$item->setDisabled(true);
}
$lang_name = $paste->getLanguage();
if ($lang_name) {
$lang_name = idx($lang_map, $lang_name, $lang_name);
$item->addIcon('none', $lang_name);
}
$list->addItem($item);
}
$result = new PhabricatorApplicationSearchResultView();
$result->setObjectList($list);
$result->setNoDataString(pht('No pastes found.'));
return $result;
}
protected function getNewUserBody() {
$create_button = id(new PHUIButtonView())
->setTag('a')
->setText(pht('Create a Paste'))
->setHref('/paste/create/')
->setColor(PHUIButtonView::GREEN);
- $icon = $this->getApplication()->getFontIcon();
+ $icon = $this->getApplication()->getIcon();
$app_name = $this->getApplication()->getName();
$view = id(new PHUIBigInfoView())
->setIcon($icon)
->setTitle(pht('Welcome to %s', $app_name))
->setDescription(
pht('Store, share, and embed snippets of code.'))
->addAction($create_button);
return $view;
}
}
diff --git a/src/applications/people/application/PhabricatorPeopleApplication.php b/src/applications/people/application/PhabricatorPeopleApplication.php
index 695669ea7c..c4bc87ea5a 100644
--- a/src/applications/people/application/PhabricatorPeopleApplication.php
+++ b/src/applications/people/application/PhabricatorPeopleApplication.php
@@ -1,161 +1,161 @@
<?php
final class PhabricatorPeopleApplication extends PhabricatorApplication {
public function getName() {
return pht('People');
}
public function getShortDescription() {
return pht('User Accounts and Profiles');
}
public function getBaseURI() {
return '/people/';
}
public function getTitleGlyph() {
return "\xE2\x99\x9F";
}
- public function getFontIcon() {
+ public function getIcon() {
return 'fa-users';
}
public function isPinnedByDefault(PhabricatorUser $viewer) {
return $viewer->getIsAdmin();
}
public function getFlavorText() {
return pht('Sort of a social utility.');
}
public function canUninstall() {
return false;
}
public function getRoutes() {
return array(
'/people/' => array(
'(query/(?P<key>[^/]+)/)?' => 'PhabricatorPeopleListController',
'logs/(?:query/(?P<queryKey>[^/]+)/)?'
=> 'PhabricatorPeopleLogsController',
'invite/' => array(
'(?:query/(?P<queryKey>[^/]+)/)?'
=> 'PhabricatorPeopleInviteListController',
'send/'
=> 'PhabricatorPeopleInviteSendController',
),
'approve/(?P<id>[1-9]\d*)/' => 'PhabricatorPeopleApproveController',
'(?P<via>disapprove)/(?P<id>[1-9]\d*)/'
=> 'PhabricatorPeopleDisableController',
'(?P<via>disable)/(?P<id>[1-9]\d*)/'
=> 'PhabricatorPeopleDisableController',
'empower/(?P<id>[1-9]\d*)/' => 'PhabricatorPeopleEmpowerController',
'delete/(?P<id>[1-9]\d*)/' => 'PhabricatorPeopleDeleteController',
'rename/(?P<id>[1-9]\d*)/' => 'PhabricatorPeopleRenameController',
'welcome/(?P<id>[1-9]\d*)/' => 'PhabricatorPeopleWelcomeController',
'create/' => 'PhabricatorPeopleCreateController',
'new/(?P<type>[^/]+)/' => 'PhabricatorPeopleNewController',
'ldap/' => 'PhabricatorPeopleLdapController',
'editprofile/(?P<id>[1-9]\d*)/' =>
'PhabricatorPeopleProfileEditController',
'picture/(?P<id>[1-9]\d*)/' =>
'PhabricatorPeopleProfilePictureController',
'manage/(?P<id>[1-9]\d*)/' =>
'PhabricatorPeopleProfileManageController',
),
'/p/(?P<username>[\w._-]+)/' => array(
'' => 'PhabricatorPeopleProfileViewController',
'panel/'
=> $this->getPanelRouting('PhabricatorPeopleProfilePanelController'),
'calendar/' => 'PhabricatorPeopleCalendarController',
),
);
}
public function getRemarkupRules() {
return array(
new PhabricatorMentionRemarkupRule(),
);
}
protected function getCustomCapabilities() {
return array(
PeopleCreateUsersCapability::CAPABILITY => array(
'default' => PhabricatorPolicies::POLICY_ADMIN,
),
PeopleBrowseUserDirectoryCapability::CAPABILITY => array(),
);
}
public function loadStatus(PhabricatorUser $user) {
if (!$user->getIsAdmin()) {
return array();
}
$limit = self::MAX_STATUS_ITEMS;
$need_approval = id(new PhabricatorPeopleQuery())
->setViewer($user)
->withIsApproved(false)
->withIsDisabled(false)
->setLimit($limit)
->execute();
if (!$need_approval) {
return array();
}
$status = array();
$count = count($need_approval);
if ($count >= $limit) {
$count_str = pht(
'%s+ User(s) Need Approval',
new PhutilNumber($limit - 1));
} else {
$count_str = pht(
'%s User(s) Need Approval',
new PhutilNumber($count));
}
$type = PhabricatorApplicationStatusView::TYPE_NEEDS_ATTENTION;
$status[] = id(new PhabricatorApplicationStatusView())
->setType($type)
->setText($count_str)
->setCount($count);
return $status;
}
public function getQuickCreateItems(PhabricatorUser $viewer) {
$items = array();
$can_create = PhabricatorPolicyFilter::hasCapability(
$viewer,
$this,
PeopleCreateUsersCapability::CAPABILITY);
if ($can_create) {
$item = id(new PHUIListItemView())
->setName(pht('User Account'))
->setIcon('fa-users')
->setHref($this->getBaseURI().'create/');
$items[] = $item;
} else if ($viewer->getIsAdmin()) {
$item = id(new PHUIListItemView())
->setName(pht('Bot Account'))
->setIcon('fa-android')
->setHref($this->getBaseURI().'new/bot/');
$items[] = $item;
}
return $items;
}
public function getApplicationSearchDocumentTypes() {
return array(
PhabricatorPeopleUserPHIDType::TYPECONST,
);
}
}
diff --git a/src/applications/people/config/PhabricatorUserConfigOptions.php b/src/applications/people/config/PhabricatorUserConfigOptions.php
index c5eefeaa9f..79be912699 100644
--- a/src/applications/people/config/PhabricatorUserConfigOptions.php
+++ b/src/applications/people/config/PhabricatorUserConfigOptions.php
@@ -1,58 +1,58 @@
<?php
final class PhabricatorUserConfigOptions
extends PhabricatorApplicationConfigOptions {
public function getName() {
return pht('User Profiles');
}
public function getDescription() {
return pht('User profiles configuration.');
}
- public function getFontIcon() {
+ public function getIcon() {
return 'fa-users';
}
public function getGroup() {
return 'apps';
}
public function getOptions() {
$default = array(
id(new PhabricatorUserRealNameField())->getFieldKey() => true,
id(new PhabricatorUserTitleField())->getFieldKey() => true,
id(new PhabricatorUserIconField())->getFieldKey() => true,
id(new PhabricatorUserSinceField())->getFieldKey() => true,
id(new PhabricatorUserRolesField())->getFieldKey() => true,
id(new PhabricatorUserStatusField())->getFieldKey() => true,
id(new PhabricatorUserBlurbField())->getFieldKey() => true,
);
foreach ($default as $key => $enabled) {
$default[$key] = array(
'disabled' => !$enabled,
);
}
$custom_field_type = 'custom:PhabricatorCustomFieldConfigOptionType';
return array(
$this->newOption('user.fields', $custom_field_type, $default)
->setCustomData(id(new PhabricatorUser())->getCustomFieldBaseClass())
->setDescription(pht('Select and reorder user profile fields.')),
$this->newOption('user.custom-field-definitions', 'map', array())
->setDescription(pht('Add new simple fields to user profiles.')),
$this->newOption('user.require-real-name', 'bool', true)
->setDescription(pht('Always require real name for user profiles.'))
->setBoolOptions(
array(
pht('Make real names required'),
pht('Make real names optional'),
)),
);
}
}
diff --git a/src/applications/phame/application/PhabricatorPhameApplication.php b/src/applications/phame/application/PhabricatorPhameApplication.php
index 1a49c95277..637b51a66c 100644
--- a/src/applications/phame/application/PhabricatorPhameApplication.php
+++ b/src/applications/phame/application/PhabricatorPhameApplication.php
@@ -1,115 +1,115 @@
<?php
final class PhabricatorPhameApplication extends PhabricatorApplication {
public function getName() {
return pht('Phame');
}
public function getBaseURI() {
return '/phame/';
}
- public function getFontIcon() {
+ public function getIcon() {
return 'fa-star';
}
public function getShortDescription() {
return pht('Blog');
}
public function getTitleGlyph() {
return "\xe2\x9c\xa9";
}
public function getHelpDocumentationArticles(PhabricatorUser $viewer) {
return array(
array(
'name' => pht('Phame User Guide'),
'href' => PhabricatorEnv::getDoclink('Phame User Guide'),
),
);
}
public function isPrototype() {
return true;
}
public function getRoutes() {
return array(
'/phame/' => array(
'' => 'PhameHomeController',
// NOTE: The live routes include an initial "/", so leave it off
// this route.
'(?P<live>live)/(?P<blogID>\d+)' => $this->getLiveRoutes(),
'post/' => array(
'(?:query/(?P<queryKey>[^/]+)/)?' => 'PhamePostListController',
'blogger/(?P<bloggername>[\w\.-_]+)/' => 'PhamePostListController',
'edit/(?:(?P<id>[^/]+)/)?' => 'PhamePostEditController',
'history/(?P<id>\d+)/' => 'PhamePostHistoryController',
'view/(?P<id>\d+)/(?:(?P<slug>[^/]+)/)?' => 'PhamePostViewController',
'(?P<action>publish|unpublish)/(?P<id>\d+)/'
=> 'PhamePostPublishController',
'preview/(?P<id>\d+)/' => 'PhamePostPreviewController',
'preview/' => 'PhabricatorMarkupPreviewController',
'framed/(?P<id>\d+)/' => 'PhamePostFramedController',
'move/(?P<id>\d+)/' => 'PhamePostMoveController',
'comment/(?P<id>[1-9]\d*)/' => 'PhamePostCommentController',
),
'blog/' => array(
'(?:query/(?P<queryKey>[^/]+)/)?' => 'PhameBlogListController',
'archive/(?P<id>[^/]+)/' => 'PhameBlogArchiveController',
'edit/(?P<id>[^/]+)/' => 'PhameBlogEditController',
'view/(?P<blogID>\d+)/' => 'PhameBlogViewController',
'manage/(?P<id>[^/]+)/' => 'PhameBlogManageController',
'feed/(?P<id>[^/]+)/' => 'PhameBlogFeedController',
'new/' => 'PhameBlogEditController',
'picture/(?P<id>[1-9]\d*)/' => 'PhameBlogProfilePictureController',
),
) + $this->getResourceSubroutes(),
);
}
public function getResourceRoutes() {
return array(
'/phame/' => $this->getResourceSubroutes(),
);
}
private function getResourceSubroutes() {
return array(
'r/(?P<id>\d+)/(?P<hash>[^/]+)/(?P<name>.*)' =>
'PhameResourceController',
);
}
public function getBlogRoutes() {
return $this->getLiveRoutes();
}
private function getLiveRoutes() {
return array(
'/' => array(
'' => 'PhameBlogViewController',
'post/(?P<id>\d+)/(?:(?P<slug>[^/]+)/)?' => 'PhamePostViewController',
),
);
}
public function getQuicksandURIPatternBlacklist() {
return array(
'/phame/live/.*',
);
}
protected function getCustomCapabilities() {
return array(
PhameBlogCreateCapability::CAPABILITY => array(
'default' => PhabricatorPolicies::POLICY_USER,
'caption' => pht('Default create policy for blogs.'),
),
);
}
}
diff --git a/src/applications/phid/type/PhabricatorPHIDType.php b/src/applications/phid/type/PhabricatorPHIDType.php
index e39ff5f562..99deb84763 100644
--- a/src/applications/phid/type/PhabricatorPHIDType.php
+++ b/src/applications/phid/type/PhabricatorPHIDType.php
@@ -1,197 +1,197 @@
<?php
abstract class PhabricatorPHIDType extends Phobject {
final public function getTypeConstant() {
$const = $this->getPhobjectClassConstant('TYPECONST');
if (!is_string($const) || !preg_match('/^[A-Z]{4}$/', $const)) {
throw new Exception(
pht(
'%s class "%s" has an invalid %s property. PHID '.
'constants must be a four character uppercase string.',
__CLASS__,
get_class($this),
'TYPECONST'));
}
return $const;
}
abstract public function getTypeName();
public function getTypeIcon() {
// Default to the application icon if the type doesn't specify one.
$application_class = $this->getPHIDTypeApplicationClass();
if ($application_class) {
$application = newv($application_class, array());
- return $application->getFontIcon();
+ return $application->getIcon();
}
return null;
}
public function newObject() {
return null;
}
/**
* Get the class name for the application this type belongs to.
*
* @return string|null Class name of the corresponding application, or null
* if the type is not bound to an application.
*/
abstract public function getPHIDTypeApplicationClass();
/**
* Build a @{class:PhabricatorPolicyAwareQuery} to load objects of this type
* by PHID.
*
* If you can not build a single query which satisfies this requirement, you
* can provide a dummy implementation for this method and overload
* @{method:loadObjects} instead.
*
* @param PhabricatorObjectQuery Query being executed.
* @param list<phid> PHIDs to load.
* @return PhabricatorPolicyAwareQuery Query object which loads the
* specified PHIDs when executed.
*/
abstract protected function buildQueryForObjects(
PhabricatorObjectQuery $query,
array $phids);
/**
* Load objects of this type, by PHID. For most PHID types, it is only
* necessary to implement @{method:buildQueryForObjects} to get object
* loading to work.
*
* @param PhabricatorObjectQuery Query being executed.
* @param list<phid> PHIDs to load.
* @return list<wild> Corresponding objects.
*/
public function loadObjects(
PhabricatorObjectQuery $query,
array $phids) {
$object_query = $this->buildQueryForObjects($query, $phids)
->setViewer($query->getViewer())
->setParentQuery($query);
// If the user doesn't have permission to use the application at all,
// just mark all the PHIDs as filtered. This primarily makes these
// objects show up as "Restricted" instead of "Unknown" when loaded as
// handles, which is technically true.
if (!$object_query->canViewerUseQueryApplication()) {
$object_query->addPolicyFilteredPHIDs(array_fuse($phids));
return array();
}
return $object_query->execute();
}
/**
* Populate provided handles with application-specific data, like titles and
* URIs.
*
* NOTE: The `$handles` and `$objects` lists are guaranteed to be nonempty
* and have the same keys: subclasses are expected to load information only
* for handles with visible objects.
*
* Because of this guarantee, a safe implementation will typically look like*
*
* foreach ($handles as $phid => $handle) {
* $object = $objects[$phid];
*
* $handle->setStuff($object->getStuff());
* // ...
* }
*
* In general, an implementation should call `setName()` and `setURI()` on
* each handle at a minimum. See @{class:PhabricatorObjectHandle} for other
* handle properties.
*
* @param PhabricatorHandleQuery Issuing query object.
* @param list<PhabricatorObjectHandle> Handles to populate with data.
* @param list<Object> Objects for these PHIDs loaded by
* @{method:buildQueryForObjects()}.
* @return void
*/
abstract public function loadHandles(
PhabricatorHandleQuery $query,
array $handles,
array $objects);
public function canLoadNamedObject($name) {
return false;
}
public function loadNamedObjects(
PhabricatorObjectQuery $query,
array $names) {
throw new PhutilMethodNotImplementedException();
}
/**
* Get all known PHID types.
*
* To get PHID types a given user has access to, see
* @{method:getAllInstalledTypes}.
*
* @return dict<string, PhabricatorPHIDType> Map of type constants to types.
*/
final public static function getAllTypes() {
return id(new PhutilClassMapQuery())
->setAncestorClass(__CLASS__)
->setUniqueMethod('getTypeConstant')
->execute();
}
/**
* Get all PHID types of applications installed for a given viewer.
*
* @param PhabricatorUser Viewing user.
* @return dict<string, PhabricatorPHIDType> Map of constants to installed
* types.
*/
public static function getAllInstalledTypes(PhabricatorUser $viewer) {
$all_types = self::getAllTypes();
$installed_types = array();
$app_classes = array();
foreach ($all_types as $key => $type) {
$app_class = $type->getPHIDTypeApplicationClass();
if ($app_class === null) {
// If the PHID type isn't bound to an application, include it as
// installed.
$installed_types[$key] = $type;
continue;
}
// Otherwise, we need to check if this application is installed before
// including the PHID type.
$app_classes[$app_class][$key] = $type;
}
if ($app_classes) {
$apps = id(new PhabricatorApplicationQuery())
->setViewer($viewer)
->withInstalled(true)
->withClasses(array_keys($app_classes))
->execute();
foreach ($apps as $app_class => $app) {
$installed_types += $app_classes[$app_class];
}
}
return $installed_types;
}
}
diff --git a/src/applications/phlux/application/PhabricatorPhluxApplication.php b/src/applications/phlux/application/PhabricatorPhluxApplication.php
index aabd7c9d1a..cc0e1a750b 100644
--- a/src/applications/phlux/application/PhabricatorPhluxApplication.php
+++ b/src/applications/phlux/application/PhabricatorPhluxApplication.php
@@ -1,43 +1,43 @@
<?php
final class PhabricatorPhluxApplication extends PhabricatorApplication {
public function getName() {
return pht('Phlux');
}
public function getBaseURI() {
return '/phlux/';
}
public function getShortDescription() {
return pht('Key/Value Configuration Store');
}
- public function getFontIcon() {
+ public function getIcon() {
return 'fa-copy';
}
public function getTitleGlyph() {
return "\xE2\x98\xBD";
}
public function getApplicationGroup() {
return self::GROUP_UTILITIES;
}
public function isPrototype() {
return true;
}
public function getRoutes() {
return array(
'/phlux/' => array(
'' => 'PhluxListController',
'view/(?P<key>[^/]+)/' => 'PhluxViewController',
'edit/(?:(?P<key>[^/]+)/)?' => 'PhluxEditController',
),
);
}
}
diff --git a/src/applications/pholio/application/PhabricatorPholioApplication.php b/src/applications/pholio/application/PhabricatorPholioApplication.php
index 16b868b9a1..ceb1e36638 100644
--- a/src/applications/pholio/application/PhabricatorPholioApplication.php
+++ b/src/applications/pholio/application/PhabricatorPholioApplication.php
@@ -1,106 +1,106 @@
<?php
final class PhabricatorPholioApplication extends PhabricatorApplication {
public function getName() {
return pht('Pholio');
}
public function getBaseURI() {
return '/pholio/';
}
public function getShortDescription() {
return pht('Review Mocks and Design');
}
- public function getFontIcon() {
+ public function getIcon() {
return 'fa-camera-retro';
}
public function getTitleGlyph() {
return "\xE2\x9D\xA6";
}
public function getFlavorText() {
return pht('Things before they were cool.');
}
public function getEventListeners() {
return array(
new PholioActionMenuEventListener(),
);
}
public function getRemarkupRules() {
return array(
new PholioRemarkupRule(),
);
}
public function getRoutes() {
return array(
'/M(?P<id>[1-9]\d*)(?:/(?P<imageID>\d+)/)?' => 'PholioMockViewController',
'/pholio/' => array(
'(?:query/(?P<queryKey>[^/]+)/)?' => 'PholioMockListController',
'new/' => 'PholioMockEditController',
'create/' => 'PholioMockEditController',
'edit/(?P<id>\d+)/' => 'PholioMockEditController',
'archive/(?P<id>\d+)/' => 'PholioMockArchiveController',
'comment/(?P<id>\d+)/' => 'PholioMockCommentController',
'inline/' => array(
'(?:(?P<id>\d+)/)?' => 'PholioInlineController',
'list/(?P<id>\d+)/' => 'PholioInlineListController',
),
'image/' => array(
'upload/' => 'PholioImageUploadController',
),
),
);
}
public function getQuickCreateItems(PhabricatorUser $viewer) {
$items = array();
$item = id(new PHUIListItemView())
->setName(pht('Pholio Mock'))
->setIcon('fa-picture-o')
->setHref($this->getBaseURI().'create/');
$items[] = $item;
return $items;
}
protected function getCustomCapabilities() {
return array(
PholioDefaultViewCapability::CAPABILITY => array(
'template' => PholioMockPHIDType::TYPECONST,
'capability' => PhabricatorPolicyCapability::CAN_VIEW,
),
PholioDefaultEditCapability::CAPABILITY => array(
'template' => PholioMockPHIDType::TYPECONST,
'capability' => PhabricatorPolicyCapability::CAN_EDIT,
),
);
}
public function getMailCommandObjects() {
return array(
'mock' => array(
'name' => pht('Email Commands: Mocks'),
'header' => pht('Interacting with Pholio Mocks'),
'object' => new PholioMock(),
'summary' => pht(
'This page documents the commands you can use to interact with '.
'mocks in Pholio.'),
),
);
}
public function getApplicationSearchDocumentTypes() {
return array(
PholioMockPHIDType::TYPECONST,
);
}
}
diff --git a/src/applications/pholio/config/PhabricatorPholioConfigOptions.php b/src/applications/pholio/config/PhabricatorPholioConfigOptions.php
index db079a4b2b..30bea98554 100644
--- a/src/applications/pholio/config/PhabricatorPholioConfigOptions.php
+++ b/src/applications/pholio/config/PhabricatorPholioConfigOptions.php
@@ -1,29 +1,29 @@
<?php
final class PhabricatorPholioConfigOptions
extends PhabricatorApplicationConfigOptions {
public function getName() {
return pht('Pholio');
}
public function getDescription() {
return pht('Configure Pholio.');
}
- public function getFontIcon() {
+ public function getIcon() {
return 'fa-camera-retro';
}
public function getGroup() {
return 'apps';
}
public function getOptions() {
return array(
$this->newOption('metamta.pholio.subject-prefix', 'string', '[Pholio]')
->setDescription(pht('Subject prefix for Pholio email.')),
);
}
}
diff --git a/src/applications/pholio/query/PholioMockSearchEngine.php b/src/applications/pholio/query/PholioMockSearchEngine.php
index 3c9d0b0d6b..2433484d69 100644
--- a/src/applications/pholio/query/PholioMockSearchEngine.php
+++ b/src/applications/pholio/query/PholioMockSearchEngine.php
@@ -1,153 +1,153 @@
<?php
final class PholioMockSearchEngine extends PhabricatorApplicationSearchEngine {
public function getResultTypeDescription() {
return pht('Pholio Mocks');
}
public function getApplicationClassName() {
return 'PhabricatorPholioApplication';
}
public function newQuery() {
return id(new PholioMockQuery())
->needCoverFiles(true)
->needImages(true)
->needTokenCounts(true);
}
protected function buildCustomSearchFields() {
return array(
id(new PhabricatorUsersSearchField())
->setKey('authorPHIDs')
->setAliases(array('authors'))
->setLabel(pht('Authors')),
id(new PhabricatorSearchCheckboxesField())
->setKey('statuses')
->setLabel(pht('Status'))
->setOptions(
id(new PholioMock())
->getStatuses()),
);
}
protected function buildQueryFromParameters(array $map) {
$query = $this->newQuery();
if ($map['authorPHIDs']) {
$query->withAuthorPHIDs($map['authorPHIDs']);
}
if ($map['statuses']) {
$query->withStatuses($map['statuses']);
}
return $query;
}
protected function getURI($path) {
return '/pholio/'.$path;
}
protected function getBuiltinQueryNames() {
$names = array(
'open' => pht('Open Mocks'),
'all' => pht('All Mocks'),
);
if ($this->requireViewer()->isLoggedIn()) {
$names['authored'] = pht('Authored');
}
return $names;
}
public function buildSavedQueryFromBuiltin($query_key) {
$query = $this->newSavedQuery();
$query->setQueryKey($query_key);
switch ($query_key) {
case 'open':
return $query->setParameter(
'statuses',
array('open'));
case 'all':
return $query;
case 'authored':
return $query->setParameter(
'authorPHIDs',
array($this->requireViewer()->getPHID()));
}
return parent::buildSavedQueryFromBuiltin($query_key);
}
protected function renderResultList(
array $mocks,
PhabricatorSavedQuery $query,
array $handles) {
assert_instances_of($mocks, 'PholioMock');
$viewer = $this->requireViewer();
$handles = $viewer->loadHandles(mpull($mocks, 'getAuthorPHID'));
$xform = PhabricatorFileTransform::getTransformByKey(
PhabricatorFileThumbnailTransform::TRANSFORM_PINBOARD);
$board = new PHUIPinboardView();
foreach ($mocks as $mock) {
$image = $mock->getCoverFile();
$image_uri = $image->getURIForTransform($xform);
list($x, $y) = $xform->getTransformedDimensions($image);
$header = 'M'.$mock->getID().' '.$mock->getName();
$item = id(new PHUIPinboardItemView())
->setUser($viewer)
->setHeader($header)
->setObject($mock)
->setURI('/M'.$mock->getID())
->setImageURI($image_uri)
->setImageSize($x, $y)
->setDisabled($mock->isClosed())
->addIconCount('fa-picture-o', count($mock->getImages()))
->addIconCount('fa-trophy', $mock->getTokenCount());
if ($mock->getAuthorPHID()) {
$author_handle = $handles[$mock->getAuthorPHID()];
$datetime = phabricator_date($mock->getDateCreated(), $viewer);
$item->appendChild(
pht('By %s on %s', $author_handle->renderLink(), $datetime));
}
$board->addItem($item);
}
$result = new PhabricatorApplicationSearchResultView();
$result->setContent($board);
return $result;
}
protected function getNewUserBody() {
$create_button = id(new PHUIButtonView())
->setTag('a')
->setText(pht('Create a Mock'))
->setHref('/pholio/create/')
->setColor(PHUIButtonView::GREEN);
- $icon = $this->getApplication()->getFontIcon();
+ $icon = $this->getApplication()->getIcon();
$app_name = $this->getApplication()->getName();
$view = id(new PHUIBigInfoView())
->setIcon($icon)
->setTitle(pht('Welcome to %s', $app_name))
->setDescription(
pht('Upload sets of images for review with revision history and '.
'inline comments.'))
->addAction($create_button);
return $view;
}
}
diff --git a/src/applications/phortune/application/PhabricatorPhortuneApplication.php b/src/applications/phortune/application/PhabricatorPhortuneApplication.php
index cf7bc00b9a..470ceb10ab 100644
--- a/src/applications/phortune/application/PhabricatorPhortuneApplication.php
+++ b/src/applications/phortune/application/PhabricatorPhortuneApplication.php
@@ -1,121 +1,121 @@
<?php
final class PhabricatorPhortuneApplication extends PhabricatorApplication {
public function getName() {
return pht('Phortune');
}
public function getBaseURI() {
return '/phortune/';
}
public function getShortDescription() {
return pht('Accounts and Billing');
}
- public function getFontIcon() {
+ public function getIcon() {
return 'fa-diamond';
}
public function getTitleGlyph() {
return "\xE2\x97\x87";
}
public function getApplicationGroup() {
return self::GROUP_UTILITIES;
}
public function isPrototype() {
return true;
}
public function getRoutes() {
return array(
'/phortune/' => array(
'' => 'PhortuneLandingController',
'(?P<accountID>\d+)/' => array(
'' => 'PhortuneAccountViewController',
'card/' => array(
'new/' => 'PhortunePaymentMethodCreateController',
),
'order/(?:query/(?P<queryKey>[^/]+)/)?'
=> 'PhortuneCartListController',
'subscription/' => array(
'(?:query/(?P<queryKey>[^/]+)/)?'
=> 'PhortuneSubscriptionListController',
'view/(?P<id>\d+)/'
=> 'PhortuneSubscriptionViewController',
'edit/(?P<id>\d+)/'
=> 'PhortuneSubscriptionEditController',
'order/(?P<subscriptionID>\d+)/'
=> 'PhortuneCartListController',
),
'charge/(?:query/(?P<queryKey>[^/]+)/)?'
=> 'PhortuneChargeListController',
),
'card/(?P<id>\d+)/' => array(
'edit/' => 'PhortunePaymentMethodEditController',
'disable/' => 'PhortunePaymentMethodDisableController',
),
'cart/(?P<id>\d+)/' => array(
'' => 'PhortuneCartViewController',
'checkout/' => 'PhortuneCartCheckoutController',
'(?P<action>cancel|refund)/' => 'PhortuneCartCancelController',
'update/' => 'PhortuneCartUpdateController',
),
'account/' => array(
'' => 'PhortuneAccountListController',
'edit/(?:(?P<id>\d+)/)?' => 'PhortuneAccountEditController',
),
'product/' => array(
'' => 'PhortuneProductListController',
'view/(?P<id>\d+)/' => 'PhortuneProductViewController',
'edit/(?:(?P<id>\d+)/)?' => 'PhortuneProductEditController',
),
'provider/' => array(
'edit/(?:(?P<id>\d+)/)?' => 'PhortuneProviderEditController',
'disable/(?P<id>\d+)/' => 'PhortuneProviderDisableController',
'(?P<id>\d+)/(?P<action>[^/]+)/'
=> 'PhortuneProviderActionController',
),
'merchant/' => array(
'(?:query/(?P<queryKey>[^/]+)/)?' => 'PhortuneMerchantListController',
'edit/(?:(?P<id>\d+)/)?' => 'PhortuneMerchantEditController',
'orders/(?P<merchantID>\d+)/(?:query/(?P<queryKey>[^/]+)/)?'
=> 'PhortuneCartListController',
'(?P<merchantID>\d+)/' => array(
'cart/(?P<id>\d+)/' => array(
'' => 'PhortuneCartViewController',
'(?P<action>cancel|refund)/' => 'PhortuneCartCancelController',
'update/' => 'PhortuneCartUpdateController',
'accept/' => 'PhortuneCartAcceptController',
),
'subscription/' => array(
'(?:query/(?P<queryKey>[^/]+)/)?'
=> 'PhortuneSubscriptionListController',
'view/(?P<id>\d+)/'
=> 'PhortuneSubscriptionViewController',
'order/(?P<subscriptionID>\d+)/'
=> 'PhortuneCartListController',
),
'invoice/' => array(
'new/' => 'PhortuneMerchantInvoiceCreateController',
),
),
'(?P<id>\d+)/' => 'PhortuneMerchantViewController',
),
),
);
}
protected function getCustomCapabilities() {
return array(
PhortuneMerchantCapability::CAPABILITY => array(
'caption' => pht('Merchant accounts can receive payments.'),
'default' => PhabricatorPolicies::POLICY_ADMIN,
),
);
}
}
diff --git a/src/applications/phpast/application/PhabricatorPHPASTApplication.php b/src/applications/phpast/application/PhabricatorPHPASTApplication.php
index 3118ed68c9..c61a6bf115 100644
--- a/src/applications/phpast/application/PhabricatorPHPASTApplication.php
+++ b/src/applications/phpast/application/PhabricatorPHPASTApplication.php
@@ -1,47 +1,47 @@
<?php
final class PhabricatorPHPASTApplication extends PhabricatorApplication {
public function getName() {
return pht('PHPAST');
}
public function getBaseURI() {
return '/xhpast/';
}
- public function getFontIcon() {
+ public function getIcon() {
return 'fa-ambulance';
}
public function getShortDescription() {
return pht('Visual PHP Parser');
}
public function getTitleGlyph() {
return "\xE2\x96\xA0";
}
public function getApplicationGroup() {
return self::GROUP_DEVELOPER;
}
public function getRoutes() {
return array(
'/xhpast/' => array(
'' => 'PhabricatorXHPASTViewRunController',
'view/(?P<id>[1-9]\d*)/'
=> 'PhabricatorXHPASTViewFrameController',
'frameset/(?P<id>[1-9]\d*)/'
=> 'PhabricatorXHPASTViewFramesetController',
'input/(?P<id>[1-9]\d*)/'
=> 'PhabricatorXHPASTViewInputController',
'tree/(?P<id>[1-9]\d*)/'
=> 'PhabricatorXHPASTViewTreeController',
'stream/(?P<id>[1-9]\d*)/'
=> 'PhabricatorXHPASTViewStreamController',
),
);
}
}
diff --git a/src/applications/phragment/application/PhabricatorPhragmentApplication.php b/src/applications/phragment/application/PhabricatorPhragmentApplication.php
index 9463835811..c5959f715f 100644
--- a/src/applications/phragment/application/PhabricatorPhragmentApplication.php
+++ b/src/applications/phragment/application/PhabricatorPhragmentApplication.php
@@ -1,70 +1,70 @@
<?php
final class PhabricatorPhragmentApplication extends PhabricatorApplication {
public function getName() {
return pht('Phragment');
}
public function getBaseURI() {
return '/phragment/';
}
public function getShortDescription() {
return pht('Versioned Artifact Storage');
}
- public function getFontIcon() {
+ public function getIcon() {
return 'fa-floppy-o';
}
public function getTitleGlyph() {
return "\xE2\x26\xB6";
}
public function getApplicationGroup() {
return self::GROUP_UTILITIES;
}
public function isPrototype() {
return true;
}
public function canUninstall() {
return true;
}
public function getRoutes() {
return array(
'/phragment/' => array(
'' => 'PhragmentBrowseController',
'browse/(?P<dblob>.*)' => 'PhragmentBrowseController',
'create/(?P<dblob>.*)' => 'PhragmentCreateController',
'update/(?P<dblob>.+)' => 'PhragmentUpdateController',
'policy/(?P<dblob>.+)' => 'PhragmentPolicyController',
'history/(?P<dblob>.+)' => 'PhragmentHistoryController',
'zip/(?P<dblob>.+)' => 'PhragmentZIPController',
'zip@(?P<snapshot>[^/]+)/(?P<dblob>.+)' => 'PhragmentZIPController',
'version/(?P<id>[0-9]*)/' => 'PhragmentVersionController',
'patch/(?P<aid>[0-9x]*)/(?P<bid>[0-9]*)/' => 'PhragmentPatchController',
'revert/(?P<id>[0-9]*)/(?P<dblob>.*)' => 'PhragmentRevertController',
'snapshot/' => array(
'create/(?P<dblob>.*)' => 'PhragmentSnapshotCreateController',
'view/(?P<id>[0-9]*)/' => 'PhragmentSnapshotViewController',
'delete/(?P<id>[0-9]*)/' => 'PhragmentSnapshotDeleteController',
'promote/' => array(
'latest/(?P<dblob>.*)' => 'PhragmentSnapshotPromoteController',
'(?P<id>[0-9]*)/' => 'PhragmentSnapshotPromoteController',
),
),
),
);
}
protected function getCustomCapabilities() {
return array(
PhragmentCanCreateCapability::CAPABILITY => array(),
);
}
}
diff --git a/src/applications/phrequent/application/PhabricatorPhrequentApplication.php b/src/applications/phrequent/application/PhabricatorPhrequentApplication.php
index bded663ed9..023827c644 100644
--- a/src/applications/phrequent/application/PhabricatorPhrequentApplication.php
+++ b/src/applications/phrequent/application/PhabricatorPhrequentApplication.php
@@ -1,72 +1,72 @@
<?php
final class PhabricatorPhrequentApplication extends PhabricatorApplication {
public function getName() {
return pht('Phrequent');
}
public function getShortDescription() {
return pht('Track Time Spent');
}
public function getBaseURI() {
return '/phrequent/';
}
public function isPrototype() {
return true;
}
- public function getFontIcon() {
+ public function getIcon() {
return 'fa-clock-o';
}
public function getApplicationGroup() {
return self::GROUP_UTILITIES;
}
public function getApplicationOrder() {
return 0.110;
}
public function getEventListeners() {
return array(
new PhrequentUIEventListener(),
);
}
public function getRoutes() {
return array(
'/phrequent/' => array(
'(?:query/(?P<queryKey>[^/]+)/)?' => 'PhrequentListController',
'track/(?P<verb>[a-z]+)/(?P<phid>[^/]+)/'
=> 'PhrequentTrackController',
),
);
}
public function loadStatus(PhabricatorUser $user) {
$status = array();
$limit = self::MAX_STATUS_ITEMS;
// Show number of objects that are currently
// being tracked for a user.
$count = PhrequentUserTimeQuery::getUserTotalObjectsTracked($user, $limit);
if ($count >= $limit) {
$count_str = pht('%s+ Object(s) Tracked', new PhutilNumber($limit - 1));
} else {
$count_str = pht('%s Object(s) Tracked', new PhutilNumber($count));
}
$type = PhabricatorApplicationStatusView::TYPE_NEEDS_ATTENTION;
$status[] = id(new PhabricatorApplicationStatusView())
->setType($type)
->setText($count_str)
->setCount($count);
return $status;
}
}
diff --git a/src/applications/phrequent/config/PhabricatorPhrequentConfigOptions.php b/src/applications/phrequent/config/PhabricatorPhrequentConfigOptions.php
index a6113155a9..e1ba0adb54 100644
--- a/src/applications/phrequent/config/PhabricatorPhrequentConfigOptions.php
+++ b/src/applications/phrequent/config/PhabricatorPhrequentConfigOptions.php
@@ -1,26 +1,26 @@
<?php
final class PhabricatorPhrequentConfigOptions
extends PhabricatorApplicationConfigOptions {
public function getName() {
return pht('Phrequent');
}
public function getDescription() {
return pht('Configure Phrequent.');
}
- public function getFontIcon() {
+ public function getIcon() {
return 'fa-clock-o';
}
public function getGroup() {
return 'apps';
}
public function getOptions() {
return array();
}
}
diff --git a/src/applications/phriction/application/PhabricatorPhrictionApplication.php b/src/applications/phriction/application/PhabricatorPhrictionApplication.php
index 19967c2e70..7721749c36 100644
--- a/src/applications/phriction/application/PhabricatorPhrictionApplication.php
+++ b/src/applications/phriction/application/PhabricatorPhrictionApplication.php
@@ -1,78 +1,78 @@
<?php
final class PhabricatorPhrictionApplication extends PhabricatorApplication {
public function getName() {
return pht('Phriction');
}
public function getShortDescription() {
return pht('Wiki');
}
public function getBaseURI() {
return '/w/';
}
- public function getFontIcon() {
+ public function getIcon() {
return 'fa-book';
}
public function isPinnedByDefault(PhabricatorUser $viewer) {
return true;
}
public function getHelpDocumentationArticles(PhabricatorUser $viewer) {
return array(
array(
'name' => pht('Phriction User Guide'),
'href' => PhabricatorEnv::getDoclink('Phriction User Guide'),
),
);
}
public function getTitleGlyph() {
return "\xE2\x9A\xA1";
}
public function getRemarkupRules() {
return array(
new PhrictionRemarkupRule(),
);
}
public function getRoutes() {
return array(
// Match "/w/" with slug "/".
'/w(?P<slug>/)' => 'PhrictionDocumentController',
// Match "/w/x/y/z/" with slug "x/y/z/".
'/w/(?P<slug>.+/)' => 'PhrictionDocumentController',
'/phriction/' => array(
'(?:query/(?P<queryKey>[^/]+)/)?' => 'PhrictionListController',
'history(?P<slug>/)' => 'PhrictionHistoryController',
'history/(?P<slug>.+/)' => 'PhrictionHistoryController',
'edit/(?:(?P<id>[1-9]\d*)/)?' => 'PhrictionEditController',
'delete/(?P<id>[1-9]\d*)/' => 'PhrictionDeleteController',
'new/' => 'PhrictionNewController',
'move/(?P<id>[1-9]\d*)/' => 'PhrictionMoveController',
'preview/' => 'PhabricatorMarkupPreviewController',
'diff/(?P<id>[1-9]\d*)/' => 'PhrictionDiffController',
),
);
}
public function getApplicationOrder() {
return 0.140;
}
public function getApplicationSearchDocumentTypes() {
return array(
PhrictionDocumentPHIDType::TYPECONST,
);
}
}
diff --git a/src/applications/phriction/config/PhabricatorPhrictionConfigOptions.php b/src/applications/phriction/config/PhabricatorPhrictionConfigOptions.php
index 7e6080dd7c..9fada90d3a 100644
--- a/src/applications/phriction/config/PhabricatorPhrictionConfigOptions.php
+++ b/src/applications/phriction/config/PhabricatorPhrictionConfigOptions.php
@@ -1,30 +1,30 @@
<?php
final class PhabricatorPhrictionConfigOptions
extends PhabricatorApplicationConfigOptions {
public function getName() {
return pht('Phriction');
}
public function getDescription() {
return pht('Options related to Phriction (wiki).');
}
- public function getFontIcon() {
+ public function getIcon() {
return 'fa-book';
}
public function getGroup() {
return 'apps';
}
public function getOptions() {
return array(
$this->newOption(
'metamta.phriction.subject-prefix', 'string', '[Phriction]')
->setDescription(pht('Subject prefix for Phriction email.')),
);
}
}
diff --git a/src/applications/phurl/application/PhabricatorPhurlApplication.php b/src/applications/phurl/application/PhabricatorPhurlApplication.php
index 83952f6817..763a85173c 100644
--- a/src/applications/phurl/application/PhabricatorPhurlApplication.php
+++ b/src/applications/phurl/application/PhabricatorPhurlApplication.php
@@ -1,71 +1,71 @@
<?php
final class PhabricatorPhurlApplication extends PhabricatorApplication {
public function getName() {
return pht('Phurl');
}
public function getShortDescription() {
return pht('URL Shortener');
}
public function getFlavorText() {
return pht('Shorten your favorite URL.');
}
public function getBaseURI() {
return '/phurl/';
}
- public function getFontIcon() {
+ public function getIcon() {
return 'fa-compress';
}
public function isPrototype() {
return true;
}
public function getRemarkupRules() {
return array(
new PhabricatorPhurlRemarkupRule(),
new PhabricatorPhurlLinkRemarkupRule(),
);
}
public function getRoutes() {
return array(
'/U(?P<id>[1-9]\d*)/?' => 'PhabricatorPhurlURLViewController',
'/u/(?P<id>[1-9]\d*)/?' => 'PhabricatorPhurlURLAccessController',
'/u/(?P<alias>[^/]+)/?' => 'PhabricatorPhurlURLAccessController',
'/phurl/' => array(
'(?:query/(?P<queryKey>[^/]+)/)?'
=> 'PhabricatorPhurlURLListController',
'url/' => array(
'create/'
=> 'PhabricatorPhurlURLEditController',
'edit/(?P<id>[1-9]\d*)/'
=> 'PhabricatorPhurlURLEditController',
'comment/(?P<id>[1-9]\d*)/'
=> 'PhabricatorPhurlURLCommentController',
),
),
);
}
public function getShortRoutes() {
return array(
'/u/(?P<append>[^/]+)' => 'PhabricatorPhurlShortURLController',
'.*' => 'PhabricatorPhurlShortURLDefaultController',
);
}
protected function getCustomCapabilities() {
return array(
PhabricatorPhurlURLCreateCapability::CAPABILITY => array(
'default' => PhabricatorPolicies::POLICY_USER,
),
);
}
}
diff --git a/src/applications/phurl/query/PhabricatorPhurlURLSearchEngine.php b/src/applications/phurl/query/PhabricatorPhurlURLSearchEngine.php
index ed8a336c3a..c652cfffdf 100644
--- a/src/applications/phurl/query/PhabricatorPhurlURLSearchEngine.php
+++ b/src/applications/phurl/query/PhabricatorPhurlURLSearchEngine.php
@@ -1,113 +1,113 @@
<?php
final class PhabricatorPhurlURLSearchEngine
extends PhabricatorApplicationSearchEngine {
public function getResultTypeDescription() {
return pht('Shortened URLs');
}
public function getApplicationClassName() {
return 'PhabricatorPhurlApplication';
}
public function newQuery() {
return new PhabricatorPhurlURLQuery();
}
protected function shouldShowOrderField() {
return true;
}
protected function buildCustomSearchFields() {
return array(
id(new PhabricatorSearchDatasourceField())
->setLabel(pht('Created By'))
->setKey('authorPHIDs')
->setDatasource(new PhabricatorPeopleUserFunctionDatasource()),
);
}
protected function buildQueryFromParameters(array $map) {
$query = $this->newQuery();
if ($map['authorPHIDs']) {
$query->withAuthorPHIDs($map['authorPHIDs']);
}
return $query;
}
protected function getURI($path) {
return '/phurl/'.$path;
}
protected function getBuiltinQueryNames() {
$names = array(
'authored' => pht('Authored'),
'all' => pht('All URLs'),
);
return $names;
}
public function buildSavedQueryFromBuiltin($query_key) {
$query = $this->newSavedQuery();
$query->setQueryKey($query_key);
$viewer = $this->requireViewer();
switch ($query_key) {
case 'authored':
return $query->setParameter('authorPHIDs', array($viewer->getPHID()));
case 'all':
return $query;
}
return parent::buildSavedQueryFromBuiltin($query_key);
}
protected function renderResultList(
array $urls,
PhabricatorSavedQuery $query,
array $handles) {
assert_instances_of($urls, 'PhabricatorPhurlURL');
$viewer = $this->requireViewer();
$list = new PHUIObjectItemListView();
$handles = $viewer->loadHandles(mpull($urls, 'getAuthorPHID'));
foreach ($urls as $url) {
$item = id(new PHUIObjectItemView())
->setUser($viewer)
->setObject($url)
->setHeader($viewer->renderHandle($url->getPHID()));
$list->addItem($item);
}
$result = new PhabricatorApplicationSearchResultView();
$result->setObjectList($list);
$result->setNoDataString(pht('No URLs found.'));
return $result;
}
protected function getNewUserBody() {
$create_button = id(new PHUIButtonView())
->setTag('a')
->setText(pht('Shorten a URL'))
->setHref('/phurl/url/create/')
->setColor(PHUIButtonView::GREEN);
- $icon = $this->getApplication()->getFontIcon();
+ $icon = $this->getApplication()->getIcon();
$app_name = $this->getApplication()->getName();
$view = id(new PHUIBigInfoView())
->setIcon($icon)
->setTitle(pht('Welcome to %s', $app_name))
->setDescription(
pht('Create reusable, memorable, shorter URLs for easy accessibility.'))
->addAction($create_button);
return $view;
}
}
diff --git a/src/applications/policy/config/PhabricatorPolicyConfigOptions.php b/src/applications/policy/config/PhabricatorPolicyConfigOptions.php
index 1c3698c4cd..eacc32cebe 100644
--- a/src/applications/policy/config/PhabricatorPolicyConfigOptions.php
+++ b/src/applications/policy/config/PhabricatorPolicyConfigOptions.php
@@ -1,72 +1,72 @@
<?php
final class PhabricatorPolicyConfigOptions
extends PhabricatorApplicationConfigOptions {
public function getName() {
return pht('Policy');
}
public function getDescription() {
return pht('Options relating to object visibility.');
}
- public function getFontIcon() {
+ public function getIcon() {
return 'fa-lock';
}
public function getGroup() {
return 'apps';
}
public function getOptions() {
$policy_locked_type = 'custom:PolicyLockOptionType';
$policy_locked_example = array(
'people.create.users' => 'admin',
);
$json = new PhutilJSON();
$policy_locked_example = $json->encodeFormatted($policy_locked_example);
return array(
$this->newOption('policy.allow-public', 'bool', false)
->setBoolOptions(
array(
pht('Allow Public Visibility'),
pht('Require Login'),
))
->setSummary(pht('Allow users to set object visibility to public.'))
->setDescription(
pht(
"Phabricator allows you to set the visibility of objects (like ".
"repositories and tasks) to 'Public', which means **anyone ".
"on the internet can see them, without needing to log in or ".
"have an account**.".
"\n\n".
"This is intended for open source projects. Many installs will ".
"never want to make anything public, so this policy is disabled ".
"by default. You can enable it here, which will let you set the ".
"policy for objects to 'Public'.".
"\n\n".
"Enabling this setting will immediately open up some features, ".
"like the user directory. Anyone on the internet will be able to ".
"access these features.".
"\n\n".
"With this setting disabled, the 'Public' policy is not ".
"available, and the most open policy is 'All Users' (which means ".
"users must have accounts and be logged in to view things).")),
$this->newOption('policy.locked', $policy_locked_type, array())
->setLocked(true)
->setSummary(pht(
'Lock specific application policies so they can not be edited.'))
->setDescription(pht(
'Phabricator has application policies which can dictate whether '.
'users can take certain actions, such as creating new users. '."\n\n".
'This setting allows for "locking" these policies such that no '.
'further edits can be made on a per-policy basis.'))
->addExample(
$policy_locked_example,
pht('Lock Create User Policy To Admins')),
);
}
}
diff --git a/src/applications/ponder/application/PhabricatorPonderApplication.php b/src/applications/ponder/application/PhabricatorPonderApplication.php
index 886fddcc05..94a06edffa 100644
--- a/src/applications/ponder/application/PhabricatorPonderApplication.php
+++ b/src/applications/ponder/application/PhabricatorPonderApplication.php
@@ -1,103 +1,103 @@
<?php
final class PhabricatorPonderApplication extends PhabricatorApplication {
public function getBaseURI() {
return '/ponder/';
}
public function getName() {
return pht('Ponder');
}
public function getShortDescription() {
return pht('Questions and Answers');
}
- public function getFontIcon() {
+ public function getIcon() {
return 'fa-university';
}
public function getFactObjectsForAnalysis() {
return array(
new PonderQuestion(),
);
}
public function getTitleGlyph() {
return "\xE2\x97\xB3";
}
public function getRemarkupRules() {
return array(
new PonderRemarkupRule(),
);
}
public function getRoutes() {
return array(
'/Q(?P<id>[1-9]\d*)'
=> 'PonderQuestionViewController',
'/ponder/' => array(
'(?:query/(?P<queryKey>[^/]+)/)?'
=> 'PonderQuestionListController',
'answer/add/'
=> 'PonderAnswerSaveController',
'answer/edit/(?P<id>\d+)/'
=> 'PonderAnswerEditController',
'answer/comment/(?P<id>\d+)/'
=> 'PonderAnswerCommentController',
'answer/history/(?P<id>\d+)/'
=> 'PonderAnswerHistoryController',
'answer/helpful/(?P<action>add|remove)/(?P<id>[1-9]\d*)/'
=> 'PonderHelpfulSaveController',
'question/edit/(?:(?P<id>\d+)/)?'
=> 'PonderQuestionEditController',
'question/create/'
=> 'PonderQuestionEditController',
'question/comment/(?P<id>\d+)/'
=> 'PonderQuestionCommentController',
'question/history/(?P<id>\d+)/'
=> 'PonderQuestionHistoryController',
'preview/'
=> 'PhabricatorMarkupPreviewController',
'question/status/(?P<id>[1-9]\d*)/'
=> 'PonderQuestionStatusController',
),
);
}
public function getMailCommandObjects() {
return array(
'question' => array(
'name' => pht('Email Commands: Questions'),
'header' => pht('Interacting with Ponder Questions'),
'object' => new PonderQuestion(),
'summary' => pht(
'This page documents the commands you can use to interact with '.
'questions in Ponder.'),
),
);
}
protected function getCustomCapabilities() {
return array(
PonderDefaultViewCapability::CAPABILITY => array(
'template' => PonderQuestionPHIDType::TYPECONST,
'capability' => PhabricatorPolicyCapability::CAN_VIEW,
),
PonderModerateCapability::CAPABILITY => array(
'default' => PhabricatorPolicies::POLICY_ADMIN,
'template' => PonderQuestionPHIDType::TYPECONST,
'capability' => PhabricatorPolicyCapability::CAN_EDIT,
),
);
}
public function getApplicationSearchDocumentTypes() {
return array(
PonderQuestionPHIDType::TYPECONST,
);
}
}
diff --git a/src/applications/ponder/query/PonderQuestionSearchEngine.php b/src/applications/ponder/query/PonderQuestionSearchEngine.php
index 7e08a3fdf4..4cba28b93b 100644
--- a/src/applications/ponder/query/PonderQuestionSearchEngine.php
+++ b/src/applications/ponder/query/PonderQuestionSearchEngine.php
@@ -1,202 +1,202 @@
<?php
final class PonderQuestionSearchEngine
extends PhabricatorApplicationSearchEngine {
public function getResultTypeDescription() {
return pht('Ponder Questions');
}
public function getApplicationClassName() {
return 'PhabricatorPonderApplication';
}
public function newQuery() {
return id(new PonderQuestionQuery())
->needProjectPHIDs(true);
}
protected function buildQueryFromParameters(array $map) {
$query = $this->newQuery();
if ($map['authorPHIDs']) {
$query->withAuthorPHIDs($map['authorPHIDs']);
}
if ($map['answerers']) {
$query->withAnswererPHIDs($map['answerers']);
}
if ($map['statuses']) {
$query->withStatuses($map['statuses']);
}
return $query;
}
protected function buildCustomSearchFields() {
return array(
id(new PhabricatorUsersSearchField())
->setKey('authorPHIDs')
->setAliases(array('authors'))
->setLabel(pht('Authors')),
id(new PhabricatorUsersSearchField())
->setKey('answerers')
->setAliases(array('answerers'))
->setLabel(pht('Answered By')),
id(new PhabricatorSearchCheckboxesField())
->setLabel(pht('Status'))
->setKey('statuses')
->setOptions(PonderQuestionStatus::getQuestionStatusMap()),
);
}
protected function getURI($path) {
return '/ponder/'.$path;
}
protected function getBuiltinQueryNames() {
$names = array(
'recent' => pht('Recent Questions'),
'open' => pht('Open Questions'),
'resolved' => pht('Resolved Questions'),
'all' => pht('All Questions'),
);
if ($this->requireViewer()->isLoggedIn()) {
$names['authored'] = pht('Authored');
$names['answered'] = pht('Answered');
}
return $names;
}
public function buildSavedQueryFromBuiltin($query_key) {
$query = $this->newSavedQuery();
$query->setQueryKey($query_key);
switch ($query_key) {
case 'all':
return $query;
case 'open':
return $query->setParameter(
'statuses', array(PonderQuestionStatus::STATUS_OPEN));
case 'recent':
return $query->setParameter(
'statuses', array(
PonderQuestionStatus::STATUS_OPEN,
PonderQuestionStatus::STATUS_CLOSED_RESOLVED,
));
case 'resolved':
return $query->setParameter(
'statuses', array(PonderQuestionStatus::STATUS_CLOSED_RESOLVED));
case 'authored':
return $query->setParameter(
'authorPHIDs',
array($this->requireViewer()->getPHID()));
case 'answered':
return $query->setParameter(
'answerers',
array($this->requireViewer()->getPHID()));
}
return parent::buildSavedQueryFromBuiltin($query_key);
}
protected function getRequiredHandlePHIDsForResultList(
array $questions,
PhabricatorSavedQuery $query) {
return mpull($questions, 'getAuthorPHID');
}
protected function renderResultList(
array $questions,
PhabricatorSavedQuery $query,
array $handles) {
assert_instances_of($questions, 'PonderQuestion');
$viewer = $this->requireViewer();
$proj_phids = array();
foreach ($questions as $question) {
foreach ($question->getProjectPHIDs() as $project_phid) {
$proj_phids[] = $project_phid;
}
}
$proj_handles = id(new PhabricatorHandleQuery())
->setViewer($viewer)
->withPHIDs($proj_phids)
->execute();
$view = id(new PHUIObjectItemListView())
->setUser($viewer);
foreach ($questions as $question) {
$color = PonderQuestionStatus::getQuestionStatusTagColor(
$question->getStatus());
$icon = PonderQuestionStatus::getQuestionStatusIcon(
$question->getStatus());
$full_status = PonderQuestionStatus::getQuestionStatusFullName(
$question->getStatus());
$item = new PHUIObjectItemView();
$item->setObjectName('Q'.$question->getID());
$item->setHeader($question->getTitle());
$item->setHref('/Q'.$question->getID());
$item->setObject($question);
$item->setStatusIcon($icon.' '.$color, $full_status);
$project_handles = array_select_keys(
$proj_handles,
$question->getProjectPHIDs());
$created_date = phabricator_date($question->getDateCreated(), $viewer);
$item->addIcon('none', $created_date);
$item->addByline(
pht(
'Asked by %s',
$handles[$question->getAuthorPHID()]->renderLink()));
$item->addAttribute(
pht(
'%s Answer(s)',
new PhutilNumber($question->getAnswerCount())));
if ($project_handles) {
$item->addAttribute(
id(new PHUIHandleTagListView())
->setLimit(4)
->setSlim(true)
->setHandles($project_handles));
}
$view->addItem($item);
}
$result = new PhabricatorApplicationSearchResultView();
$result->setObjectList($view);
$result->setNoDataString(pht('No questions found.'));
return $result;
}
protected function getNewUserBody() {
$create_button = id(new PHUIButtonView())
->setTag('a')
->setText(pht('Ask a Question'))
->setHref('/ponder/question/create/')
->setColor(PHUIButtonView::GREEN);
- $icon = $this->getApplication()->getFontIcon();
+ $icon = $this->getApplication()->getIcon();
$app_name = $this->getApplication()->getName();
$view = id(new PHUIBigInfoView())
->setIcon($icon)
->setTitle(pht('Welcome to %s', $app_name))
->setDescription(
pht('A simple questions and answers application for your teams.'))
->addAction($create_button);
return $view;
}
}
diff --git a/src/applications/project/application/PhabricatorProjectApplication.php b/src/applications/project/application/PhabricatorProjectApplication.php
index fc30363f5b..59904cb06b 100644
--- a/src/applications/project/application/PhabricatorProjectApplication.php
+++ b/src/applications/project/application/PhabricatorProjectApplication.php
@@ -1,147 +1,147 @@
<?php
final class PhabricatorProjectApplication extends PhabricatorApplication {
public function getName() {
return pht('Projects');
}
public function getShortDescription() {
return pht('Get Organized');
}
public function isPinnedByDefault(PhabricatorUser $viewer) {
return true;
}
public function getBaseURI() {
return '/project/';
}
- public function getFontIcon() {
+ public function getIcon() {
return 'fa-briefcase';
}
public function getFlavorText() {
return pht('Group stuff into big piles.');
}
public function getRemarkupRules() {
return array(
new ProjectRemarkupRule(),
);
}
public function getEventListeners() {
return array(
new PhabricatorProjectUIEventListener(),
);
}
public function getRoutes() {
return array(
'/project/' => array(
'(?:query/(?P<queryKey>[^/]+)/)?' => 'PhabricatorProjectListController',
'filter/(?P<filter>[^/]+)/' => 'PhabricatorProjectListController',
'archive/(?P<id>[1-9]\d*)/'
=> 'PhabricatorProjectArchiveController',
'lock/(?P<id>[1-9]\d*)/'
=> 'PhabricatorProjectLockController',
'members/(?P<id>[1-9]\d*)/'
=> 'PhabricatorProjectMembersViewController',
'members/(?P<id>[1-9]\d*)/add/'
=> 'PhabricatorProjectMembersAddController',
'(?P<type>members|watchers)/(?P<id>[1-9]\d*)/remove/'
=> 'PhabricatorProjectMembersRemoveController',
'profile/(?P<id>[1-9]\d*)/'
=> 'PhabricatorProjectProfileController',
'view/(?P<id>[1-9]\d*)/'
=> 'PhabricatorProjectViewController',
'picture/(?P<id>[1-9]\d*)/'
=> 'PhabricatorProjectEditPictureController',
$this->getEditRoutePattern('edit/')
=> 'PhabricatorProjectEditController',
'(?P<projectID>[1-9]\d*)/panel/'
=> $this->getPanelRouting('PhabricatorProjectPanelController'),
'subprojects/(?P<id>[1-9]\d*)/'
=> 'PhabricatorProjectSubprojectsController',
'milestones/(?P<id>[1-9]\d*)/'
=> 'PhabricatorProjectMilestonesController',
'board/(?P<id>[1-9]\d*)/'.
'(?P<filter>filter/)?'.
'(?:query/(?P<queryKey>[^/]+)/)?'
=> 'PhabricatorProjectBoardViewController',
'move/(?P<id>[1-9]\d*)/' => 'PhabricatorProjectMoveController',
'board/(?P<projectID>[1-9]\d*)/' => array(
'edit/(?:(?P<id>\d+)/)?'
=> 'PhabricatorProjectColumnEditController',
'hide/(?:(?P<id>\d+)/)?'
=> 'PhabricatorProjectColumnHideController',
'column/(?:(?P<id>\d+)/)?'
=> 'PhabricatorProjectColumnDetailController',
'import/'
=> 'PhabricatorProjectBoardImportController',
'reorder/'
=> 'PhabricatorProjectBoardReorderController',
),
'update/(?P<id>[1-9]\d*)/(?P<action>[^/]+)/'
=> 'PhabricatorProjectUpdateController',
'manage/(?P<id>[1-9]\d*)/' => 'PhabricatorProjectManageController',
'(?P<action>watch|unwatch)/(?P<id>[1-9]\d*)/'
=> 'PhabricatorProjectWatchController',
'silence/(?P<id>[1-9]\d*)/'
=> 'PhabricatorProjectSilenceController',
),
'/tag/' => array(
'(?P<slug>[^/]+)/' => 'PhabricatorProjectViewController',
'(?P<slug>[^/]+)/board/' => 'PhabricatorProjectBoardViewController',
),
);
}
public function getQuickCreateItems(PhabricatorUser $viewer) {
return id(new PhabricatorProjectEditEngine())
->setViewer($viewer)
->loadQuickCreateItems();
}
protected function getCustomCapabilities() {
return array(
ProjectCreateProjectsCapability::CAPABILITY => array(),
ProjectCanLockProjectsCapability::CAPABILITY => array(
'default' => PhabricatorPolicies::POLICY_ADMIN,
),
ProjectDefaultViewCapability::CAPABILITY => array(
'caption' => pht('Default view policy for newly created projects.'),
'template' => PhabricatorProjectProjectPHIDType::TYPECONST,
'capability' => PhabricatorPolicyCapability::CAN_VIEW,
),
ProjectDefaultEditCapability::CAPABILITY => array(
'caption' => pht('Default edit policy for newly created projects.'),
'template' => PhabricatorProjectProjectPHIDType::TYPECONST,
'capability' => PhabricatorPolicyCapability::CAN_EDIT,
),
ProjectDefaultJoinCapability::CAPABILITY => array(
'caption' => pht('Default join policy for newly created projects.'),
'template' => PhabricatorProjectProjectPHIDType::TYPECONST,
'capability' => PhabricatorPolicyCapability::CAN_JOIN,
),
);
}
public function getApplicationSearchDocumentTypes() {
return array(
PhabricatorProjectProjectPHIDType::TYPECONST,
);
}
public function getHelpDocumentationArticles(PhabricatorUser $viewer) {
return array(
array(
'name' => pht('Projects User Guide'),
'href' => PhabricatorEnv::getDoclink('Projects User Guide'),
),
);
}
}
diff --git a/src/applications/project/config/PhabricatorProjectConfigOptions.php b/src/applications/project/config/PhabricatorProjectConfigOptions.php
index 73c013c887..84c24c39e8 100644
--- a/src/applications/project/config/PhabricatorProjectConfigOptions.php
+++ b/src/applications/project/config/PhabricatorProjectConfigOptions.php
@@ -1,106 +1,106 @@
<?php
final class PhabricatorProjectConfigOptions
extends PhabricatorApplicationConfigOptions {
public function getName() {
return pht('Projects');
}
public function getDescription() {
return pht('Configure Projects.');
}
- public function getFontIcon() {
+ public function getIcon() {
return 'fa-briefcase';
}
public function getGroup() {
return 'apps';
}
public function getOptions() {
$default_icons = PhabricatorProjectIconSet::getDefaultConfiguration();
$icons_type = 'custom:PhabricatorProjectIconsConfigOptionType';
$icons_description = $this->deformat(pht(<<<EOTEXT
Allows you to change and customize the available project icons.
You can find a list of available icons in {nav UIExamples > Icons and Images}.
Configure a list of icon specifications. Each icon specification should be
a dictionary, which may contain these keys:
- `key` //Required string.// Internal key identifying the icon.
- `name` //Required string.// Human-readable icon name.
- `icon` //Required string.// Specifies which actual icon image to use.
- `default` //Optional bool.// Selects a default icon. Exactly one icon must
be selected as the default.
- `disabled` //Optional bool.// If true, this icon will no longer be
available for selection when creating or editing projects.
- `special` //Optional string.// Marks an icon as a special icon:
- `milestone` This is the icon for milestones. Exactly one icon must be
selected as the milestone icon.
You can look at the default configuration below for an example of a valid
configuration.
EOTEXT
));
$default_colors = PhabricatorProjectIconSet::getDefaultColorMap();
$colors_type = 'custom:PhabricatorProjectColorsConfigOptionType';
$colors_description = $this->deformat(pht(<<<EOTEXT
Allows you to relabel project colors.
The list of available colors can not be expanded, but the existing colors may
be given labels.
Configure a list of color specifications. Each color specification should be a
dictionary, which may contain these keys:
- `key` //Required string.// The internal key identifying the color.
- `name` //Required string.// Human-readable label for the color.
- `default` //Optional bool.// Selects the default color used when creating
new projects. Exactly one color must be selected as the default.
You can look at the default configuration below for an example of a valid
configuration.
EOTEXT
));
$default_fields = array(
'std:project:internal:description' => true,
);
foreach ($default_fields as $key => $enabled) {
$default_fields[$key] = array(
'disabled' => !$enabled,
);
}
$custom_field_type = 'custom:PhabricatorCustomFieldConfigOptionType';
return array(
$this->newOption('projects.custom-field-definitions', 'wild', array())
->setSummary(pht('Custom Projects fields.'))
->setDescription(
pht(
'Array of custom fields for Projects.'))
->addExample(
'{"mycompany:motto": {"name": "Project Motto", '.
'"type": "text"}}',
pht('Valid Setting')),
$this->newOption('projects.fields', $custom_field_type, $default_fields)
->setCustomData(id(new PhabricatorProject())->getCustomFieldBaseClass())
->setDescription(pht('Select and reorder project fields.')),
$this->newOption('projects.icons', $icons_type, $default_icons)
->setSummary(pht('Adjust project icons.'))
->setDescription($icons_description),
$this->newOption('projects.colors', $colors_type, $default_colors)
->setSummary(pht('Adjust project colors.'))
->setDescription($colors_description),
);
}
}
diff --git a/src/applications/project/query/PhabricatorProjectSearchEngine.php b/src/applications/project/query/PhabricatorProjectSearchEngine.php
index 4a29034ba6..ea91dc9754 100644
--- a/src/applications/project/query/PhabricatorProjectSearchEngine.php
+++ b/src/applications/project/query/PhabricatorProjectSearchEngine.php
@@ -1,201 +1,201 @@
<?php
final class PhabricatorProjectSearchEngine
extends PhabricatorApplicationSearchEngine {
public function getResultTypeDescription() {
return pht('Projects');
}
public function getApplicationClassName() {
return 'PhabricatorProjectApplication';
}
public function newQuery() {
return id(new PhabricatorProjectQuery())
->needImages(true)
->withIsMilestone(false);
}
protected function buildCustomSearchFields() {
return array(
id(new PhabricatorSearchTextField())
->setLabel(pht('Name'))
->setKey('name'),
id(new PhabricatorUsersSearchField())
->setLabel(pht('Members'))
->setKey('memberPHIDs')
->setAliases(array('member', 'members')),
id(new PhabricatorSearchSelectField())
->setLabel(pht('Status'))
->setKey('status')
->setOptions($this->getStatusOptions()),
id(new PhabricatorSearchCheckboxesField())
->setLabel(pht('Icons'))
->setKey('icons')
->setOptions($this->getIconOptions()),
id(new PhabricatorSearchCheckboxesField())
->setLabel(pht('Colors'))
->setKey('colors')
->setOptions($this->getColorOptions()),
);
}
protected function buildQueryFromParameters(array $map) {
$query = $this->newQuery();
if (strlen($map['name'])) {
$tokens = PhabricatorTypeaheadDatasource::tokenizeString($map['name']);
$query->withNameTokens($tokens);
}
if ($map['memberPHIDs']) {
$query->withMemberPHIDs($map['memberPHIDs']);
}
if ($map['status']) {
$status = idx($this->getStatusValues(), $map['status']);
if ($status) {
$query->withStatus($status);
}
}
if ($map['icons']) {
$query->withIcons($map['icons']);
}
if ($map['colors']) {
$query->withColors($map['colors']);
}
return $query;
}
protected function getURI($path) {
return '/project/'.$path;
}
protected function getBuiltinQueryNames() {
$names = array();
if ($this->requireViewer()->isLoggedIn()) {
$names['joined'] = pht('Joined');
}
$names['active'] = pht('Active');
$names['all'] = pht('All');
return $names;
}
public function buildSavedQueryFromBuiltin($query_key) {
$query = $this->newSavedQuery();
$query->setQueryKey($query_key);
$viewer_phid = $this->requireViewer()->getPHID();
switch ($query_key) {
case 'all':
return $query;
case 'active':
return $query
->setParameter('status', 'active');
case 'joined':
return $query
->setParameter('memberPHIDs', array($viewer_phid))
->setParameter('status', 'active');
}
return parent::buildSavedQueryFromBuiltin($query_key);
}
private function getStatusOptions() {
return array(
'active' => pht('Show Only Active Projects'),
'archived' => pht('Show Only Archived Projects'),
'all' => pht('Show All Projects'),
);
}
private function getStatusValues() {
return array(
'active' => PhabricatorProjectQuery::STATUS_ACTIVE,
'archived' => PhabricatorProjectQuery::STATUS_ARCHIVED,
'all' => PhabricatorProjectQuery::STATUS_ANY,
);
}
private function getIconOptions() {
$options = array();
$set = new PhabricatorProjectIconSet();
foreach ($set->getIcons() as $icon) {
if ($icon->getIsDisabled()) {
continue;
}
$options[$icon->getKey()] = array(
id(new PHUIIconView())
->setIcon($icon->getIcon()),
' ',
$icon->getLabel(),
);
}
return $options;
}
private function getColorOptions() {
$options = array();
foreach (PhabricatorProjectIconSet::getColorMap() as $color => $name) {
$options[$color] = array(
id(new PHUITagView())
->setType(PHUITagView::TYPE_SHADE)
->setShade($color)
->setName($name),
);
}
return $options;
}
protected function renderResultList(
array $projects,
PhabricatorSavedQuery $query,
array $handles) {
assert_instances_of($projects, 'PhabricatorProject');
$viewer = $this->requireViewer();
$list = id(new PhabricatorProjectListView())
->setUser($viewer)
->setProjects($projects)
->renderList();
return id(new PhabricatorApplicationSearchResultView())
->setObjectList($list)
->setNoDataString(pht('No projects found.'));
}
protected function getNewUserBody() {
$create_button = id(new PHUIButtonView())
->setTag('a')
->setText(pht('Create a Project'))
->setHref('/project/edit/')
->setColor(PHUIButtonView::GREEN);
- $icon = $this->getApplication()->getFontIcon();
+ $icon = $this->getApplication()->getIcon();
$app_name = $this->getApplication()->getName();
$view = id(new PHUIBigInfoView())
->setIcon($icon)
->setTitle(pht('Welcome to %s', $app_name))
->setDescription(
pht('Projects are flexible storage containers used as '.
'tags, teams, projects, or anything you need to group.'))
->addAction($create_button);
return $view;
}
}
diff --git a/src/applications/releeph/application/PhabricatorReleephApplication.php b/src/applications/releeph/application/PhabricatorReleephApplication.php
index ba19ae4321..ab5a12dc80 100644
--- a/src/applications/releeph/application/PhabricatorReleephApplication.php
+++ b/src/applications/releeph/application/PhabricatorReleephApplication.php
@@ -1,88 +1,88 @@
<?php
final class PhabricatorReleephApplication extends PhabricatorApplication {
public function getName() {
return pht('Releeph');
}
public function getShortDescription() {
return pht('Pull Requests');
}
public function getBaseURI() {
return '/releeph/';
}
- public function getFontIcon() {
+ public function getIcon() {
return 'fa-flag-checkered';
}
public function isPrototype() {
return true;
}
public function getRoutes() {
return array(
'/Y(?P<requestID>[1-9]\d*)' => 'ReleephRequestViewController',
// TODO: Remove these older routes eventually.
'/RQ(?P<requestID>[1-9]\d*)' => 'ReleephRequestViewController',
'/releeph/request/(?P<requestID>[1-9]\d*)/'
=> 'ReleephRequestViewController',
'/releeph/' => array(
'' => 'ReleephProductListController',
'(?:product|project)/' => array(
'(?:query/(?P<queryKey>[^/]+)/)?' => 'ReleephProductListController',
'create/' => 'ReleephProductCreateController',
'(?P<projectID>[1-9]\d*)/' => array(
'(?:query/(?P<queryKey>[^/]+)/)?' => 'ReleephProductViewController',
'edit/' => 'ReleephProductEditController',
'cutbranch/' => 'ReleephBranchCreateController',
'action/(?P<action>.+)/' => 'ReleephProductActionController',
'history/' => 'ReleephProductHistoryController',
),
),
'branch/' => array(
'edit/(?P<branchID>[1-9]\d*)/'
=> 'ReleephBranchEditController',
'(?P<action>close|re-open)/(?P<branchID>[1-9]\d*)/'
=> 'ReleephBranchAccessController',
'preview/' => 'ReleephBranchNamePreviewController',
'(?P<branchID>[1-9]\d*)/' => array(
'history/' => 'ReleephBranchHistoryController',
'(?:query/(?P<queryKey>[^/]+)/)?' => 'ReleephBranchViewController',
),
'pull/(?P<branchID>[1-9]\d*)/'
=> 'ReleephRequestEditController',
),
'request/' => array(
'create/' => 'ReleephRequestEditController',
'differentialcreate/' => array(
'D(?P<diffRevID>[1-9]\d*)' =>
'ReleephRequestDifferentialCreateController',
),
'edit/(?P<requestID>[1-9]\d*)/'
=> 'ReleephRequestEditController',
'action/(?P<action>.+)/(?P<requestID>[1-9]\d*)/'
=> 'ReleephRequestActionController',
'typeahead/' =>
'ReleephRequestTypeaheadController',
'comment/(?P<requestID>[1-9]\d*)/'
=> 'ReleephRequestCommentController',
),
),
);
}
public function getMailCommandObjects() {
// TODO: Pull requests don't implement any interfaces which give them
// meaningful commands, so don't expose ReleephRequest here for now.
// Once we add relevant commands, return it here.
return array();
}
}
diff --git a/src/applications/releeph/config/PhabricatorReleephApplicationConfigOptions.php b/src/applications/releeph/config/PhabricatorReleephApplicationConfigOptions.php
index 86f78a48fe..08dace52a7 100644
--- a/src/applications/releeph/config/PhabricatorReleephApplicationConfigOptions.php
+++ b/src/applications/releeph/config/PhabricatorReleephApplicationConfigOptions.php
@@ -1,67 +1,67 @@
<?php
final class PhabricatorReleephApplicationConfigOptions
extends PhabricatorApplicationConfigOptions {
public function getName() {
return pht('Releeph');
}
public function getDescription() {
return pht('Options for configuring Releeph, the release branch tool.');
}
- public function getFontIcon() {
+ public function getIcon() {
return 'fa-flag-checkered';
}
public function getGroup() {
return 'apps';
}
public function getOptions() {
$default_fields = array(
new ReleephSummaryFieldSpecification(),
new ReleephRequestorFieldSpecification(),
new ReleephSeverityFieldSpecification(),
new ReleephIntentFieldSpecification(),
new ReleephReasonFieldSpecification(),
new ReleephAuthorFieldSpecification(),
new ReleephRevisionFieldSpecification(),
new ReleephOriginalCommitFieldSpecification(),
new ReleephBranchCommitFieldSpecification(),
new ReleephDiffSizeFieldSpecification(),
new ReleephDiffChurnFieldSpecification(),
new ReleephDiffMessageFieldSpecification(),
new ReleephCommitMessageFieldSpecification(),
);
$default = array();
foreach ($default_fields as $default_field) {
$default[$default_field->getFieldKey()] = true;
}
foreach ($default as $key => $enabled) {
$default[$key] = array(
'disabled' => !$enabled,
);
}
$custom_field_type = 'custom:PhabricatorCustomFieldConfigOptionType';
return array(
$this->newOption('releeph.fields', $custom_field_type, $default)
->setCustomData('ReleephFieldSpecification'),
$this->newOption(
'releeph.default-branch-template',
'string',
'releases/%P/%p-%Y%m%d-%v')
->setDescription(
pht(
'The default branch template for new branches in unconfigured '.
'Releeph projects. This is also configurable on a per-project '.
'basis.')),
);
}
}
diff --git a/src/applications/repository/config/PhabricatorRepositoryConfigOptions.php b/src/applications/repository/config/PhabricatorRepositoryConfigOptions.php
index fa8e38e063..26e0e9d5d1 100644
--- a/src/applications/repository/config/PhabricatorRepositoryConfigOptions.php
+++ b/src/applications/repository/config/PhabricatorRepositoryConfigOptions.php
@@ -1,37 +1,37 @@
<?php
final class PhabricatorRepositoryConfigOptions
extends PhabricatorApplicationConfigOptions {
public function getName() {
return pht('Repositories');
}
public function getDescription() {
return pht('Configure repositories.');
}
- public function getFontIcon() {
+ public function getIcon() {
return 'fa-hdd-o';
}
public function getGroup() {
return 'apps';
}
public function getOptions() {
return array(
$this->newOption('repository.default-local-path', 'string', '/var/repo/')
->setLocked(true)
->setSummary(
pht('Default location to store local copies of repositories.'))
->setDescription(
pht(
'The default location in which to store working copies and other '.
'data about repositories. Phabricator will control and manage '.
'data here, so you should **not** choose an existing directory '.
'full of data you care about.')),
);
}
}
diff --git a/src/applications/repository/query/PhabricatorRepositorySearchEngine.php b/src/applications/repository/query/PhabricatorRepositorySearchEngine.php
index 83ec6c92e2..059ae9a76d 100644
--- a/src/applications/repository/query/PhabricatorRepositorySearchEngine.php
+++ b/src/applications/repository/query/PhabricatorRepositorySearchEngine.php
@@ -1,270 +1,270 @@
<?php
final class PhabricatorRepositorySearchEngine
extends PhabricatorApplicationSearchEngine {
public function getResultTypeDescription() {
return pht('Repositories');
}
public function getApplicationClassName() {
return 'PhabricatorDiffusionApplication';
}
public function newQuery() {
return id(new PhabricatorRepositoryQuery())
->needProjectPHIDs(true)
->needCommitCounts(true)
->needMostRecentCommits(true);
}
protected function buildCustomSearchFields() {
return array(
id(new PhabricatorSearchStringListField())
->setLabel(pht('Callsigns'))
->setKey('callsigns'),
id(new PhabricatorSearchTextField())
->setLabel(pht('Name Contains'))
->setKey('name'),
id(new PhabricatorSearchSelectField())
->setLabel(pht('Status'))
->setKey('status')
->setOptions($this->getStatusOptions()),
id(new PhabricatorSearchSelectField())
->setLabel(pht('Hosted'))
->setKey('hosted')
->setOptions($this->getHostedOptions()),
id(new PhabricatorSearchCheckboxesField())
->setLabel(pht('Types'))
->setKey('types')
->setOptions(PhabricatorRepositoryType::getAllRepositoryTypes()),
);
}
protected function buildQueryFromParameters(array $map) {
$query = $this->newQuery();
if ($map['callsigns']) {
$query->withCallsigns($map['callsigns']);
}
if ($map['status']) {
$status = idx($this->getStatusValues(), $map['status']);
if ($status) {
$query->withStatus($status);
}
}
if ($map['hosted']) {
$hosted = idx($this->getHostedValues(), $map['hosted']);
if ($hosted) {
$query->withHosted($hosted);
}
}
if ($map['types']) {
$query->withTypes($map['types']);
}
if (strlen($map['name'])) {
$query->withNameContains($map['name']);
}
return $query;
}
protected function getURI($path) {
return '/diffusion/'.$path;
}
protected function getBuiltinQueryNames() {
$names = array(
'active' => pht('Active Repositories'),
'all' => pht('All Repositories'),
);
return $names;
}
public function buildSavedQueryFromBuiltin($query_key) {
$query = $this->newSavedQuery();
$query->setQueryKey($query_key);
switch ($query_key) {
case 'active':
return $query->setParameter('status', 'open');
case 'all':
return $query;
}
return parent::buildSavedQueryFromBuiltin($query_key);
}
private function getStatusOptions() {
return array(
'' => pht('Active and Inactive Repositories'),
'open' => pht('Active Repositories'),
'closed' => pht('Inactive Repositories'),
);
}
private function getStatusValues() {
return array(
'' => PhabricatorRepositoryQuery::STATUS_ALL,
'open' => PhabricatorRepositoryQuery::STATUS_OPEN,
'closed' => PhabricatorRepositoryQuery::STATUS_CLOSED,
);
}
private function getHostedOptions() {
return array(
'' => pht('Hosted and Remote Repositories'),
'phabricator' => pht('Hosted Repositories'),
'remote' => pht('Remote Repositories'),
);
}
private function getHostedValues() {
return array(
'' => PhabricatorRepositoryQuery::HOSTED_ALL,
'phabricator' => PhabricatorRepositoryQuery::HOSTED_PHABRICATOR,
'remote' => PhabricatorRepositoryQuery::HOSTED_REMOTE,
);
}
protected function getRequiredHandlePHIDsForResultList(
array $repositories,
PhabricatorSavedQuery $query) {
return array_mergev(mpull($repositories, 'getProjectPHIDs'));
}
protected function renderResultList(
array $repositories,
PhabricatorSavedQuery $query,
array $handles) {
assert_instances_of($repositories, 'PhabricatorRepository');
$viewer = $this->requireViewer();
$list = new PHUIObjectItemListView();
foreach ($repositories as $repository) {
$id = $repository->getID();
$item = id(new PHUIObjectItemView())
->setUser($viewer)
->setObject($repository)
->setHeader($repository->getName())
->setObjectName($repository->getMonogram())
->setHref($repository->getURI());
$commit = $repository->getMostRecentCommit();
if ($commit) {
$commit_link = phutil_tag(
'a',
array(
'href' => $commit->getURI(),
),
pht(
'%s: %s',
$commit->getLocalName(),
$commit->getSummary()));
$item->setSubhead($commit_link);
$item->setEpoch($commit->getEpoch());
}
$item->addIcon(
'none',
PhabricatorRepositoryType::getNameForRepositoryType(
$repository->getVersionControlSystem()));
$size = $repository->getCommitCount();
if ($size) {
$history_uri = $repository->generateURI(
array(
'action' => 'history',
));
$item->addAttribute(
phutil_tag(
'a',
array(
'href' => $history_uri,
),
pht('%s Commit(s)', new PhutilNumber($size))));
} else {
$item->addAttribute(pht('No Commits'));
}
$project_handles = array_select_keys(
$handles,
$repository->getProjectPHIDs());
if ($project_handles) {
$item->addAttribute(
id(new PHUIHandleTagListView())
->setSlim(true)
->setHandles($project_handles));
}
if (!$repository->isTracked()) {
$item->setDisabled(true);
$item->addIcon('disable-grey', pht('Inactive'));
} else if ($repository->isImporting()) {
$item->addIcon('fa-clock-o indigo', pht('Importing...'));
}
$list->addItem($item);
}
$result = new PhabricatorApplicationSearchResultView();
$result->setObjectList($list);
$result->setNoDataString(pht('No repositories found for this query.'));
return $result;
}
protected function willUseSavedQuery(PhabricatorSavedQuery $saved) {
$project_phids = $saved->getParameter('projectPHIDs', array());
$old = $saved->getParameter('projects', array());
foreach ($old as $phid) {
$project_phids[] = $phid;
}
$any = $saved->getParameter('anyProjectPHIDs', array());
foreach ($any as $project) {
$project_phids[] = 'any('.$project.')';
}
$saved->setParameter('projectPHIDs', $project_phids);
}
protected function getNewUserBody() {
$import_button = id(new PHUIButtonView())
->setTag('a')
->setText(pht('Import Repository'))
->setHref('/diffusion/import/')
->setColor(PHUIButtonView::GREEN);
$create_button = id(new PHUIButtonView())
->setTag('a')
->setText(pht('Create Repository'))
->setHref('/diffusion/create/')
->setColor(PHUIButtonView::GREEN);
- $icon = $this->getApplication()->getFontIcon();
+ $icon = $this->getApplication()->getIcon();
$app_name = $this->getApplication()->getName();
$view = id(new PHUIBigInfoView())
->setIcon($icon)
->setTitle(pht('Welcome to %s', $app_name))
->setDescription(
pht('Import, create, or just browse repositories in Diffusion.'))
->addAction($import_button)
->addAction($create_button);
return $view;
}
}
diff --git a/src/applications/search/application/PhabricatorSearchApplication.php b/src/applications/search/application/PhabricatorSearchApplication.php
index 5b09e21a9e..bd3f78359e 100644
--- a/src/applications/search/application/PhabricatorSearchApplication.php
+++ b/src/applications/search/application/PhabricatorSearchApplication.php
@@ -1,48 +1,48 @@
<?php
final class PhabricatorSearchApplication extends PhabricatorApplication {
public function getBaseURI() {
return '/search/';
}
public function getName() {
return pht('Search');
}
public function getShortDescription() {
return pht('Full-Text Search');
}
public function getFlavorText() {
return pht('Find stuff in big piles.');
}
- public function getFontIcon() {
+ public function getIcon() {
return 'fa-search';
}
public function isLaunchable() {
return false;
}
public function getRoutes() {
return array(
'/search/' => array(
'(?:query/(?P<queryKey>[^/]+)/)?' => 'PhabricatorSearchController',
'attach/(?P<phid>[^/]+)/(?P<type>\w+)/(?:(?P<action>\w+)/)?'
=> 'PhabricatorSearchAttachController',
'select/(?P<type>\w+)/(?:(?P<action>\w+)/)?'
=> 'PhabricatorSearchSelectController',
'index/(?P<phid>[^/]+)/' => 'PhabricatorSearchIndexController',
'hovercard/'
=> 'PhabricatorSearchHovercardController',
'edit/(?P<queryKey>[^/]+)/' => 'PhabricatorSearchEditController',
'delete/(?P<queryKey>[^/]+)/(?P<engine>[^/]+)/'
=> 'PhabricatorSearchDeleteController',
'order/(?P<engine>[^/]+)/' => 'PhabricatorSearchOrderController',
),
);
}
}
diff --git a/src/applications/search/config/PhabricatorSearchConfigOptions.php b/src/applications/search/config/PhabricatorSearchConfigOptions.php
index 453821bc49..2f2cc4f902 100644
--- a/src/applications/search/config/PhabricatorSearchConfigOptions.php
+++ b/src/applications/search/config/PhabricatorSearchConfigOptions.php
@@ -1,35 +1,35 @@
<?php
final class PhabricatorSearchConfigOptions
extends PhabricatorApplicationConfigOptions {
public function getName() {
return pht('Search');
}
public function getDescription() {
return pht('Options relating to Search.');
}
- public function getFontIcon() {
+ public function getIcon() {
return 'fa-search';
}
public function getGroup() {
return 'apps';
}
public function getOptions() {
return array(
$this->newOption('search.elastic.host', 'string', null)
->setLocked(true)
->setDescription(pht('Elastic Search host.'))
->addExample('http://elastic.example.com:9200/', pht('Valid Setting')),
$this->newOption('search.elastic.namespace', 'string', 'phabricator')
->setLocked(true)
->setDescription(pht('Elastic Search index.'))
->addExample('phabricator2', pht('Valid Setting')),
);
}
}
diff --git a/src/applications/settings/application/PhabricatorSettingsApplication.php b/src/applications/settings/application/PhabricatorSettingsApplication.php
index 2608cabd88..d0d6494c12 100644
--- a/src/applications/settings/application/PhabricatorSettingsApplication.php
+++ b/src/applications/settings/application/PhabricatorSettingsApplication.php
@@ -1,43 +1,43 @@
<?php
final class PhabricatorSettingsApplication extends PhabricatorApplication {
public function getBaseURI() {
return '/settings/';
}
public function getName() {
return pht('Settings');
}
public function getShortDescription() {
return pht('User Preferences');
}
- public function getFontIcon() {
+ public function getIcon() {
return 'fa-wrench';
}
public function canUninstall() {
return false;
}
public function isLaunchable() {
return false;
}
public function getRoutes() {
return array(
'/settings/' => array(
'(?:(?P<id>\d+)/)?(?:panel/(?P<key>[^/]+)/)?'
=> 'PhabricatorSettingsMainController',
'adjust/' => 'PhabricatorSettingsAdjustController',
),
);
}
public function getApplicationGroup() {
return self::GROUP_UTILITIES;
}
}
diff --git a/src/applications/settings/panel/PhabricatorHomePreferencesSettingsPanel.php b/src/applications/settings/panel/PhabricatorHomePreferencesSettingsPanel.php
index eabbc3ff32..06b17fecca 100644
--- a/src/applications/settings/panel/PhabricatorHomePreferencesSettingsPanel.php
+++ b/src/applications/settings/panel/PhabricatorHomePreferencesSettingsPanel.php
@@ -1,194 +1,194 @@
<?php
final class PhabricatorHomePreferencesSettingsPanel
extends PhabricatorSettingsPanel {
public function getPanelKey() {
return 'home';
}
public function getPanelName() {
return pht('Home Page');
}
public function getPanelGroup() {
return pht('Application Settings');
}
public function processRequest(AphrontRequest $request) {
$user = $request->getUser();
$preferences = $user->loadPreferences();
$apps = id(new PhabricatorApplicationQuery())
->setViewer($user)
->withInstalled(true)
->withUnlisted(false)
->withLaunchable(true)
->execute();
$pinned = $preferences->getPinnedApplications($apps, $user);
$app_list = array();
foreach ($pinned as $app) {
if (isset($apps[$app])) {
$app_list[$app] = $apps[$app];
}
}
if ($request->getBool('add')) {
$options = array();
foreach ($apps as $app) {
$options[get_class($app)] = $app->getName();
}
asort($options);
unset($options['PhabricatorApplicationsApplication']);
if ($request->isFormPost()) {
$pin = $request->getStr('pin');
if (isset($options[$pin]) && !in_array($pin, $pinned)) {
$pinned[] = $pin;
$preferences->setPreference(
PhabricatorUserPreferences::PREFERENCE_APP_PINNED,
$pinned);
$preferences->save();
return id(new AphrontRedirectResponse())
->setURI($this->getPanelURI());
}
}
$options_control = id(new AphrontFormSelectControl())
->setName('pin')
->setLabel(pht('Application'))
->setOptions($options)
->setDisabledOptions(array_keys($app_list));
$form = id(new AphrontFormView())
->setUser($user)
->addHiddenInput('add', 'true')
->appendRemarkupInstructions(
pht('Choose an application to pin to your home page.'))
->appendChild($options_control);
$dialog = id(new AphrontDialogView())
->setUser($user)
->setWidth(AphrontDialogView::WIDTH_FORM)
->setTitle(pht('Pin Application'))
->appendChild($form->buildLayoutView())
->addSubmitButton(pht('Pin Application'))
->addCancelButton($this->getPanelURI());
return id(new AphrontDialogResponse())->setDialog($dialog);
}
$unpin = $request->getStr('unpin');
if ($unpin) {
$app = idx($apps, $unpin);
if ($app) {
if ($request->isFormPost()) {
$pinned = array_diff($pinned, array($unpin));
$preferences->setPreference(
PhabricatorUserPreferences::PREFERENCE_APP_PINNED,
$pinned);
$preferences->save();
return id(new AphrontRedirectResponse())
->setURI($this->getPanelURI());
}
$dialog = id(new AphrontDialogView())
->setUser($user)
->setTitle(pht('Unpin Application'))
->appendParagraph(
pht(
'Unpin the %s application from your home page?',
phutil_tag('strong', array(), $app->getName())))
->addSubmitButton(pht('Unpin Application'))
->addCanceLButton($this->getPanelURI());
return id(new AphrontDialogResponse())->setDialog($dialog);
}
}
$order = $request->getStrList('order');
if ($order && $request->validateCSRF()) {
$preferences->setPreference(
PhabricatorUserPreferences::PREFERENCE_APP_PINNED,
$order);
$preferences->save();
return id(new AphrontRedirectResponse())
->setURI($this->getPanelURI());
}
$list_id = celerity_generate_unique_node_id();
$list = id(new PHUIObjectItemListView())
->setUser($user)
->setID($list_id);
Javelin::initBehavior(
'reorder-applications',
array(
'listID' => $list_id,
'panelURI' => $this->getPanelURI(),
));
foreach ($app_list as $key => $application) {
if ($key == 'PhabricatorApplicationsApplication') {
continue;
}
- $icon = $application->getFontIcon();
+ $icon = $application->getIcon();
if (!$icon) {
$icon = 'application';
}
$icon_view = javelin_tag(
'span',
array(
'class' => 'phui-icon-view phui-font-fa '.$icon,
'aural' => false,
),
'');
$item = id(new PHUIObjectItemView())
->setHeader($application->getName())
->setImageIcon($icon_view)
->addAttribute($application->getShortDescription())
->setGrippable(true);
$item->addAction(
id(new PHUIListItemView())
->setIcon('fa-times')
->setHref($this->getPanelURI().'?unpin='.$key)
->setWorkflow(true));
$item->addSigil('pinned-application');
$item->setMetadata(
array(
'applicationClass' => $key,
));
$list->addItem($item);
}
$header = id(new PHUIHeaderView())
->setHeader(pht('Pinned Applications'))
->addActionLink(
id(new PHUIButtonView())
->setTag('a')
->setText(pht('Pin Application'))
->setHref($this->getPanelURI().'?add=true')
->setWorkflow(true)
->setIcon('fa-thumb-tack'));
$box = id(new PHUIObjectBoxView())
->setHeader($header)
->setObjectList($list);
return $box;
}
}
diff --git a/src/applications/slowvote/application/PhabricatorSlowvoteApplication.php b/src/applications/slowvote/application/PhabricatorSlowvoteApplication.php
index e7ea30dfed..1e4bd78419 100644
--- a/src/applications/slowvote/application/PhabricatorSlowvoteApplication.php
+++ b/src/applications/slowvote/application/PhabricatorSlowvoteApplication.php
@@ -1,73 +1,73 @@
<?php
final class PhabricatorSlowvoteApplication extends PhabricatorApplication {
public function getBaseURI() {
return '/vote/';
}
- public function getFontIcon() {
+ public function getIcon() {
return 'fa-bar-chart';
}
public function getName() {
return pht('Slowvote');
}
public function getShortDescription() {
return pht('Conduct Polls');
}
public function getTitleGlyph() {
return "\xE2\x9C\x94";
}
public function getHelpDocumentationArticles(PhabricatorUser $viewer) {
return array(
array(
'name' => pht('Slowvote User Guide'),
'href' => PhabricatorEnv::getDoclink('Slowvote User Guide'),
),
);
}
public function getFlavorText() {
return pht('Design by committee.');
}
public function getApplicationGroup() {
return self::GROUP_UTILITIES;
}
public function getRemarkupRules() {
return array(
new SlowvoteRemarkupRule(),
);
}
public function getRoutes() {
return array(
'/V(?P<id>[1-9]\d*)' => 'PhabricatorSlowvotePollController',
'/vote/' => array(
'(?:query/(?P<queryKey>[^/]+)/)?'
=> 'PhabricatorSlowvoteListController',
'create/' => 'PhabricatorSlowvoteEditController',
'edit/(?P<id>[1-9]\d*)/' => 'PhabricatorSlowvoteEditController',
'(?P<id>[1-9]\d*)/' => 'PhabricatorSlowvoteVoteController',
'comment/(?P<id>[1-9]\d*)/' => 'PhabricatorSlowvoteCommentController',
'close/(?P<id>[1-9]\d*)/' => 'PhabricatorSlowvoteCloseController',
),
);
}
protected function getCustomCapabilities() {
return array(
PhabricatorSlowvoteDefaultViewCapability::CAPABILITY => array(
'caption' => pht('Default view policy for new polls.'),
'template' => PhabricatorSlowvotePollPHIDType::TYPECONST,
'capability' => PhabricatorPolicyCapability::CAN_VIEW,
),
);
}
}
diff --git a/src/applications/slowvote/query/PhabricatorSlowvoteSearchEngine.php b/src/applications/slowvote/query/PhabricatorSlowvoteSearchEngine.php
index d38683ee06..fee52a908c 100644
--- a/src/applications/slowvote/query/PhabricatorSlowvoteSearchEngine.php
+++ b/src/applications/slowvote/query/PhabricatorSlowvoteSearchEngine.php
@@ -1,185 +1,185 @@
<?php
final class PhabricatorSlowvoteSearchEngine
extends PhabricatorApplicationSearchEngine {
public function getResultTypeDescription() {
return pht('Slowvotes');
}
public function getApplicationClassName() {
return 'PhabricatorSlowvoteApplication';
}
public function newQuery() {
return new PhabricatorSlowvoteQuery();
}
protected function buildQueryFromParameters(array $map) {
$query = $this->newQuery();
if ($map['voted']) {
$query->withVotesByViewer(true);
}
if ($map['authorPHIDs']) {
$query->withAuthorPHIDs($map['authorPHIDs']);
}
$statuses = $map['statuses'];
if (count($statuses) == 1) {
$status = head($statuses);
if ($status == 'open') {
$query->withIsClosed(false);
} else {
$query->withIsClosed(true);
}
}
return $query;
}
protected function buildCustomSearchFields() {
return array(
id(new PhabricatorUsersSearchField())
->setKey('authorPHIDs')
->setAliases(array('authors'))
->setLabel(pht('Authors')),
id(new PhabricatorSearchCheckboxesField())
->setKey('voted')
->setOptions(array(
'voted' => pht("Show only polls I've voted in."),
)),
id(new PhabricatorSearchCheckboxesField())
->setKey('statuses')
->setOptions(array(
'open' => pht('Open'),
'closed' => pht('Closed'),
)),
);
}
protected function getURI($path) {
return '/vote/'.$path;
}
protected function getBuiltinQueryNames() {
$names = array(
'open' => pht('Open Polls'),
'all' => pht('All Polls'),
);
if ($this->requireViewer()->isLoggedIn()) {
$names['authored'] = pht('Authored');
$names['voted'] = pht('Voted In');
}
return $names;
}
public function buildSavedQueryFromBuiltin($query_key) {
$query = $this->newSavedQuery();
$query->setQueryKey($query_key);
switch ($query_key) {
case 'open':
return $query->setParameter('statuses', array('open'));
case 'all':
return $query;
case 'authored':
return $query->setParameter(
'authorPHIDs',
array($this->requireViewer()->getPHID()));
case 'voted':
return $query->setParameter('voted', array('voted'));
}
return parent::buildSavedQueryFromBuiltin($query_key);
}
protected function getRequiredHandlePHIDsForResultList(
array $polls,
PhabricatorSavedQuery $query) {
return mpull($polls, 'getAuthorPHID');
}
protected function renderResultList(
array $polls,
PhabricatorSavedQuery $query,
array $handles) {
assert_instances_of($polls, 'PhabricatorSlowvotePoll');
$viewer = $this->requireViewer();
$list = id(new PHUIObjectItemListView())
->setUser($viewer);
$phids = mpull($polls, 'getAuthorPHID');
foreach ($polls as $poll) {
$date_created = phabricator_datetime($poll->getDateCreated(), $viewer);
if ($poll->getAuthorPHID()) {
$author = $handles[$poll->getAuthorPHID()]->renderLink();
} else {
$author = null;
}
$item = id(new PHUIObjectItemView())
->setUser($viewer)
->setObject($poll)
->setObjectName('V'.$poll->getID())
->setHeader($poll->getQuestion())
->setHref('/V'.$poll->getID())
->addIcon('none', $date_created);
if ($poll->getIsClosed()) {
$item->setStatusIcon('fa-ban grey');
$item->setDisabled(true);
} else {
$item->setStatusIcon('fa-bar-chart');
}
$description = $poll->getDescription();
if (strlen($description)) {
$item->addAttribute(id(new PhutilUTF8StringTruncator())
->setMaximumGlyphs(120)
->truncateString($poll->getDescription()));
}
if ($author) {
$item->addByline(pht('Author: %s', $author));
}
$list->addItem($item);
}
$result = new PhabricatorApplicationSearchResultView();
$result->setObjectList($list);
$result->setNoDataString(pht('No polls found.'));
return $result;
}
protected function getNewUserBody() {
$create_button = id(new PHUIButtonView())
->setTag('a')
->setText(pht('Create a Poll'))
->setHref('/vote/create/')
->setColor(PHUIButtonView::GREEN);
- $icon = $this->getApplication()->getFontIcon();
+ $icon = $this->getApplication()->getIcon();
$app_name = $this->getApplication()->getName();
$view = id(new PHUIBigInfoView())
->setIcon($icon)
->setTitle(pht('Welcome to %s', $app_name))
->setDescription(
pht('Poll other users to help facilitate decision making.'))
->addAction($create_button);
return $view;
}
}
diff --git a/src/applications/spaces/application/PhabricatorSpacesApplication.php b/src/applications/spaces/application/PhabricatorSpacesApplication.php
index 66371f1bc2..d542551ae4 100644
--- a/src/applications/spaces/application/PhabricatorSpacesApplication.php
+++ b/src/applications/spaces/application/PhabricatorSpacesApplication.php
@@ -1,84 +1,84 @@
<?php
final class PhabricatorSpacesApplication extends PhabricatorApplication {
public function getBaseURI() {
return '/spaces/';
}
public function getName() {
return pht('Spaces');
}
public function getShortDescription() {
return pht('Policy Namespaces');
}
- public function getFontIcon() {
+ public function getIcon() {
return 'fa-th-large';
}
public function getTitleGlyph() {
return "\xE2\x97\x8B";
}
public function getFlavorText() {
return pht('Control access to groups of objects.');
}
public function getApplicationGroup() {
return self::GROUP_UTILITIES;
}
public function canUninstall() {
return false;
}
public function getHelpDocumentationArticles(PhabricatorUser $viewer) {
return array(
array(
'name' => pht('Spaces User Guide'),
'href' => PhabricatorEnv::getDoclink('Spaces User Guide'),
),
);
}
public function getRemarkupRules() {
return array(
new PhabricatorSpacesRemarkupRule(),
);
}
public function getRoutes() {
return array(
'/S(?P<id>[1-9]\d*)' => 'PhabricatorSpacesViewController',
'/spaces/' => array(
'(?:query/(?P<queryKey>[^/]+)/)?' => 'PhabricatorSpacesListController',
'create/' => 'PhabricatorSpacesEditController',
'edit/(?:(?P<id>\d+)/)?' => 'PhabricatorSpacesEditController',
'(?P<action>activate|archive)/(?P<id>\d+)/'
=> 'PhabricatorSpacesArchiveController',
),
);
}
protected function getCustomCapabilities() {
return array(
PhabricatorSpacesCapabilityCreateSpaces::CAPABILITY => array(
'default' => PhabricatorPolicies::POLICY_ADMIN,
),
PhabricatorSpacesCapabilityDefaultView::CAPABILITY => array(
'caption' => pht('Default view policy for newly created spaces.'),
'template' => PhabricatorSpacesNamespacePHIDType::TYPECONST,
'capability' => PhabricatorPolicyCapability::CAN_VIEW,
),
PhabricatorSpacesCapabilityDefaultEdit::CAPABILITY => array(
'caption' => pht('Default edit policy for newly created spaces.'),
'default' => PhabricatorPolicies::POLICY_ADMIN,
'template' => PhabricatorSpacesNamespacePHIDType::TYPECONST,
'capability' => PhabricatorPolicyCapability::CAN_EDIT,
),
);
}
}
diff --git a/src/applications/spaces/query/PhabricatorSpacesNamespaceSearchEngine.php b/src/applications/spaces/query/PhabricatorSpacesNamespaceSearchEngine.php
index 4b469cca1b..3880143a24 100644
--- a/src/applications/spaces/query/PhabricatorSpacesNamespaceSearchEngine.php
+++ b/src/applications/spaces/query/PhabricatorSpacesNamespaceSearchEngine.php
@@ -1,121 +1,121 @@
<?php
final class PhabricatorSpacesNamespaceSearchEngine
extends PhabricatorApplicationSearchEngine {
public function getApplicationClassName() {
return 'PhabricatorSpacesApplication';
}
public function getResultTypeDescription() {
return pht('Spaces');
}
public function newQuery() {
return new PhabricatorSpacesNamespaceQuery();
}
protected function buildCustomSearchFields() {
return array(
id(new PhabricatorSearchThreeStateField())
->setLabel(pht('Active'))
->setKey('active')
->setOptions(
pht('(Show All)'),
pht('Show Only Active Spaces'),
pht('Hide Active Spaces')),
);
}
protected function buildQueryFromParameters(array $map) {
$query = $this->newQuery();
if ($map['active']) {
$query->withIsArchived(!$map['active']);
}
return $query;
}
protected function getURI($path) {
return '/spaces/'.$path;
}
protected function getBuiltinQueryNames() {
$names = array(
'active' => pht('Active Spaces'),
'all' => pht('All Spaces'),
);
return $names;
}
public function buildSavedQueryFromBuiltin($query_key) {
$query = $this->newSavedQuery();
$query->setQueryKey($query_key);
switch ($query_key) {
case 'active':
return $query->setParameter('active', true);
case 'all':
return $query;
}
return parent::buildSavedQueryFromBuiltin($query_key);
}
protected function renderResultList(
array $spaces,
PhabricatorSavedQuery $query,
array $handles) {
assert_instances_of($spaces, 'PhabricatorSpacesNamespace');
$viewer = $this->requireViewer();
$list = new PHUIObjectItemListView();
$list->setUser($viewer);
foreach ($spaces as $space) {
$item = id(new PHUIObjectItemView())
->setObjectName($space->getMonogram())
->setHeader($space->getNamespaceName())
->setHref('/'.$space->getMonogram());
if ($space->getIsDefaultNamespace()) {
$item->addIcon('fa-certificate', pht('Default Space'));
}
if ($space->getIsArchived()) {
$item->setDisabled(true);
}
$list->addItem($item);
}
$result = new PhabricatorApplicationSearchResultView();
$result->setObjectList($list);
$result->setNoDataString(pht('No spaces found.'));
return $result;
}
protected function getNewUserBody() {
$create_button = id(new PHUIButtonView())
->setTag('a')
->setText(pht('Create a Space'))
->setHref('/spaces/create/')
->setColor(PHUIButtonView::GREEN);
- $icon = $this->getApplication()->getFontIcon();
+ $icon = $this->getApplication()->getIcon();
$app_name = $this->getApplication()->getName();
$view = id(new PHUIBigInfoView())
->setIcon($icon)
->setTitle(pht('Welcome to %s', $app_name))
->setDescription(
pht('Policy namespaces to segment object visibility throughout your '.
'instance.'))
->addAction($create_button);
return $view;
}
}
diff --git a/src/applications/tokens/application/PhabricatorTokensApplication.php b/src/applications/tokens/application/PhabricatorTokensApplication.php
index 76046e82de..0ef130a282 100644
--- a/src/applications/tokens/application/PhabricatorTokensApplication.php
+++ b/src/applications/tokens/application/PhabricatorTokensApplication.php
@@ -1,46 +1,46 @@
<?php
final class PhabricatorTokensApplication extends PhabricatorApplication {
public function getName() {
return pht('Tokens');
}
public function getBaseURI() {
return '/token/';
}
- public function getFontIcon() {
+ public function getIcon() {
return 'fa-thumbs-up';
}
public function getTitleGlyph() {
return "\xE2\x99\xA6";
}
public function getShortDescription() {
return pht('Award and Acquire Trinkets');
}
public function getApplicationGroup() {
return self::GROUP_UTILITIES;
}
public function getRoutes() {
return array(
'/token/' => array(
'' => 'PhabricatorTokenGivenController',
'given/' => 'PhabricatorTokenGivenController',
'give/(?<phid>[^/]+)/' => 'PhabricatorTokenGiveController',
'leaders/' => 'PhabricatorTokenLeaderController',
),
);
}
public function getEventListeners() {
return array(
new PhabricatorTokenUIEventListener(),
);
}
}
diff --git a/src/applications/transactions/editengine/PhabricatorEditEngine.php b/src/applications/transactions/editengine/PhabricatorEditEngine.php
index 9efc3c4100..f8dc0ee175 100644
--- a/src/applications/transactions/editengine/PhabricatorEditEngine.php
+++ b/src/applications/transactions/editengine/PhabricatorEditEngine.php
@@ -1,1887 +1,1887 @@
<?php
/**
* @task fields Managing Fields
* @task text Display Text
* @task config Edit Engine Configuration
* @task uri Managing URIs
* @task load Creating and Loading Objects
* @task web Responding to Web Requests
* @task edit Responding to Edit Requests
* @task http Responding to HTTP Parameter Requests
* @task conduit Responding to Conduit Requests
*/
abstract class PhabricatorEditEngine
extends Phobject
implements PhabricatorPolicyInterface {
const EDITENGINECONFIG_DEFAULT = 'default';
private $viewer;
private $controller;
private $isCreate;
private $editEngineConfiguration;
private $contextParameters = array();
final public function setViewer(PhabricatorUser $viewer) {
$this->viewer = $viewer;
return $this;
}
final public function getViewer() {
return $this->viewer;
}
final public function setController(PhabricatorController $controller) {
$this->controller = $controller;
$this->setViewer($controller->getViewer());
return $this;
}
final public function getController() {
return $this->controller;
}
final public function getEngineKey() {
return $this->getPhobjectClassConstant('ENGINECONST', 64);
}
final public function getApplication() {
$app_class = $this->getEngineApplicationClass();
return PhabricatorApplication::getByClass($app_class);
}
final public function addContextParameter($key) {
$this->contextParameters[] = $key;
return $this;
}
public function isEngineConfigurable() {
return true;
}
/* -( Managing Fields )---------------------------------------------------- */
abstract public function getEngineApplicationClass();
abstract protected function buildCustomEditFields($object);
public function getFieldsForConfig(
PhabricatorEditEngineConfiguration $config) {
$object = $this->newEditableObject();
$this->editEngineConfiguration = $config;
// This is mostly making sure that we fill in default values.
$this->setIsCreate(true);
return $this->buildEditFields($object);
}
final protected function buildEditFields($object) {
$viewer = $this->getViewer();
$fields = $this->buildCustomEditFields($object);
foreach ($fields as $field) {
$field
->setViewer($viewer)
->setObject($object);
}
$fields = mpull($fields, null, 'getKey');
$extensions = PhabricatorEditEngineExtension::getAllEnabledExtensions();
foreach ($extensions as $extension) {
$extension->setViewer($viewer);
if (!$extension->supportsObject($this, $object)) {
continue;
}
$extension_fields = $extension->buildCustomEditFields($this, $object);
// TODO: Validate this in more detail with a more tailored error.
assert_instances_of($extension_fields, 'PhabricatorEditField');
foreach ($extension_fields as $field) {
$field
->setViewer($viewer)
->setObject($object);
}
$extension_fields = mpull($extension_fields, null, 'getKey');
foreach ($extension_fields as $key => $field) {
$fields[$key] = $field;
}
}
$config = $this->getEditEngineConfiguration();
$fields = $this->willConfigureFields($object, $fields);
$fields = $config->applyConfigurationToFields($this, $object, $fields);
return $fields;
}
protected function willConfigureFields($object, array $fields) {
return $fields;
}
/* -( Display Text )------------------------------------------------------- */
/**
* @task text
*/
abstract public function getEngineName();
/**
* @task text
*/
abstract protected function getObjectCreateTitleText($object);
/**
* @task text
*/
protected function getFormHeaderText($object) {
$config = $this->getEditEngineConfiguration();
return $config->getName();
}
/**
* @task text
*/
abstract protected function getObjectEditTitleText($object);
/**
* @task text
*/
abstract protected function getObjectCreateShortText();
/**
* @task text
*/
abstract protected function getObjectEditShortText($object);
/**
* @task text
*/
protected function getObjectCreateButtonText($object) {
return $this->getObjectCreateTitleText($object);
}
/**
* @task text
*/
protected function getObjectEditButtonText($object) {
return pht('Save Changes');
}
/**
* @task text
*/
protected function getCommentViewSeriousHeaderText($object) {
return pht('Take Action');
}
/**
* @task text
*/
protected function getCommentViewSeriousButtonText($object) {
return pht('Submit');
}
/**
* @task text
*/
protected function getCommentViewHeaderText($object) {
return $this->getCommentViewSeriousHeaderText($object);
}
/**
* @task text
*/
protected function getCommentViewButtonText($object) {
return $this->getCommentViewSeriousButtonText($object);
}
/**
* @task text
*/
protected function getQuickCreateMenuHeaderText() {
return $this->getObjectCreateShortText();
}
/**
* Return a human-readable header describing what this engine is used to do,
* like "Configure Maniphest Task Forms".
*
* @return string Human-readable description of the engine.
* @task text
*/
abstract public function getSummaryHeader();
/**
* Return a human-readable summary of what this engine is used to do.
*
* @return string Human-readable description of the engine.
* @task text
*/
abstract public function getSummaryText();
/* -( Edit Engine Configuration )------------------------------------------ */
protected function supportsEditEngineConfiguration() {
return true;
}
final protected function getEditEngineConfiguration() {
return $this->editEngineConfiguration;
}
private function newConfigurationQuery() {
return id(new PhabricatorEditEngineConfigurationQuery())
->setViewer($this->getViewer())
->withEngineKeys(array($this->getEngineKey()));
}
private function loadEditEngineConfigurationWithQuery(
PhabricatorEditEngineConfigurationQuery $query,
$sort_method) {
if ($sort_method) {
$results = $query->execute();
$results = msort($results, $sort_method);
$result = head($results);
} else {
$result = $query->executeOne();
}
if (!$result) {
return null;
}
$this->editEngineConfiguration = $result;
return $result;
}
private function loadEditEngineConfigurationWithIdentifier($identifier) {
$query = $this->newConfigurationQuery()
->withIdentifiers(array($identifier));
return $this->loadEditEngineConfigurationWithQuery($query, null);
}
private function loadDefaultConfiguration() {
$query = $this->newConfigurationQuery()
->withIdentifiers(
array(
self::EDITENGINECONFIG_DEFAULT,
))
->withIgnoreDatabaseConfigurations(true);
return $this->loadEditEngineConfigurationWithQuery($query, null);
}
private function loadDefaultCreateConfiguration() {
$query = $this->newConfigurationQuery()
->withIsDefault(true)
->withIsDisabled(false);
return $this->loadEditEngineConfigurationWithQuery(
$query,
'getCreateSortKey');
}
public function loadDefaultEditConfiguration() {
$query = $this->newConfigurationQuery()
->withIsEdit(true)
->withIsDisabled(false);
return $this->loadEditEngineConfigurationWithQuery(
$query,
'getEditSortKey');
}
final public function getBuiltinEngineConfigurations() {
$configurations = $this->newBuiltinEngineConfigurations();
if (!$configurations) {
throw new Exception(
pht(
'EditEngine ("%s") returned no builtin engine configurations, but '.
'an edit engine must have at least one configuration.',
get_class($this)));
}
assert_instances_of($configurations, 'PhabricatorEditEngineConfiguration');
$has_default = false;
foreach ($configurations as $config) {
if ($config->getBuiltinKey() == self::EDITENGINECONFIG_DEFAULT) {
$has_default = true;
}
}
if (!$has_default) {
$first = head($configurations);
if (!$first->getBuiltinKey()) {
$first
->setBuiltinKey(self::EDITENGINECONFIG_DEFAULT)
->setIsDefault(true)
->setIsEdit(true);
if (!strlen($first->getName())) {
$first->setName($this->getObjectCreateShortText());
}
} else {
throw new Exception(
pht(
'EditEngine ("%s") returned builtin engine configurations, '.
'but none are marked as default and the first configuration has '.
'a different builtin key already. Mark a builtin as default or '.
'omit the key from the first configuration',
get_class($this)));
}
}
$builtins = array();
foreach ($configurations as $key => $config) {
$builtin_key = $config->getBuiltinKey();
if ($builtin_key === null) {
throw new Exception(
pht(
'EditEngine ("%s") returned builtin engine configurations, '.
'but one (with key "%s") is missing a builtin key. Provide a '.
'builtin key for each configuration (you can omit it from the '.
'first configuration in the list to automatically assign the '.
'default key).',
get_class($this),
$key));
}
if (isset($builtins[$builtin_key])) {
throw new Exception(
pht(
'EditEngine ("%s") returned builtin engine configurations, '.
'but at least two specify the same builtin key ("%s"). Engines '.
'must have unique builtin keys.',
get_class($this),
$builtin_key));
}
$builtins[$builtin_key] = $config;
}
return $builtins;
}
protected function newBuiltinEngineConfigurations() {
return array(
$this->newConfiguration(),
);
}
final protected function newConfiguration() {
return PhabricatorEditEngineConfiguration::initializeNewConfiguration(
$this->getViewer(),
$this);
}
/* -( Managing URIs )------------------------------------------------------ */
/**
* @task uri
*/
abstract protected function getObjectViewURI($object);
/**
* @task uri
*/
protected function getObjectCreateCancelURI($object) {
return $this->getApplication()->getApplicationURI();
}
/**
* @task uri
*/
protected function getEditorURI() {
return $this->getApplication()->getApplicationURI('edit/');
}
/**
* @task uri
*/
protected function getObjectEditCancelURI($object) {
return $this->getObjectViewURI($object);
}
/**
* @task uri
*/
public function getEditURI($object = null, $path = null) {
$parts = array();
$parts[] = $this->getEditorURI();
if ($object && $object->getID()) {
$parts[] = $object->getID().'/';
}
if ($path !== null) {
$parts[] = $path;
}
return implode('', $parts);
}
/* -( Creating and Loading Objects )--------------------------------------- */
/**
* Initialize a new object for creation.
*
* @return object Newly initialized object.
* @task load
*/
abstract protected function newEditableObject();
/**
* Build an empty query for objects.
*
* @return PhabricatorPolicyAwareQuery Query.
* @task load
*/
abstract protected function newObjectQuery();
/**
* Test if this workflow is creating a new object or editing an existing one.
*
* @return bool True if a new object is being created.
* @task load
*/
final public function getIsCreate() {
return $this->isCreate;
}
/**
* Flag this workflow as a create or edit.
*
* @param bool True if this is a create workflow.
* @return this
* @task load
*/
private function setIsCreate($is_create) {
$this->isCreate = $is_create;
return $this;
}
/**
* Try to load an object by ID, PHID, or monogram. This is done primarily
* to make Conduit a little easier to use.
*
* @param wild ID, PHID, or monogram.
* @param list<const> List of required capability constants, or omit for
* defaults.
* @return object Corresponding editable object.
* @task load
*/
private function newObjectFromIdentifier(
$identifier,
array $capabilities = array()) {
if (is_int($identifier) || ctype_digit($identifier)) {
$object = $this->newObjectFromID($identifier, $capabilities);
if (!$object) {
throw new Exception(
pht(
'No object exists with ID "%s".',
$identifier));
}
return $object;
}
$type_unknown = PhabricatorPHIDConstants::PHID_TYPE_UNKNOWN;
if (phid_get_type($identifier) != $type_unknown) {
$object = $this->newObjectFromPHID($identifier, $capabilities);
if (!$object) {
throw new Exception(
pht(
'No object exists with PHID "%s".',
$identifier));
}
return $object;
}
$target = id(new PhabricatorObjectQuery())
->setViewer($this->getViewer())
->withNames(array($identifier))
->executeOne();
if (!$target) {
throw new Exception(
pht(
'Monogram "%s" does not identify a valid object.',
$identifier));
}
$expect = $this->newEditableObject();
$expect_class = get_class($expect);
$target_class = get_class($target);
if ($expect_class !== $target_class) {
throw new Exception(
pht(
'Monogram "%s" identifies an object of the wrong type. Loaded '.
'object has class "%s", but this editor operates on objects of '.
'type "%s".',
$identifier,
$target_class,
$expect_class));
}
// Load the object by PHID using this engine's standard query. This makes
// sure it's really valid, goes through standard policy check logic, and
// picks up any `need...()` clauses we want it to load with.
$object = $this->newObjectFromPHID($target->getPHID(), $capabilities);
if (!$object) {
throw new Exception(
pht(
'Failed to reload object identified by monogram "%s" when '.
'querying by PHID.',
$identifier));
}
return $object;
}
/**
* Load an object by ID.
*
* @param int Object ID.
* @param list<const> List of required capability constants, or omit for
* defaults.
* @return object|null Object, or null if no such object exists.
* @task load
*/
private function newObjectFromID($id, array $capabilities = array()) {
$query = $this->newObjectQuery()
->withIDs(array($id));
return $this->newObjectFromQuery($query, $capabilities);
}
/**
* Load an object by PHID.
*
* @param phid Object PHID.
* @param list<const> List of required capability constants, or omit for
* defaults.
* @return object|null Object, or null if no such object exists.
* @task load
*/
private function newObjectFromPHID($phid, array $capabilities = array()) {
$query = $this->newObjectQuery()
->withPHIDs(array($phid));
return $this->newObjectFromQuery($query, $capabilities);
}
/**
* Load an object given a configured query.
*
* @param PhabricatorPolicyAwareQuery Configured query.
* @param list<const> List of required capabilitiy constants, or omit for
* defaults.
* @return object|null Object, or null if no such object exists.
* @task load
*/
private function newObjectFromQuery(
PhabricatorPolicyAwareQuery $query,
array $capabilities = array()) {
$viewer = $this->getViewer();
if (!$capabilities) {
$capabilities = array(
PhabricatorPolicyCapability::CAN_VIEW,
PhabricatorPolicyCapability::CAN_EDIT,
);
}
$object = $query
->setViewer($viewer)
->requireCapabilities($capabilities)
->executeOne();
if (!$object) {
return null;
}
return $object;
}
/**
* Verify that an object is appropriate for editing.
*
* @param wild Loaded value.
* @return void
* @task load
*/
private function validateObject($object) {
if (!$object || !is_object($object)) {
throw new Exception(
pht(
'EditEngine "%s" created or loaded an invalid object: object must '.
'actually be an object, but is of some other type ("%s").',
get_class($this),
gettype($object)));
}
if (!($object instanceof PhabricatorApplicationTransactionInterface)) {
throw new Exception(
pht(
'EditEngine "%s" created or loaded an invalid object: object (of '.
'class "%s") must implement "%s", but does not.',
get_class($this),
get_class($object),
'PhabricatorApplicationTransactionInterface'));
}
}
/* -( Responding to Web Requests )----------------------------------------- */
final public function buildResponse() {
$viewer = $this->getViewer();
$controller = $this->getController();
$request = $controller->getRequest();
$action = $request->getURIData('editAction');
$capabilities = array();
$use_default = false;
$require_create = true;
switch ($action) {
case 'comment':
$capabilities = array(
PhabricatorPolicyCapability::CAN_VIEW,
);
$use_default = true;
break;
case 'parameters':
$use_default = true;
break;
case 'nodefault':
case 'nocreate':
case 'nomanage':
$require_create = false;
break;
default:
break;
}
$id = $request->getURIData('id');
if ($id) {
$this->setIsCreate(false);
$object = $this->newObjectFromID($id, $capabilities);
if (!$object) {
return new Aphront404Response();
}
} else {
// Make sure the viewer has permission to create new objects of
// this type if we're going to create a new object.
if ($require_create) {
$this->requireCreateCapability();
}
$this->setIsCreate(true);
$object = $this->newEditableObject();
}
$this->validateObject($object);
if ($use_default) {
$config = $this->loadDefaultConfiguration();
if (!$config) {
return new Aphront404Response();
}
} else {
$form_key = $request->getURIData('formKey');
if (strlen($form_key)) {
$config = $this->loadEditEngineConfigurationWithIdentifier($form_key);
if (!$config) {
return new Aphront404Response();
}
if ($id && !$config->getIsEdit()) {
return $this->buildNotEditFormRespose($object, $config);
}
} else {
if ($id) {
$config = $this->loadDefaultEditConfiguration();
if (!$config) {
return $this->buildNoEditResponse($object);
}
} else {
$config = $this->loadDefaultCreateConfiguration();
if (!$config) {
return $this->buildNoCreateResponse($object);
}
}
}
}
if ($config->getIsDisabled()) {
return $this->buildDisabledFormResponse($object, $config);
}
switch ($action) {
case 'parameters':
return $this->buildParametersResponse($object);
case 'nodefault':
return $this->buildNoDefaultResponse($object);
case 'nocreate':
return $this->buildNoCreateResponse($object);
case 'nomanage':
return $this->buildNoManageResponse($object);
case 'comment':
return $this->buildCommentResponse($object);
default:
return $this->buildEditResponse($object);
}
}
private function buildCrumbs($object, $final = false) {
$controller = $this->getcontroller();
$crumbs = $controller->buildApplicationCrumbsForEditEngine();
if ($this->getIsCreate()) {
$create_text = $this->getObjectCreateShortText();
if ($final) {
$crumbs->addTextCrumb($create_text);
} else {
$edit_uri = $this->getEditURI($object);
$crumbs->addTextCrumb($create_text, $edit_uri);
}
} else {
$crumbs->addTextCrumb(
$this->getObjectEditShortText($object),
$this->getObjectViewURI($object));
$edit_text = pht('Edit');
if ($final) {
$crumbs->addTextCrumb($edit_text);
} else {
$edit_uri = $this->getEditURI($object);
$crumbs->addTextCrumb($edit_text, $edit_uri);
}
}
return $crumbs;
}
private function buildEditResponse($object) {
$viewer = $this->getViewer();
$controller = $this->getController();
$request = $controller->getRequest();
$fields = $this->buildEditFields($object);
$template = $object->getApplicationTransactionTemplate();
$validation_exception = null;
if ($request->isFormPost()) {
$submit_fields = $fields;
foreach ($submit_fields as $key => $field) {
if (!$field->shouldGenerateTransactionsFromSubmit()) {
unset($submit_fields[$key]);
continue;
}
}
// Before we read the submitted values, store a copy of what we would
// use if the form was empty so we can figure out which transactions are
// just setting things to their default values for the current form.
$defaults = array();
foreach ($submit_fields as $key => $field) {
$defaults[$key] = $field->getValueForTransaction();
}
foreach ($submit_fields as $key => $field) {
$field->setIsSubmittedForm(true);
if (!$field->shouldReadValueFromSubmit()) {
continue;
}
$field->readValueFromSubmit($request);
}
$xactions = array();
if ($this->getIsCreate()) {
$xactions[] = id(clone $template)
->setTransactionType(PhabricatorTransactions::TYPE_CREATE);
}
foreach ($submit_fields as $key => $field) {
$field_value = $field->getValueForTransaction();
$type_xactions = $field->generateTransactions(
clone $template,
array(
'value' => $field_value,
));
foreach ($type_xactions as $type_xaction) {
$default = $defaults[$key];
if ($default === $field->getValueForTransaction()) {
$type_xaction->setIsDefaultTransaction(true);
}
$xactions[] = $type_xaction;
}
}
$editor = $object->getApplicationTransactionEditor()
->setActor($viewer)
->setContentSourceFromRequest($request)
->setContinueOnNoEffect(true);
try {
$editor->applyTransactions($object, $xactions);
return $this->newEditResponse($request, $object, $xactions);
} catch (PhabricatorApplicationTransactionValidationException $ex) {
$validation_exception = $ex;
foreach ($fields as $field) {
$xaction_type = $field->getTransactionType();
if ($xaction_type === null) {
continue;
}
$message = $ex->getShortMessage($xaction_type);
if ($message === null) {
continue;
}
$field->setControlError($message);
}
}
} else {
if ($this->getIsCreate()) {
$template = $request->getStr('template');
if (strlen($template)) {
$template_object = $this->newObjectFromIdentifier(
$template,
array(
PhabricatorPolicyCapability::CAN_VIEW,
));
if (!$template_object) {
return new Aphront404Response();
}
} else {
$template_object = null;
}
if ($template_object) {
$copy_fields = $this->buildEditFields($template_object);
$copy_fields = mpull($copy_fields, null, 'getKey');
foreach ($copy_fields as $copy_key => $copy_field) {
if (!$copy_field->getIsCopyable()) {
unset($copy_fields[$copy_key]);
}
}
} else {
$copy_fields = array();
}
foreach ($fields as $field) {
if (!$field->shouldReadValueFromRequest()) {
continue;
}
$field_key = $field->getKey();
if (isset($copy_fields[$field_key])) {
$field->readValueFromField($copy_fields[$field_key]);
}
$field->readValueFromRequest($request);
}
}
}
$action_button = $this->buildEditFormActionButton($object);
if ($this->getIsCreate()) {
$header_text = $this->getFormHeaderText($object);
} else {
$header_text = $this->getObjectEditTitleText($object);
}
$show_preview = !$request->isAjax();
if ($show_preview) {
$previews = array();
foreach ($fields as $field) {
$preview = $field->getPreviewPanel();
if (!$preview) {
continue;
}
$control_id = $field->getControlID();
$preview
->setControlID($control_id)
->setPreviewURI('/transactions/remarkuppreview/');
$previews[] = $preview;
}
} else {
$previews = array();
}
$form = $this->buildEditForm($object, $fields);
if ($request->isAjax()) {
if ($this->getIsCreate()) {
$cancel_uri = $this->getObjectCreateCancelURI($object);
$submit_button = $this->getObjectCreateButtonText($object);
} else {
$cancel_uri = $this->getObjectEditCancelURI($object);
$submit_button = $this->getObjectEditButtonText($object);
}
return $this->getController()
->newDialog()
->setWidth(AphrontDialogView::WIDTH_FULL)
->setTitle($header_text)
->setValidationException($validation_exception)
->appendForm($form)
->addCancelButton($cancel_uri)
->addSubmitButton($submit_button);
}
$header = id(new PHUIHeaderView())
->setHeader($header_text);
if ($action_button) {
$header->addActionLink($action_button);
}
$crumbs = $this->buildCrumbs($object, $final = true);
$box = id(new PHUIObjectBoxView())
->setUser($viewer)
->setHeader($header)
->setValidationException($validation_exception)
->appendChild($form);
return $controller->newPage()
->setTitle($header_text)
->setCrumbs($crumbs)
->appendChild($box)
->appendChild($previews);
}
protected function newEditResponse(
AphrontRequest $request,
$object,
array $xactions) {
return id(new AphrontRedirectResponse())
->setURI($this->getObjectViewURI($object));
}
private function buildEditForm($object, array $fields) {
$viewer = $this->getViewer();
$controller = $this->getController();
$request = $controller->getRequest();
$form = id(new AphrontFormView())
->setUser($viewer);
foreach ($this->contextParameters as $param) {
$form->addHiddenInput($param, $request->getStr($param));
}
foreach ($fields as $field) {
$field->appendToForm($form);
}
if ($this->getIsCreate()) {
$cancel_uri = $this->getObjectCreateCancelURI($object);
$submit_button = $this->getObjectCreateButtonText($object);
} else {
$cancel_uri = $this->getObjectEditCancelURI($object);
$submit_button = $this->getObjectEditButtonText($object);
}
if (!$request->isAjax()) {
$form->appendControl(
id(new AphrontFormSubmitControl())
->addCancelButton($cancel_uri)
->setValue($submit_button));
}
return $form;
}
private function buildEditFormActionButton($object) {
if (!$this->isEngineConfigurable()) {
return null;
}
$viewer = $this->getViewer();
$action_view = id(new PhabricatorActionListView())
->setUser($viewer);
foreach ($this->buildEditFormActions($object) as $action) {
$action_view->addAction($action);
}
$action_button = id(new PHUIButtonView())
->setTag('a')
->setText(pht('Configure Form'))
->setHref('#')
->setIcon('fa-gear')
->setDropdownMenu($action_view);
return $action_button;
}
private function buildEditFormActions($object) {
$actions = array();
if ($this->supportsEditEngineConfiguration()) {
$engine_key = $this->getEngineKey();
$config = $this->getEditEngineConfiguration();
$can_manage = PhabricatorPolicyFilter::hasCapability(
$this->getViewer(),
$config,
PhabricatorPolicyCapability::CAN_EDIT);
if ($can_manage) {
$manage_uri = $config->getURI();
} else {
$manage_uri = $this->getEditURI(null, 'nomanage/');
}
$view_uri = "/transactions/editengine/{$engine_key}/";
$actions[] = id(new PhabricatorActionView())
->setLabel(true)
->setName(pht('Configuration'));
$actions[] = id(new PhabricatorActionView())
->setName(pht('View Form Configurations'))
->setIcon('fa-list-ul')
->setHref($view_uri);
$actions[] = id(new PhabricatorActionView())
->setName(pht('Edit Form Configuration'))
->setIcon('fa-pencil')
->setHref($manage_uri)
->setDisabled(!$can_manage)
->setWorkflow(!$can_manage);
}
$actions[] = id(new PhabricatorActionView())
->setLabel(true)
->setName(pht('Documentation'));
$actions[] = id(new PhabricatorActionView())
->setName(pht('Using HTTP Parameters'))
->setIcon('fa-book')
->setHref($this->getEditURI($object, 'parameters/'));
$doc_href = PhabricatorEnv::getDoclink('User Guide: Customizing Forms');
$actions[] = id(new PhabricatorActionView())
->setName(pht('User Guide: Customizing Forms'))
->setIcon('fa-book')
->setHref($doc_href);
return $actions;
}
final public function addActionToCrumbs(PHUICrumbsView $crumbs) {
$viewer = $this->getViewer();
$can_create = $this->hasCreateCapability();
if ($can_create) {
$configs = $this->loadUsableConfigurationsForCreate();
} else {
$configs = array();
}
$dropdown = null;
$disabled = false;
$workflow = false;
$menu_icon = 'fa-plus-square';
if (!$configs) {
if ($viewer->isLoggedIn()) {
$disabled = true;
} else {
// If the viewer isn't logged in, assume they'll get hit with a login
// dialog and are likely able to create objects after they log in.
$disabled = false;
}
$workflow = true;
if ($can_create) {
$create_uri = $this->getEditURI(null, 'nodefault/');
} else {
$create_uri = $this->getEditURI(null, 'nocreate/');
}
} else {
$config = head($configs);
$form_key = $config->getIdentifier();
$create_uri = $this->getEditURI(null, "form/{$form_key}/");
if (count($configs) > 1) {
$menu_icon = 'fa-caret-square-o-down';
$dropdown = id(new PhabricatorActionListView())
->setUser($viewer);
foreach ($configs as $config) {
$form_key = $config->getIdentifier();
$config_uri = $this->getEditURI(null, "form/{$form_key}/");
$item_icon = 'fa-plus';
$dropdown->addAction(
id(new PhabricatorActionView())
->setName($config->getDisplayName())
->setIcon($item_icon)
->setHref($config_uri));
}
}
}
$action = id(new PHUIListItemView())
->setName($this->getObjectCreateShortText())
->setHref($create_uri)
->setIcon($menu_icon)
->setWorkflow($workflow)
->setDisabled($disabled);
if ($dropdown) {
$action->setDropdownMenu($dropdown);
}
$crumbs->addAction($action);
}
final public function buildEditEngineCommentView($object) {
$config = $this->loadDefaultEditConfiguration();
if (!$config) {
// TODO: This just nukes the entire comment form if you don't have access
// to any edit forms. We might want to tailor this UX a bit.
return id(new PhabricatorApplicationTransactionCommentView())
->setNoPermission(true);
}
$viewer = $this->getViewer();
$object_phid = $object->getPHID();
$is_serious = PhabricatorEnv::getEnvConfig('phabricator.serious-business');
if ($is_serious) {
$header_text = $this->getCommentViewSeriousHeaderText($object);
$button_text = $this->getCommentViewSeriousButtonText($object);
} else {
$header_text = $this->getCommentViewHeaderText($object);
$button_text = $this->getCommentViewButtonText($object);
}
$comment_uri = $this->getEditURI($object, 'comment/');
$view = id(new PhabricatorApplicationTransactionCommentView())
->setUser($viewer)
->setObjectPHID($object_phid)
->setHeaderText($header_text)
->setAction($comment_uri)
->setSubmitButtonName($button_text);
$draft = PhabricatorVersionedDraft::loadDraft(
$object_phid,
$viewer->getPHID());
if ($draft) {
$view->setVersionedDraft($draft);
}
$view->setCurrentVersion($this->loadDraftVersion($object));
$fields = $this->buildEditFields($object);
$comment_actions = array();
foreach ($fields as $field) {
if (!$field->shouldGenerateTransactionsFromComment()) {
continue;
}
$comment_action = $field->getCommentAction();
if (!$comment_action) {
continue;
}
$key = $comment_action->getKey();
// TODO: Validate these better.
$comment_actions[$key] = $comment_action;
}
$view->setCommentActions($comment_actions);
return $view;
}
protected function loadDraftVersion($object) {
$viewer = $this->getViewer();
if (!$viewer->isLoggedIn()) {
return null;
}
$template = $object->getApplicationTransactionTemplate();
$conn_r = $template->establishConnection('r');
// Find the most recent transaction the user has written. We'll use this
// as a version number to make sure that out-of-date drafts get discarded.
$result = queryfx_one(
$conn_r,
'SELECT id AS version FROM %T
WHERE objectPHID = %s AND authorPHID = %s
ORDER BY id DESC LIMIT 1',
$template->getTableName(),
$object->getPHID(),
$viewer->getPHID());
if ($result) {
return (int)$result['version'];
} else {
return null;
}
}
/* -( Responding to HTTP Parameter Requests )------------------------------ */
/**
* Respond to a request for documentation on HTTP parameters.
*
* @param object Editable object.
* @return AphrontResponse Response object.
* @task http
*/
private function buildParametersResponse($object) {
$controller = $this->getController();
$viewer = $this->getViewer();
$request = $controller->getRequest();
$fields = $this->buildEditFields($object);
$crumbs = $this->buildCrumbs($object);
$crumbs->addTextCrumb(pht('HTTP Parameters'));
$crumbs->setBorder(true);
$header_text = pht(
'HTTP Parameters: %s',
$this->getObjectCreateShortText());
$header = id(new PHUIHeaderView())
->setHeader($header_text);
$help_view = id(new PhabricatorApplicationEditHTTPParameterHelpView())
->setUser($viewer)
->setFields($fields);
$document = id(new PHUIDocumentViewPro())
->setUser($viewer)
->setHeader($header)
->appendChild($help_view);
return $controller->newPage()
->setTitle(pht('HTTP Parameters'))
->setCrumbs($crumbs)
->appendChild($document);
}
private function buildError($object, $title, $body) {
$cancel_uri = $this->getObjectCreateCancelURI($object);
return $this->getController()
->newDialog()
->setTitle($title)
->appendParagraph($body)
->addCancelButton($cancel_uri);
}
private function buildNoDefaultResponse($object) {
return $this->buildError(
$object,
pht('No Default Create Forms'),
pht(
'This application is not configured with any forms for creating '.
'objects that are visible to you and enabled.'));
}
private function buildNoCreateResponse($object) {
return $this->buildError(
$object,
pht('No Create Permission'),
pht('You do not have permission to create these objects.'));
}
private function buildNoManageResponse($object) {
return $this->buildError(
$object,
pht('No Manage Permission'),
pht(
'You do not have permission to configure forms for this '.
'application.'));
}
private function buildNoEditResponse($object) {
return $this->buildError(
$object,
pht('No Edit Forms'),
pht(
'You do not have access to any forms which are enabled and marked '.
'as edit forms.'));
}
private function buildNotEditFormRespose($object, $config) {
return $this->buildError(
$object,
pht('Not an Edit Form'),
pht(
'This form ("%s") is not marked as an edit form, so '.
'it can not be used to edit objects.',
$config->getName()));
}
private function buildDisabledFormResponse($object, $config) {
return $this->buildError(
$object,
pht('Form Disabled'),
pht(
'This form ("%s") has been disabled, so it can not be used.',
$config->getName()));
}
private function buildCommentResponse($object) {
$viewer = $this->getViewer();
if ($this->getIsCreate()) {
return new Aphront404Response();
}
$controller = $this->getController();
$request = $controller->getRequest();
if (!$request->isFormPost()) {
return new Aphront400Response();
}
$config = $this->loadDefaultEditConfiguration();
if (!$config) {
return new Aphront404Response();
}
$fields = $this->buildEditFields($object);
$is_preview = $request->isPreviewRequest();
$view_uri = $this->getObjectViewURI($object);
$template = $object->getApplicationTransactionTemplate();
$comment_template = $template->getApplicationTransactionCommentObject();
$comment_text = $request->getStr('comment');
$actions = $request->getStr('editengine.actions');
if ($actions) {
$actions = phutil_json_decode($actions);
}
if ($is_preview) {
$version_key = PhabricatorVersionedDraft::KEY_VERSION;
$request_version = $request->getInt($version_key);
$current_version = $this->loadDraftVersion($object);
if ($request_version >= $current_version) {
$draft = PhabricatorVersionedDraft::loadOrCreateDraft(
$object->getPHID(),
$viewer->getPHID(),
$current_version);
$draft
->setProperty('comment', $comment_text)
->setProperty('actions', $actions)
->save();
}
}
$xactions = array();
if ($actions) {
$action_map = array();
foreach ($actions as $action) {
$type = idx($action, 'type');
if (!$type) {
continue;
}
if (empty($fields[$type])) {
continue;
}
$action_map[$type] = $action;
}
foreach ($action_map as $type => $action) {
$field = $fields[$type];
if (!$field->shouldGenerateTransactionsFromComment()) {
continue;
}
if (array_key_exists('initialValue', $action)) {
$field->setInitialValue($action['initialValue']);
}
$field->readValueFromComment(idx($action, 'value'));
$type_xactions = $field->generateTransactions(
clone $template,
array(
'value' => $field->getValueForTransaction(),
));
foreach ($type_xactions as $type_xaction) {
$xactions[] = $type_xaction;
}
}
}
if (strlen($comment_text) || !$xactions) {
$xactions[] = id(clone $template)
->setTransactionType(PhabricatorTransactions::TYPE_COMMENT)
->attachComment(
id(clone $comment_template)
->setContent($comment_text));
}
$editor = $object->getApplicationTransactionEditor()
->setActor($viewer)
->setContinueOnNoEffect($request->isContinueRequest())
->setContinueOnMissingFields(true)
->setContentSourceFromRequest($request)
->setIsPreview($is_preview);
try {
$xactions = $editor->applyTransactions($object, $xactions);
} catch (PhabricatorApplicationTransactionNoEffectException $ex) {
return id(new PhabricatorApplicationTransactionNoEffectResponse())
->setCancelURI($view_uri)
->setException($ex);
}
if (!$is_preview) {
PhabricatorVersionedDraft::purgeDrafts(
$object->getPHID(),
$viewer->getPHID(),
$this->loadDraftVersion($object));
}
if ($request->isAjax() && $is_preview) {
return id(new PhabricatorApplicationTransactionResponse())
->setViewer($viewer)
->setTransactions($xactions)
->setIsPreview($is_preview);
} else {
return id(new AphrontRedirectResponse())
->setURI($view_uri);
}
}
/* -( Conduit )------------------------------------------------------------ */
/**
* Respond to a Conduit edit request.
*
* This method accepts a list of transactions to apply to an object, and
* either edits an existing object or creates a new one.
*
* @task conduit
*/
final public function buildConduitResponse(ConduitAPIRequest $request) {
$viewer = $this->getViewer();
$config = $this->loadDefaultConfiguration();
if (!$config) {
throw new Exception(
pht(
'Unable to load configuration for this EditEngine ("%s").',
get_class($this)));
}
$identifier = $request->getValue('objectIdentifier');
if ($identifier) {
$this->setIsCreate(false);
$object = $this->newObjectFromIdentifier($identifier);
} else {
$this->requireCreateCapability();
$this->setIsCreate(true);
$object = $this->newEditableObject();
}
$this->validateObject($object);
$fields = $this->buildEditFields($object);
$types = $this->getConduitEditTypesFromFields($fields);
$template = $object->getApplicationTransactionTemplate();
$xactions = $this->getConduitTransactions($request, $types, $template);
$editor = $object->getApplicationTransactionEditor()
->setActor($viewer)
->setContentSourceFromConduitRequest($request)
->setContinueOnNoEffect(true);
if (!$this->getIsCreate()) {
$editor->setContinueOnMissingFields(true);
}
$xactions = $editor->applyTransactions($object, $xactions);
$xactions_struct = array();
foreach ($xactions as $xaction) {
$xactions_struct[] = array(
'phid' => $xaction->getPHID(),
);
}
return array(
'object' => array(
'id' => $object->getID(),
'phid' => $object->getPHID(),
),
'transactions' => $xactions_struct,
);
}
/**
* Generate transactions which can be applied from edit actions in a Conduit
* request.
*
* @param ConduitAPIRequest The request.
* @param list<PhabricatorEditType> Supported edit types.
* @param PhabricatorApplicationTransaction Template transaction.
* @return list<PhabricatorApplicationTransaction> Generated transactions.
* @task conduit
*/
private function getConduitTransactions(
ConduitAPIRequest $request,
array $types,
PhabricatorApplicationTransaction $template) {
$viewer = $request->getUser();
$transactions_key = 'transactions';
$xactions = $request->getValue($transactions_key);
if (!is_array($xactions)) {
throw new Exception(
pht(
'Parameter "%s" is not a list of transactions.',
$transactions_key));
}
foreach ($xactions as $key => $xaction) {
if (!is_array($xaction)) {
throw new Exception(
pht(
'Parameter "%s" must contain a list of transaction descriptions, '.
'but item with key "%s" is not a dictionary.',
$transactions_key,
$key));
}
if (!array_key_exists('type', $xaction)) {
throw new Exception(
pht(
'Parameter "%s" must contain a list of transaction descriptions, '.
'but item with key "%s" is missing a "type" field. Each '.
'transaction must have a type field.',
$transactions_key,
$key));
}
$type = $xaction['type'];
if (empty($types[$type])) {
throw new Exception(
pht(
'Transaction with key "%s" has invalid type "%s". This type is '.
'not recognized. Valid types are: %s.',
$key,
$type,
implode(', ', array_keys($types))));
}
}
$results = array();
if ($this->getIsCreate()) {
$results[] = id(clone $template)
->setTransactionType(PhabricatorTransactions::TYPE_CREATE);
}
foreach ($xactions as $xaction) {
$type = $types[$xaction['type']];
// Let the parameter type interpret the value. This allows you to
// use usernames in list<user> fields, for example.
$parameter_type = $type->getConduitParameterType();
$parameter_type->setViewer($viewer);
try {
$xaction['value'] = $parameter_type->getValue($xaction, 'value');
} catch (Exception $ex) {
throw new PhutilProxyException(
pht(
'Exception when processing transaction of type "%s".',
$xaction['type']),
$ex);
}
$type_xactions = $type->generateTransactions(
clone $template,
$xaction);
foreach ($type_xactions as $type_xaction) {
$results[] = $type_xaction;
}
}
return $results;
}
/**
* @return map<string, PhabricatorEditType>
* @task conduit
*/
private function getConduitEditTypesFromFields(array $fields) {
$types = array();
foreach ($fields as $field) {
$field_types = $field->getConduitEditTypes();
if ($field_types === null) {
continue;
}
foreach ($field_types as $field_type) {
$field_type->setField($field);
$types[$field_type->getEditType()] = $field_type;
}
}
return $types;
}
public function getConduitEditTypes() {
$config = $this->loadDefaultConfiguration();
if (!$config) {
return array();
}
$object = $this->newEditableObject();
$fields = $this->buildEditFields($object);
return $this->getConduitEditTypesFromFields($fields);
}
final public static function getAllEditEngines() {
return id(new PhutilClassMapQuery())
->setAncestorClass(__CLASS__)
->setUniqueMethod('getEngineKey')
->execute();
}
final public static function getByKey(PhabricatorUser $viewer, $key) {
return id(new PhabricatorEditEngineQuery())
->setViewer($viewer)
->withEngineKeys(array($key))
->executeOne();
}
public function getIcon() {
$application = $this->getApplication();
- return $application->getFontIcon();
+ return $application->getIcon();
}
public function loadQuickCreateItems() {
$items = array();
if (!$this->hasCreateCapability()) {
return $items;
}
$configs = $this->loadUsableConfigurationsForCreate();
if (!$configs) {
// No items to add.
} else if (count($configs) == 1) {
$config = head($configs);
$items[] = $this->newQuickCreateItem($config);
} else {
$group_name = $this->getQuickCreateMenuHeaderText();
$items[] = id(new PHUIListItemView())
->setType(PHUIListItemView::TYPE_LABEL)
->setName($group_name);
foreach ($configs as $config) {
$items[] = $this->newQuickCreateItem($config)
->setIndented(true);
}
}
return $items;
}
private function loadUsableConfigurationsForCreate() {
$viewer = $this->getViewer();
$configs = id(new PhabricatorEditEngineConfigurationQuery())
->setViewer($viewer)
->withEngineKeys(array($this->getEngineKey()))
->withIsDefault(true)
->withIsDisabled(false)
->execute();
$configs = msort($configs, 'getCreateSortKey');
return $configs;
}
private function newQuickCreateItem(
PhabricatorEditEngineConfiguration $config) {
$item_name = $config->getName();
$item_icon = $config->getIcon();
$form_key = $config->getIdentifier();
$item_uri = $this->getEditURI(null, "form/{$form_key}/");
return id(new PHUIListItemView())
->setName($item_name)
->setIcon($item_icon)
->setHref($item_uri);
}
protected function getCreateNewObjectPolicy() {
return PhabricatorPolicies::POLICY_USER;
}
private function requireCreateCapability() {
PhabricatorPolicyFilter::requireCapability(
$this->getViewer(),
$this,
PhabricatorPolicyCapability::CAN_EDIT);
}
private function hasCreateCapability() {
return PhabricatorPolicyFilter::hasCapability(
$this->getViewer(),
$this,
PhabricatorPolicyCapability::CAN_EDIT);
}
/* -( PhabricatorPolicyInterface )----------------------------------------- */
public function getPHID() {
return get_class($this);
}
public function getCapabilities() {
return array(
PhabricatorPolicyCapability::CAN_VIEW,
PhabricatorPolicyCapability::CAN_EDIT,
);
}
public function getPolicy($capability) {
switch ($capability) {
case PhabricatorPolicyCapability::CAN_VIEW:
return PhabricatorPolicies::getMostOpenPolicy();
case PhabricatorPolicyCapability::CAN_EDIT:
return $this->getCreateNewObjectPolicy();
}
}
public function hasAutomaticCapability($capability, PhabricatorUser $viewer) {
return false;
}
public function describeAutomaticCapability($capability) {
return null;
}
}
diff --git a/src/applications/transactions/feed/PhabricatorApplicationTransactionFeedStory.php b/src/applications/transactions/feed/PhabricatorApplicationTransactionFeedStory.php
index 3a840d73a1..5e9d7c40b3 100644
--- a/src/applications/transactions/feed/PhabricatorApplicationTransactionFeedStory.php
+++ b/src/applications/transactions/feed/PhabricatorApplicationTransactionFeedStory.php
@@ -1,163 +1,163 @@
<?php
/**
* @concrete-extensible
*/
class PhabricatorApplicationTransactionFeedStory
extends PhabricatorFeedStory {
public function getPrimaryObjectPHID() {
return $this->getValue('objectPHID');
}
public function getRequiredObjectPHIDs() {
return $this->getValue('transactionPHIDs');
}
public function getRequiredHandlePHIDs() {
$phids = array();
$phids[] = $this->getValue('objectPHID');
foreach ($this->getValue('transactionPHIDs') as $xaction_phid) {
$xaction = $this->getObject($xaction_phid);
foreach ($xaction->getRequiredHandlePHIDs() as $handle_phid) {
$phids[] = $handle_phid;
}
}
return $phids;
}
protected function getPrimaryTransactionPHID() {
return head($this->getValue('transactionPHIDs'));
}
public function getPrimaryTransaction() {
return $this->getObject($this->getPrimaryTransactionPHID());
}
public function getFieldStoryMarkupFields() {
$xaction_phids = $this->getValue('transactionPHIDs');
$fields = array();
foreach ($xaction_phids as $xaction_phid) {
$xaction = $this->getObject($xaction_phid);
foreach ($xaction->getMarkupFieldsForFeed($this) as $field) {
$fields[] = $field;
}
}
return $fields;
}
public function getMarkupText($field) {
$xaction_phids = $this->getValue('transactionPHIDs');
foreach ($xaction_phids as $xaction_phid) {
$xaction = $this->getObject($xaction_phid);
foreach ($xaction->getMarkupFieldsForFeed($this) as $xaction_field) {
if ($xaction_field == $field) {
return $xaction->getMarkupTextForFeed($this, $field);
}
}
}
return null;
}
public function renderView() {
$view = $this->newStoryView();
$handle = $this->getHandle($this->getPrimaryObjectPHID());
$view->setHref($handle->getURI());
$type = phid_get_type($handle->getPHID());
$phid_types = PhabricatorPHIDType::getAllTypes();
$icon = null;
if (!empty($phid_types[$type])) {
$phid_type = $phid_types[$type];
$class = $phid_type->getPHIDTypeApplicationClass();
if ($class) {
$application = PhabricatorApplication::getByClass($class);
- $icon = $application->getFontIcon();
+ $icon = $application->getIcon();
}
}
$view->setAppIcon($icon);
$xaction_phids = $this->getValue('transactionPHIDs');
$xaction = $this->getPrimaryTransaction();
$xaction->setHandles($this->getHandles());
$view->setTitle($xaction->getTitleForFeed());
foreach ($xaction_phids as $xaction_phid) {
$secondary_xaction = $this->getObject($xaction_phid);
$secondary_xaction->setHandles($this->getHandles());
$body = $secondary_xaction->getBodyForFeed($this);
if (nonempty($body)) {
$view->appendChild($body);
}
}
$view->setImage(
$this->getHandle($xaction->getAuthorPHID())->getImageURI());
return $view;
}
public function renderText() {
$xaction = $this->getPrimaryTransaction();
$old_target = $xaction->getRenderingTarget();
$new_target = PhabricatorApplicationTransaction::TARGET_TEXT;
$xaction->setRenderingTarget($new_target);
$xaction->setHandles($this->getHandles());
$text = $xaction->getTitleForFeed();
$xaction->setRenderingTarget($old_target);
return $text;
}
public function renderTextBody() {
$all_bodies = '';
$new_target = PhabricatorApplicationTransaction::TARGET_TEXT;
$xaction_phids = $this->getValue('transactionPHIDs');
foreach ($xaction_phids as $xaction_phid) {
$secondary_xaction = $this->getObject($xaction_phid);
$old_target = $secondary_xaction->getRenderingTarget();
$secondary_xaction->setRenderingTarget($new_target);
$secondary_xaction->setHandles($this->getHandles());
$body = $secondary_xaction->getBodyForMail();
if (nonempty($body)) {
$all_bodies .= $body."\n";
}
$secondary_xaction->setRenderingTarget($old_target);
}
return trim($all_bodies);
}
public function getImageURI() {
$author_phid = $this->getPrimaryTransaction()->getAuthorPHID();
return $this->getHandle($author_phid)->getImageURI();
}
public function getURI() {
$handle = $this->getHandle($this->getPrimaryObjectPHID());
return PhabricatorEnv::getProductionURI($handle->getURI());
}
public function renderAsTextForDoorkeeper(
DoorkeeperFeedStoryPublisher $publisher) {
$xactions = array();
$xaction_phids = $this->getValue('transactionPHIDs');
foreach ($xaction_phids as $xaction_phid) {
$xaction = $this->getObject($xaction_phid);
$xaction->setHandles($this->getHandles());
$xactions[] = $xaction;
}
$primary = $this->getPrimaryTransaction();
return $primary->renderAsTextForDoorkeeper($publisher, $this, $xactions);
}
}
diff --git a/src/applications/transactions/query/PhabricatorEditEngineSearchEngine.php b/src/applications/transactions/query/PhabricatorEditEngineSearchEngine.php
index 4ba4ed9b12..70cd4cd1a3 100644
--- a/src/applications/transactions/query/PhabricatorEditEngineSearchEngine.php
+++ b/src/applications/transactions/query/PhabricatorEditEngineSearchEngine.php
@@ -1,87 +1,87 @@
<?php
final class PhabricatorEditEngineSearchEngine
extends PhabricatorApplicationSearchEngine {
public function getResultTypeDescription() {
return pht('Edit Engines');
}
public function getApplicationClassName() {
return 'PhabricatorTransactionsApplication';
}
public function newQuery() {
return id(new PhabricatorEditEngineQuery());
}
protected function buildQueryFromParameters(array $map) {
$query = $this->newQuery();
return $query;
}
protected function buildCustomSearchFields() {
return array();
}
protected function getDefaultFieldOrder() {
return array();
}
protected function getURI($path) {
return '/transactions/editengine/'.$path;
}
protected function getBuiltinQueryNames() {
$names = array(
'all' => pht('All Edit Engines'),
);
return $names;
}
public function buildSavedQueryFromBuiltin($query_key) {
$query = $this->newSavedQuery();
$query->setQueryKey($query_key);
switch ($query_key) {
case 'all':
return $query;
}
return parent::buildSavedQueryFromBuiltin($query_key);
}
protected function renderResultList(
array $engines,
PhabricatorSavedQuery $query,
array $handles) {
assert_instances_of($engines, 'PhabricatorEditEngine');
$viewer = $this->requireViewer();
$list = id(new PHUIObjectItemListView())
->setUser($viewer);
foreach ($engines as $engine) {
if (!$engine->isEngineConfigurable()) {
continue;
}
$engine_key = $engine->getEngineKey();
$query_uri = "/transactions/editengine/{$engine_key}/";
$application = $engine->getApplication();
- $app_icon = $application->getFontIcon();
+ $app_icon = $application->getIcon();
$item = id(new PHUIObjectItemView())
->setHeader($engine->getSummaryHeader())
->setHref($query_uri)
->setStatusIcon($app_icon)
->addAttribute($engine->getSummaryText());
$list->addItem($item);
}
return id(new PhabricatorApplicationSearchResultView())
->setObjectList($list);
}
}
diff --git a/src/applications/uiexample/application/PhabricatorUIExamplesApplication.php b/src/applications/uiexample/application/PhabricatorUIExamplesApplication.php
index 3b3d38ef14..350417ecc6 100644
--- a/src/applications/uiexample/application/PhabricatorUIExamplesApplication.php
+++ b/src/applications/uiexample/application/PhabricatorUIExamplesApplication.php
@@ -1,50 +1,50 @@
<?php
final class PhabricatorUIExamplesApplication extends PhabricatorApplication {
public function getBaseURI() {
return '/uiexample/';
}
public function getShortDescription() {
return pht('Developer UI Examples');
}
public function getName() {
return pht('UIExamples');
}
- public function getFontIcon() {
+ public function getIcon() {
return 'fa-magnet';
}
public function getTitleGlyph() {
return "\xE2\x8F\x9A";
}
public function getFlavorText() {
return pht('A gallery of modern art.');
}
public function getApplicationGroup() {
return self::GROUP_DEVELOPER;
}
public function isPrototype() {
return true;
}
public function getApplicationOrder() {
return 0.110;
}
public function getRoutes() {
return array(
'/uiexample/' => array(
'' => 'PhabricatorUIExampleRenderController',
'view/(?P<class>[^/]+)/' => 'PhabricatorUIExampleRenderController',
),
);
}
}
diff --git a/src/applications/uiexample/examples/PHUIActionPanelExample.php b/src/applications/uiexample/examples/PHUIActionPanelExample.php
index c57617a566..9294dcbea6 100644
--- a/src/applications/uiexample/examples/PHUIActionPanelExample.php
+++ b/src/applications/uiexample/examples/PHUIActionPanelExample.php
@@ -1,92 +1,92 @@
<?php
final class PHUIActionPanelExample extends PhabricatorUIExample {
public function getName() {
return pht('Action Panel');
}
public function getDescription() {
return pht('A panel with strong tendencies for inciting ACTION!');
}
public function renderExample() {
$view = id(new AphrontMultiColumnView())
->setFluidLayout(true);
/* Action Panels */
$panel1 = id(new PHUIActionPanelView())
- ->setFontIcon('fa-book')
+ ->setIcon('fa-book')
->setHeader(pht('Read Documentation'))
->setHref('#')
->setSubHeader(pht('Reading is a common way to learn about things.'))
->setState(PHUIActionPanelView::COLOR_BLUE);
$view->addColumn($panel1);
$panel2 = id(new PHUIActionPanelView())
- ->setFontIcon('fa-server')
+ ->setIcon('fa-server')
->setHeader(pht('Launch Instance'))
->setHref('#')
->setSubHeader(pht("Maybe this is what you're likely here for."))
->setState(PHUIActionPanelView::COLOR_RED);
$view->addColumn($panel2);
$panel3 = id(new PHUIActionPanelView())
- ->setFontIcon('fa-group')
+ ->setIcon('fa-group')
->setHeader(pht('Code with Friends'))
->setHref('#')
->setSubHeader(pht('Writing code is much more fun with friends!'))
->setState(PHUIActionPanelView::COLOR_YELLOW);
$view->addColumn($panel3);
$panel4 = id(new PHUIActionPanelView())
- ->setFontIcon('fa-cloud-download')
+ ->setIcon('fa-cloud-download')
->setHeader(pht('Download Data'))
->setHref('#')
->setSubHeader(pht('Need a backup of all your kitten memes?'))
->setState(PHUIActionPanelView::COLOR_PINK);
$view->addColumn($panel4);
$view2 = id(new AphrontMultiColumnView())
->setFluidLayout(true);
/* Action Panels */
$panel1 = id(new PHUIActionPanelView())
- ->setFontIcon('fa-credit-card')
+ ->setIcon('fa-credit-card')
->setHeader(pht('Account Balance'))
->setHref('#')
->setSubHeader(pht('You were last billed $2,245.12 on Dec 12, 2014.'))
->setState(PHUIActionPanelView::COLOR_GREEN);
$view2->addColumn($panel1);
$panel2 = id(new PHUIActionPanelView())
->setBigText(true)
->setHeader(pht('Instance Users'))
->setHref('#')
->setSubHeader(
pht('148'));
$view2->addColumn($panel2);
$panel3 = id(new PHUIActionPanelView())
->setBigText(true)
->setHeader(pht('Next Maintenance Window'))
->setHref('#')
->setSubHeader(
pht('March 12'))
->setState(PHUIActionPanelView::COLOR_ORANGE);
$view2->addColumn($panel3);
$panel4 = id(new PHUIActionPanelView())
->setBigText(true)
->setHeader(pht('Lines of Code'))
->setHref('#')
->setSubHeader(pht('1,113,377'))
->setState(PHUIActionPanelView::COLOR_INDIGO);
$view2->addColumn($panel4);
$view = phutil_tag_div('mlb', $view);
return phutil_tag_div('ml', array($view, $view2));
}
}
diff --git a/src/applications/uiexample/examples/PHUIIconExample.php b/src/applications/uiexample/examples/PHUIIconExample.php
index ad31caba8d..1db4aa202f 100644
--- a/src/applications/uiexample/examples/PHUIIconExample.php
+++ b/src/applications/uiexample/examples/PHUIIconExample.php
@@ -1,207 +1,207 @@
<?php
final class PHUIIconExample extends PhabricatorUIExample {
public function getName() {
return pht('Icons and Images');
}
public function getDescription() {
return pht('Easily render icons or images with links and sprites.');
}
private function listTransforms() {
return array(
'ph-rotate-90',
'ph-rotate-180',
'ph-rotate-270',
'ph-flip-horizontal',
'ph-flip-vertical',
'ph-spin',
);
}
public function renderExample() {
- $colors = PHUIIconView::getFontIconColors();
+ $colors = PHUIIconView::getIconColors();
$colors = array_merge(array(null), $colors);
- $fas = PHUIIconView::getFontIcons();
+ $fas = PHUIIconView::getIcons();
$trans = $this->listTransforms();
$cicons = array();
foreach ($colors as $color) {
$cicons[] = id(new PHUIIconView())
->addClass('phui-example-icon-transform')
->setIcon('fa-tag '.$color)
->setText(pht('fa-tag %s', $color));
}
$ficons = array();
sort($fas);
foreach ($fas as $fa) {
$ficons[] = id(new PHUIIconView())
->addClass('phui-example-icon-name')
->setIcon($fa)
->setText($fa);
}
$person1 = new PHUIIconView();
$person1->setHeadSize(PHUIIconView::HEAD_MEDIUM);
$person1->setHref('http://en.wikipedia.org/wiki/George_Washington');
$person1->setImage(
celerity_get_resource_uri('/rsrc/image/people/washington.png'));
$person2 = new PHUIIconView();
$person2->setHeadSize(PHUIIconView::HEAD_MEDIUM);
$person2->setHref('http://en.wikipedia.org/wiki/Warren_G._Harding');
$person2->setImage(
celerity_get_resource_uri('/rsrc/image/people/harding.png'));
$person3 = new PHUIIconView();
$person3->setHeadSize(PHUIIconView::HEAD_MEDIUM);
$person3->setHref('http://en.wikipedia.org/wiki/William_Howard_Taft');
$person3->setImage(
celerity_get_resource_uri('/rsrc/image/people/taft.png'));
$person4 = new PHUIIconView();
$person4->setHeadSize(PHUIIconView::HEAD_SMALL);
$person4->setHref('http://en.wikipedia.org/wiki/George_Washington');
$person4->setImage(
celerity_get_resource_uri('/rsrc/image/people/washington.png'));
$person5 = new PHUIIconView();
$person5->setHeadSize(PHUIIconView::HEAD_SMALL);
$person5->setHref('http://en.wikipedia.org/wiki/Warren_G._Harding');
$person5->setImage(
celerity_get_resource_uri('/rsrc/image/people/harding.png'));
$person6 = new PHUIIconView();
$person6->setHeadSize(PHUIIconView::HEAD_SMALL);
$person6->setHref('http://en.wikipedia.org/wiki/William_Howard_Taft');
$person6->setImage(
celerity_get_resource_uri('/rsrc/image/people/taft.png'));
$tokens = array(
'like-1',
'like-2',
'heart-1',
'heart-2',
);
$tokenview = array();
foreach ($tokens as $token) {
$tokenview[] =
id(new PHUIIconView())
->setSpriteSheet(PHUIIconView::SPRITE_TOKENS)
->setSpriteIcon($token);
}
$logins = array(
'Asana',
'Dropbox',
'Google',
'Github',
);
$loginview = array();
foreach ($logins as $login) {
$loginview[] =
id(new PHUIIconView())
->setSpriteSheet(PHUIIconView::SPRITE_LOGIN)
->setSpriteIcon($login)
->addClass(PHUI::MARGIN_SMALL_RIGHT);
}
$circles = array('fa-pencil', 'fa-chevron-left', 'fa-chevron-right');
$circleview = array();
foreach ($circles as $circle) {
$circleview[] =
id(new PHUIIconCircleView())
->setIcon($circle)
->setHref('#')
->addClass('mmr');
}
$circles = array('fa-plus', 'fa-bars', 'fa-paw');
foreach ($circles as $circle) {
$circleview[] =
id(new PHUIIconCircleView())
->setIcon($circle)
->setSize(PHUIIconCircleView::MEDIUM)
->setHref('#')
->addClass('mmr');
}
$layout_cicons = id(new PHUIBoxView())
->appendChild($cicons)
->addMargin(PHUI::MARGIN_LARGE);
$layout_fa = id(new PHUIBoxView())
->appendChild($ficons)
->addMargin(PHUI::MARGIN_LARGE);
$layout2 = id(new PHUIBoxView())
->appendChild(array($person1, $person2, $person3))
->addMargin(PHUI::MARGIN_MEDIUM);
$layout2a = id(new PHUIBoxView())
->appendChild(array($person4, $person5, $person6))
->addMargin(PHUI::MARGIN_MEDIUM);
$layout3 = id(new PHUIBoxView())
->appendChild($tokenview)
->addMargin(PHUI::MARGIN_MEDIUM);
$layout4 = id(new PHUIBoxView())
->appendChild($circleview)
->addMargin(PHUI::MARGIN_MEDIUM);
$layout5 = id(new PHUIBoxView())
->appendChild($loginview)
->addMargin(PHUI::MARGIN_MEDIUM);
$fa_link = phutil_tag(
'a',
array(
'href' => 'http://fontawesome.io',
),
'http://fontawesome.io');
$fa_text = pht('Font Awesome by Dave Gandy - %s', $fa_link);
$fontawesome = id(new PHUIObjectBoxView())
->setHeaderText($fa_text)
->appendChild($layout_fa);
$transforms = id(new PHUIObjectBoxView())
->setHeaderText(pht('Colors and Transforms'))
->appendChild($layout_cicons);
$wrap2 = id(new PHUIObjectBoxView())
->setHeaderText(pht('People!'))
->appendChild(array($layout2, $layout2a));
$wrap3 = id(new PHUIObjectBoxView())
->setHeaderText(pht('Tokens'))
->appendChild($layout3);
$wrap4 = id(new PHUIObjectBoxView())
->setHeaderText(pht('Circles'))
->appendChild($layout4);
$wrap5 = id(new PHUIObjectBoxView())
->setHeaderText(pht('Authentication'))
->appendChild($layout5);
return phutil_tag(
'div',
array(
'class' => 'phui-icon-example',
),
array(
$fontawesome,
$transforms,
$wrap2,
$wrap3,
$wrap4,
$wrap5,
));
}
}
diff --git a/src/applications/xhprof/application/PhabricatorXHProfApplication.php b/src/applications/xhprof/application/PhabricatorXHProfApplication.php
index ad480a821a..999e0378a5 100644
--- a/src/applications/xhprof/application/PhabricatorXHProfApplication.php
+++ b/src/applications/xhprof/application/PhabricatorXHProfApplication.php
@@ -1,39 +1,39 @@
<?php
final class PhabricatorXHProfApplication extends PhabricatorApplication {
public function getBaseURI() {
return '/xhprof/';
}
public function getName() {
return pht('XHProf');
}
public function getShortDescription() {
return pht('PHP Profiling Tool');
}
- public function getFontIcon() {
+ public function getIcon() {
return 'fa-stethoscope';
}
public function getTitleGlyph() {
return "\xE2\x98\x84";
}
public function getApplicationGroup() {
return self::GROUP_DEVELOPER;
}
public function getRoutes() {
return array(
'/xhprof/' => array(
'' => 'PhabricatorXHProfSampleListController',
'list/(?P<view>[^/]+)/' => 'PhabricatorXHProfSampleListController',
'profile/(?P<phid>[^/]+)/' => 'PhabricatorXHProfProfileController',
),
);
}
}
diff --git a/src/infrastructure/markup/rule/PhabricatorNavigationRemarkupRule.php b/src/infrastructure/markup/rule/PhabricatorNavigationRemarkupRule.php
index 857a0c10bd..458ee5b834 100644
--- a/src/infrastructure/markup/rule/PhabricatorNavigationRemarkupRule.php
+++ b/src/infrastructure/markup/rule/PhabricatorNavigationRemarkupRule.php
@@ -1,112 +1,112 @@
<?php
final class PhabricatorNavigationRemarkupRule extends PhutilRemarkupRule {
public function getPriority() {
return 200.0;
}
public function apply($text) {
return preg_replace_callback(
'@{nav\b((?:[^}\\\\]+|\\\\.)*)}@m',
array($this, 'markupNavigation'),
$text);
}
public function markupNavigation(array $matches) {
if (!$this->isFlatText($matches[0])) {
return $matches[0];
}
$elements = ltrim($matches[1], ", \n");
$elements = explode('>', $elements);
$defaults = array(
'name' => null,
'type' => 'link',
'href' => null,
'icon' => null,
);
$sequence = array();
$parser = new PhutilSimpleOptions();
foreach ($elements as $element) {
if (strpos($element, '=') === false) {
$sequence[] = array(
'name' => trim($element),
) + $defaults;
} else {
$sequence[] = $parser->parse($element) + $defaults;
}
}
if ($this->getEngine()->isTextMode()) {
return implode(' > ', ipull($sequence, 'name'));
}
static $icon_names;
if (!$icon_names) {
- $icon_names = array_fuse(PHUIIconView::getFontIcons());
+ $icon_names = array_fuse(PHUIIconView::getIcons());
}
$out = array();
foreach ($sequence as $item) {
$item_name = $item['name'];
$item_color = PHUITagView::COLOR_GREY;
if ($item['type'] == 'instructions') {
$item_name = phutil_tag('em', array(), $item_name);
$item_color = PHUITagView::COLOR_INDIGO;
}
$tag = id(new PHUITagView())
->setType(PHUITagView::TYPE_SHADE)
->setShade($item_color)
->setName($item_name);
if ($item['icon']) {
$icon_name = 'fa-'.$item['icon'];
if (isset($icon_names[$icon_name])) {
$tag->setIcon($icon_name);
}
}
if ($item['href'] !== null) {
if (PhabricatorEnv::isValidRemoteURIForLink($item['href'])) {
$tag->setHref($item['href']);
$tag->setExternal(true);
}
}
$out[] = $tag;
}
if ($this->getEngine()->isHTMLMailMode()) {
$arrow_attr = array(
'style' => 'color: #92969D;',
);
$nav_attr = array();
} else {
$arrow_attr = array(
'class' => 'remarkup-nav-sequence-arrow',
);
$nav_attr = array(
'class' => 'remarkup-nav-sequence',
);
}
$joiner = phutil_tag(
'span',
$arrow_attr,
" \xE2\x86\x92 ");
$out = phutil_implode_html($joiner, $out);
$out = phutil_tag(
'span',
$nav_attr,
$out);
return $this->getEngine()->storeText($out);
}
}
diff --git a/src/view/page/PhabricatorStandardPageView.php b/src/view/page/PhabricatorStandardPageView.php
index b26ce6297b..e85abb2140 100644
--- a/src/view/page/PhabricatorStandardPageView.php
+++ b/src/view/page/PhabricatorStandardPageView.php
@@ -1,839 +1,839 @@
<?php
/**
* This is a standard Phabricator page with menus, Javelin, DarkConsole, and
* basic styles.
*/
final class PhabricatorStandardPageView extends PhabricatorBarePageView
implements AphrontResponseProducerInterface {
private $baseURI;
private $applicationName;
private $glyph;
private $menuContent;
private $showChrome = true;
private $classes = array();
private $disableConsole;
private $pageObjects = array();
private $applicationMenu;
private $showFooter = true;
private $showDurableColumn = true;
private $quicksandConfig = array();
private $crumbs;
private $navigation;
public function setShowFooter($show_footer) {
$this->showFooter = $show_footer;
return $this;
}
public function getShowFooter() {
return $this->showFooter;
}
public function setApplicationMenu($application_menu) {
// NOTE: For now, this can either be a PHUIListView or a
// PHUIApplicationMenuView.
$this->applicationMenu = $application_menu;
return $this;
}
public function getApplicationMenu() {
return $this->applicationMenu;
}
public function setApplicationName($application_name) {
$this->applicationName = $application_name;
return $this;
}
public function setDisableConsole($disable) {
$this->disableConsole = $disable;
return $this;
}
public function getApplicationName() {
return $this->applicationName;
}
public function setBaseURI($base_uri) {
$this->baseURI = $base_uri;
return $this;
}
public function getBaseURI() {
return $this->baseURI;
}
public function setShowChrome($show_chrome) {
$this->showChrome = $show_chrome;
return $this;
}
public function getShowChrome() {
return $this->showChrome;
}
public function addClass($class) {
$this->classes[] = $class;
return $this;
}
public function setPageObjectPHIDs(array $phids) {
$this->pageObjects = $phids;
return $this;
}
public function setShowDurableColumn($show) {
$this->showDurableColumn = $show;
return $this;
}
public function getShowDurableColumn() {
$request = $this->getRequest();
if (!$request) {
return false;
}
$viewer = $request->getUser();
if (!$viewer->isLoggedIn()) {
return false;
}
$conpherence_installed = PhabricatorApplication::isClassInstalledForViewer(
'PhabricatorConpherenceApplication',
$viewer);
if (!$conpherence_installed) {
return false;
}
if ($this->isQuicksandBlacklistURI()) {
return false;
}
return true;
}
private function isQuicksandBlacklistURI() {
$request = $this->getRequest();
if (!$request) {
return false;
}
$patterns = $this->getQuicksandURIPatternBlacklist();
$path = $request->getRequestURI()->getPath();
foreach ($patterns as $pattern) {
if (preg_match('(^'.$pattern.'$)', $path)) {
return true;
}
}
return false;
}
public function getDurableColumnVisible() {
$column_key = PhabricatorUserPreferences::PREFERENCE_CONPHERENCE_COLUMN;
return (bool)$this->getUserPreference($column_key, 0);
}
public function addQuicksandConfig(array $config) {
$this->quicksandConfig = $config + $this->quicksandConfig;
return $this;
}
public function getQuicksandConfig() {
return $this->quicksandConfig;
}
public function setCrumbs(PHUICrumbsView $crumbs) {
$this->crumbs = $crumbs;
return $this;
}
public function getCrumbs() {
return $this->crumbs;
}
public function setNavigation(AphrontSideNavFilterView $navigation) {
$this->navigation = $navigation;
return $this;
}
public function getNavigation() {
return $this->navigation;
}
public function getTitle() {
$glyph_key = PhabricatorUserPreferences::PREFERENCE_TITLES;
if ($this->getUserPreference($glyph_key) == 'text') {
$use_glyph = false;
} else {
$use_glyph = true;
}
$title = parent::getTitle();
$prefix = null;
if ($use_glyph) {
$prefix = $this->getGlyph();
} else {
$application_name = $this->getApplicationName();
if (strlen($application_name)) {
$prefix = '['.$application_name.']';
}
}
if (strlen($prefix)) {
$title = $prefix.' '.$title;
}
return $title;
}
protected function willRenderPage() {
parent::willRenderPage();
if (!$this->getRequest()) {
throw new Exception(
pht(
'You must set the %s to render a %s.',
'Request',
__CLASS__));
}
$console = $this->getConsole();
require_celerity_resource('phabricator-core-css');
require_celerity_resource('phabricator-zindex-css');
require_celerity_resource('phui-button-css');
require_celerity_resource('phui-spacing-css');
require_celerity_resource('phui-form-css');
require_celerity_resource('phabricator-standard-page-view');
require_celerity_resource('conpherence-durable-column-view');
require_celerity_resource('font-lato');
require_celerity_resource('font-aleo');
Javelin::initBehavior('workflow', array());
$request = $this->getRequest();
$user = null;
if ($request) {
$user = $request->getUser();
}
if ($user) {
$default_img_uri =
celerity_get_resource_uri(
'rsrc/image/icon/fatcow/document_black.png');
$download_form = phabricator_form(
$user,
array(
'action' => '#',
'method' => 'POST',
'class' => 'lightbox-download-form',
'sigil' => 'download',
),
phutil_tag(
'button',
array(),
pht('Download')));
Javelin::initBehavior(
'lightbox-attachments',
array(
'defaultImageUri' => $default_img_uri,
'downloadForm' => $download_form,
));
}
Javelin::initBehavior('aphront-form-disable-on-submit');
Javelin::initBehavior('toggle-class', array());
Javelin::initBehavior('history-install');
Javelin::initBehavior('phabricator-gesture');
$current_token = null;
if ($user) {
$current_token = $user->getCSRFToken();
}
Javelin::initBehavior(
'refresh-csrf',
array(
'tokenName' => AphrontRequest::getCSRFTokenName(),
'header' => AphrontRequest::getCSRFHeaderName(),
'viaHeader' => AphrontRequest::getViaHeaderName(),
'current' => $current_token,
));
Javelin::initBehavior('device');
Javelin::initBehavior(
'high-security-warning',
$this->getHighSecurityWarningConfig());
if ($console) {
require_celerity_resource('aphront-dark-console-css');
$headers = array();
if (DarkConsoleXHProfPluginAPI::isProfilerStarted()) {
$headers[DarkConsoleXHProfPluginAPI::getProfilerHeader()] = 'page';
}
if (DarkConsoleServicesPlugin::isQueryAnalyzerRequested()) {
$headers[DarkConsoleServicesPlugin::getQueryAnalyzerHeader()] = true;
}
Javelin::initBehavior(
'dark-console',
$this->getConsoleConfig());
// Change this to initBehavior when there is some behavior to initialize
require_celerity_resource('javelin-behavior-error-log');
}
if ($user) {
$viewer = $user;
} else {
$viewer = new PhabricatorUser();
}
$menu = id(new PhabricatorMainMenuView())
->setUser($viewer);
if ($this->getController()) {
$menu->setController($this->getController());
}
$application_menu = $this->getApplicationMenu();
if ($application_menu) {
if ($application_menu instanceof PHUIApplicationMenuView) {
$crumbs = $this->getCrumbs();
if ($crumbs) {
$application_menu->setCrumbs($crumbs);
}
$application_menu = $application_menu->buildListView();
}
$menu->setApplicationMenu($application_menu);
}
$this->menuContent = $menu->render();
}
protected function getHead() {
$monospaced = null;
$request = $this->getRequest();
if ($request) {
$user = $request->getUser();
if ($user) {
$monospaced = $user->loadPreferences()->getPreference(
PhabricatorUserPreferences::PREFERENCE_MONOSPACED);
}
}
$response = CelerityAPI::getStaticResourceResponse();
$font_css = null;
if (!empty($monospaced)) {
// We can't print this normally because escaping quotation marks will
// break the CSS. Instead, filter it strictly and then mark it as safe.
$monospaced = new PhutilSafeHTML(
PhabricatorUserPreferences::filterMonospacedCSSRule(
$monospaced));
$font_css = hsprintf(
'<style type="text/css">'.
'.PhabricatorMonospaced, '.
'.phabricator-remarkup .remarkup-code-block '.
'.remarkup-code { font: %s !important; } '.
'</style>',
$monospaced);
}
return hsprintf(
'%s%s%s',
parent::getHead(),
$font_css,
$response->renderSingleResource('javelin-magical-init', 'phabricator'));
}
public function setGlyph($glyph) {
$this->glyph = $glyph;
return $this;
}
public function getGlyph() {
return $this->glyph;
}
protected function willSendResponse($response) {
$request = $this->getRequest();
$response = parent::willSendResponse($response);
$console = $request->getApplicationConfiguration()->getConsole();
if ($console) {
$response = PhutilSafeHTML::applyFunction(
'str_replace',
hsprintf('<darkconsole />'),
$console->render($request),
$response);
}
return $response;
}
protected function getBody() {
$user = null;
$request = $this->getRequest();
if ($request) {
$user = $request->getUser();
}
$header_chrome = null;
if ($this->getShowChrome()) {
$header_chrome = $this->menuContent;
}
$classes = array();
$classes[] = 'main-page-frame';
$developer_warning = null;
if (PhabricatorEnv::getEnvConfig('phabricator.developer-mode') &&
DarkConsoleErrorLogPluginAPI::getErrors()) {
$developer_warning = phutil_tag_div(
'aphront-developer-error-callout',
pht(
'This page raised PHP errors. Find them in DarkConsole '.
'or the error log.'));
}
// Render the "you have unresolved setup issues..." warning.
$setup_warning = null;
if ($user && $user->getIsAdmin()) {
$open = PhabricatorSetupCheck::getOpenSetupIssueKeys();
if ($open) {
$classes[] = 'page-has-warning';
$setup_warning = phutil_tag_div(
'setup-warning-callout',
phutil_tag(
'a',
array(
'href' => '/config/issue/',
'title' => implode(', ', $open),
),
pht('You have %d unresolved setup issue(s)...', count($open))));
}
}
$main_page = phutil_tag(
'div',
array(
'id' => 'phabricator-standard-page',
'class' => 'phabricator-standard-page',
),
array(
$developer_warning,
$header_chrome,
$setup_warning,
phutil_tag(
'div',
array(
'id' => 'phabricator-standard-page-body',
'class' => 'phabricator-standard-page-body',
),
$this->renderPageBodyContent()),
));
$durable_column = null;
if ($this->getShowDurableColumn()) {
$is_visible = $this->getDurableColumnVisible();
$durable_column = id(new ConpherenceDurableColumnView())
->setSelectedConpherence(null)
->setUser($user)
->setQuicksandConfig($this->buildQuicksandConfig())
->setVisible($is_visible)
->setInitialLoad(true);
}
Javelin::initBehavior('quicksand-blacklist', array(
'patterns' => $this->getQuicksandURIPatternBlacklist(),
));
return phutil_tag(
'div',
array(
'class' => implode(' ', $classes),
),
array(
$main_page,
$durable_column,
));
}
private function renderPageBodyContent() {
$console = $this->getConsole();
$body = parent::getBody();
$footer = $this->renderFooter();
$nav = $this->getNavigation();
if ($nav) {
$crumbs = $this->getCrumbs();
if ($crumbs) {
$nav->setCrumbs($crumbs);
}
$nav->appendChild($body);
$nav->appendFooter($footer);
$content = phutil_implode_html('', array($nav->render()));
} else {
$contnet = array();
$crumbs = $this->getCrumbs();
if ($crumbs) {
$content[] = $crumbs;
}
$content[] = $body;
$content[] = $footer;
$content = phutil_implode_html('', $content);
}
return array(
($console ? hsprintf('<darkconsole />') : null),
$content,
);
}
protected function getTail() {
$request = $this->getRequest();
$user = $request->getUser();
$tail = array(
parent::getTail(),
);
$response = CelerityAPI::getStaticResourceResponse();
if (PhabricatorEnv::getEnvConfig('notification.enabled')) {
if ($user && $user->isLoggedIn()) {
$client_uri = PhabricatorEnv::getEnvConfig('notification.client-uri');
$client_uri = new PhutilURI($client_uri);
if ($client_uri->getDomain() == 'localhost') {
$this_host = $this->getRequest()->getHost();
$this_host = new PhutilURI('http://'.$this_host.'/');
$client_uri->setDomain($this_host->getDomain());
}
if ($request->isHTTPS()) {
$client_uri->setProtocol('wss');
} else {
$client_uri->setProtocol('ws');
}
Javelin::initBehavior(
'aphlict-listen',
array(
'websocketURI' => (string)$client_uri,
) + $this->buildAphlictListenConfigData());
}
}
$tail[] = $response->renderHTMLFooter();
return $tail;
}
protected function getBodyClasses() {
$classes = array();
if (!$this->getShowChrome()) {
$classes[] = 'phabricator-chromeless-page';
}
$agent = AphrontRequest::getHTTPHeader('User-Agent');
// Try to guess the device resolution based on UA strings to avoid a flash
// of incorrectly-styled content.
$device_guess = 'device-desktop';
if (preg_match('@iPhone|iPod|(Android.*Chrome/[.0-9]* Mobile)@', $agent)) {
$device_guess = 'device-phone device';
} else if (preg_match('@iPad|(Android.*Chrome/)@', $agent)) {
$device_guess = 'device-tablet device';
}
$classes[] = $device_guess;
if (preg_match('@Windows@', $agent)) {
$classes[] = 'platform-windows';
} else if (preg_match('@Macintosh@', $agent)) {
$classes[] = 'platform-mac';
} else if (preg_match('@X11@', $agent)) {
$classes[] = 'platform-linux';
}
if ($this->getRequest()->getStr('__print__')) {
$classes[] = 'printable';
}
if ($this->getRequest()->getStr('__aural__')) {
$classes[] = 'audible';
}
$classes[] = 'phui-theme-'.PhabricatorEnv::getEnvConfig('ui.header-color');
foreach ($this->classes as $class) {
$classes[] = $class;
}
return implode(' ', $classes);
}
private function getConsole() {
if ($this->disableConsole) {
return null;
}
return $this->getRequest()->getApplicationConfiguration()->getConsole();
}
private function getConsoleConfig() {
$user = $this->getRequest()->getUser();
$headers = array();
if (DarkConsoleXHProfPluginAPI::isProfilerStarted()) {
$headers[DarkConsoleXHProfPluginAPI::getProfilerHeader()] = 'page';
}
if (DarkConsoleServicesPlugin::isQueryAnalyzerRequested()) {
$headers[DarkConsoleServicesPlugin::getQueryAnalyzerHeader()] = true;
}
return array(
// NOTE: We use a generic label here to prevent input reflection
// and mitigate compression attacks like BREACH. See discussion in
// T3684.
'uri' => pht('Main Request'),
'selected' => $user ? $user->getConsoleTab() : null,
'visible' => $user ? (int)$user->getConsoleVisible() : true,
'headers' => $headers,
);
}
private function getHighSecurityWarningConfig() {
$user = $this->getRequest()->getUser();
$show = false;
if ($user->hasSession()) {
$hisec = ($user->getSession()->getHighSecurityUntil() - time());
if ($hisec > 0) {
$show = true;
}
}
return array(
'show' => $show,
'uri' => '/auth/session/downgrade/',
'message' => pht(
'Your session is in high security mode. When you '.
'finish using it, click here to leave.'),
);
}
private function renderFooter() {
if (!$this->getShowChrome()) {
return null;
}
if (!$this->getShowFooter()) {
return null;
}
$items = PhabricatorEnv::getEnvConfig('ui.footer-items');
if (!$items) {
return null;
}
$foot = array();
foreach ($items as $item) {
$name = idx($item, 'name', pht('Unnamed Footer Item'));
$href = idx($item, 'href');
if (!PhabricatorEnv::isValidURIForLink($href)) {
$href = null;
}
if ($href !== null) {
$tag = 'a';
} else {
$tag = 'span';
}
$foot[] = phutil_tag(
$tag,
array(
'href' => $href,
),
$name);
}
$foot = phutil_implode_html(" \xC2\xB7 ", $foot);
return phutil_tag(
'div',
array(
'class' => 'phabricator-standard-page-footer grouped',
),
$foot);
}
public function renderForQuicksand() {
parent::willRenderPage();
$response = $this->renderPageBodyContent();
$response = $this->willSendResponse($response);
$extra_config = $this->getQuicksandConfig();
return array(
'content' => hsprintf('%s', $response),
) + $this->buildQuicksandConfig()
+ $extra_config;
}
private function buildQuicksandConfig() {
$viewer = $this->getRequest()->getUser();
$controller = $this->getController();
$dropdown_query = id(new AphlictDropdownDataQuery())
->setViewer($viewer);
$dropdown_query->execute();
$rendered_dropdowns = array();
$applications = array(
'PhabricatorHelpApplication',
);
foreach ($applications as $application_class) {
if (!PhabricatorApplication::isClassInstalledForViewer(
$application_class,
$viewer)) {
continue;
}
$application = PhabricatorApplication::getByClass($application_class);
$rendered_dropdowns[$application_class] =
$application->buildMainMenuExtraNodes(
$viewer,
$controller);
}
$hisec_warning_config = $this->getHighSecurityWarningConfig();
$console_config = null;
$console = $this->getConsole();
if ($console) {
$console_config = $this->getConsoleConfig();
}
$upload_enabled = false;
if ($controller) {
$upload_enabled = $controller->isGlobalDragAndDropUploadEnabled();
}
$application_class = null;
$application_search_icon = null;
$controller = $this->getController();
if ($controller) {
$application = $controller->getCurrentApplication();
if ($application) {
$application_class = get_class($application);
if ($application->getApplicationSearchDocumentTypes()) {
- $application_search_icon = $application->getFontIcon();
+ $application_search_icon = $application->getIcon();
}
}
}
return array(
'title' => $this->getTitle(),
'aphlictDropdownData' => array(
$dropdown_query->getNotificationData(),
$dropdown_query->getConpherenceData(),
),
'globalDragAndDrop' => $upload_enabled,
'aphlictDropdowns' => $rendered_dropdowns,
'hisecWarningConfig' => $hisec_warning_config,
'consoleConfig' => $console_config,
'applicationClass' => $application_class,
'applicationSearchIcon' => $application_search_icon,
) + $this->buildAphlictListenConfigData();
}
private function buildAphlictListenConfigData() {
$user = $this->getRequest()->getUser();
$subscriptions = $this->pageObjects;
$subscriptions[] = $user->getPHID();
return array(
'pageObjects' => array_fill_keys($this->pageObjects, true),
'subscriptions' => $subscriptions,
);
}
private function getQuicksandURIPatternBlacklist() {
$applications = PhabricatorApplication::getAllApplications();
$blacklist = array();
foreach ($applications as $application) {
$blacklist[] = $application->getQuicksandURIPatternBlacklist();
}
return array_mergev($blacklist);
}
private function getUserPreference($key, $default = null) {
$request = $this->getRequest();
if (!$request) {
return $default;
}
$user = $request->getUser();
if (!$user) {
return $default;
}
return $user->loadPreferences()->getPreference($key, $default);
}
public function produceAphrontResponse() {
$controller = $this->getController();
if (!$this->getApplicationMenu()) {
$application_menu = $controller->buildApplicationMenu();
if ($application_menu) {
$this->setApplicationMenu($application_menu);
}
}
$viewer = $this->getUser();
if ($viewer && $viewer->getPHID()) {
$object_phids = $this->pageObjects;
foreach ($object_phids as $object_phid) {
PhabricatorFeedStoryNotification::updateObjectNotificationViews(
$viewer,
$object_phid);
}
}
if ($this->getRequest()->isQuicksand()) {
$content = $this->renderForQuicksand();
$response = id(new AphrontAjaxResponse())
->setContent($content);
} else {
$content = $this->render();
$response = id(new AphrontWebpageResponse())
->setContent($content);
}
return $response;
}
}
diff --git a/src/view/page/menu/PhabricatorMainMenuSearchView.php b/src/view/page/menu/PhabricatorMainMenuSearchView.php
index 1af42511a8..a5c5653cc3 100644
--- a/src/view/page/menu/PhabricatorMainMenuSearchView.php
+++ b/src/view/page/menu/PhabricatorMainMenuSearchView.php
@@ -1,231 +1,231 @@
<?php
final class PhabricatorMainMenuSearchView extends AphrontView {
const DEFAULT_APPLICATION_ICON = 'fa-dot-circle-o';
private $id;
private $application;
public function setApplication(PhabricatorApplication $application) {
$this->application = $application;
return $this;
}
public function getApplication() {
return $this->application;
}
public function getID() {
if (!$this->id) {
$this->id = celerity_generate_unique_node_id();
}
return $this->id;
}
public function render() {
$user = $this->user;
$target_id = celerity_generate_unique_node_id();
$search_id = $this->getID();
$button_id = celerity_generate_unique_node_id();
$selector_id = celerity_generate_unique_node_id();
$application_id = celerity_generate_unique_node_id();
$input = phutil_tag(
'input',
array(
'type' => 'text',
'name' => 'query',
'id' => $search_id,
'autocomplete' => 'off',
));
$target = javelin_tag(
'div',
array(
'id' => $target_id,
'class' => 'phabricator-main-menu-search-target',
),
'');
$search_datasource = new PhabricatorSearchDatasource();
$scope_key = PhabricatorUserPreferences::PREFERENCE_SEARCH_SCOPE;
Javelin::initBehavior(
'phabricator-search-typeahead',
array(
'id' => $target_id,
'input' => $search_id,
'button' => $button_id,
'selectorID' => $selector_id,
'applicationID' => $application_id,
'defaultApplicationIcon' => self::DEFAULT_APPLICATION_ICON,
'appScope' => PhabricatorSearchController::SCOPE_CURRENT_APPLICATION,
'src' => $search_datasource->getDatasourceURI(),
'limit' => 10,
'placeholder' => pht('Search'),
'scopeUpdateURI' => '/settings/adjust/?key='.$scope_key,
));
$primary_input = phutil_tag(
'input',
array(
'type' => 'hidden',
'name' => 'search:primary',
'value' => 'true',
));
$search_text = javelin_tag(
'span',
array(
'aural' => true,
),
pht('Search'));
$selector = $this->buildModeSelector($selector_id, $application_id);
$form = phabricator_form(
$user,
array(
'action' => '/search/',
'method' => 'POST',
),
phutil_tag_div('phabricator-main-menu-search-container', array(
$input,
phutil_tag(
'button',
array(
'id' => $button_id,
'class' => 'phui-icon-view phui-font-fa fa-search',
),
$search_text),
$selector,
$primary_input,
$target,
)));
return $form;
}
private function buildModeSelector($selector_id, $application_id) {
$viewer = $this->getUser();
$items = array();
$items[] = array(
'name' => pht('Search'),
);
$items[] = array(
'icon' => 'fa-globe',
'name' => pht('Search All Documents'),
'value' => 'all',
);
$application_value = null;
$application_icon = self::DEFAULT_APPLICATION_ICON;
$application = $this->getApplication();
if ($application) {
$application_value = get_class($application);
if ($application->getApplicationSearchDocumentTypes()) {
- $application_icon = $application->getFontIcon();
+ $application_icon = $application->getIcon();
}
}
$items[] = array(
'icon' => $application_icon,
'name' => pht('Search Current Application'),
'value' => PhabricatorSearchController::SCOPE_CURRENT_APPLICATION,
);
$items[] = array(
'name' => pht('Saved Queries'),
);
$engine = id(new PhabricatorSearchApplicationSearchEngine())
->setViewer($viewer);
$engine_queries = $engine->loadEnabledNamedQueries();
$query_map = mpull($engine_queries, 'getQueryName', 'getQueryKey');
foreach ($query_map as $query_key => $query_name) {
if ($query_key == 'all') {
// Skip the builtin "All" query since it's redundant with the default
// setting.
continue;
}
$items[] = array(
'icon' => 'fa-certificate',
'name' => $query_name,
'value' => $query_key,
);
}
$items[] = array(
'name' => pht('More Options'),
);
$items[] = array(
'icon' => 'fa-search-plus',
'name' => pht('Advanced Search'),
'href' => '/search/query/advanced/',
);
$items[] = array(
'icon' => 'fa-book',
'name' => pht('User Guide: Search'),
'href' => PhabricatorEnv::getDoclink('Search User Guide'),
);
$scope_key = PhabricatorUserPreferences::PREFERENCE_SEARCH_SCOPE;
$current_value = $viewer->loadPreferences()->getPreference(
$scope_key,
'all');
$current_icon = 'fa-globe';
foreach ($items as $item) {
if (idx($item, 'value') == $current_value) {
$current_icon = $item['icon'];
break;
}
}
$selector = id(new PHUIButtonView())
->setID($selector_id)
->addClass('phabricator-main-menu-search-dropdown')
->addSigil('global-search-dropdown')
->setMetadata(
array(
'items' => $items,
'icon' => $current_icon,
'value' => $current_value,
))
->setIcon(
id(new PHUIIconView())
->addSigil('global-search-dropdown-icon')
->setIcon($current_icon))
->setDropdown(true);
$input = javelin_tag(
'input',
array(
'type' => 'hidden',
'sigil' => 'global-search-dropdown-input',
'name' => 'search:scope',
'value' => $current_value,
));
$application_input = javelin_tag(
'input',
array(
'type' => 'hidden',
'id' => $application_id,
'sigil' => 'global-search-dropdown-app',
'name' => 'search:application',
'value' => $application_value,
));
return array($selector, $input, $application_input);
}
}
diff --git a/src/view/phui/PHUIActionPanelView.php b/src/view/phui/PHUIActionPanelView.php
index a81b2e5dcf..f5f74b2807 100644
--- a/src/view/phui/PHUIActionPanelView.php
+++ b/src/view/phui/PHUIActionPanelView.php
@@ -1,139 +1,139 @@
<?php
final class PHUIActionPanelView extends AphrontTagView {
private $href;
private $fontIcon;
private $header;
private $subHeader;
private $bigText;
private $state;
private $status;
const COLOR_RED = 'phui-action-panel-red';
const COLOR_ORANGE = 'phui-action-panel-orange';
const COLOR_YELLOW = 'phui-action-panel-yellow';
const COLOR_GREEN = 'phui-action-panel-green';
const COLOR_BLUE = 'phui-action-panel-blue';
const COLOR_INDIGO = 'phui-action-panel-indigo';
const COLOR_VIOLET = 'phui-action-panel-violet';
const COLOR_PINK = 'phui-action-panel-pink';
public function setHref($href) {
$this->href = $href;
return $this;
}
- public function setFontIcon($image) {
+ public function setIcon($image) {
$this->fontIcon = $image;
return $this;
}
public function setBigText($text) {
$this->bigText = $text;
return $this;
}
public function setHeader($header) {
$this->header = $header;
return $this;
}
public function setSubHeader($sub) {
$this->subHeader = $sub;
return $this;
}
public function setState($state) {
$this->state = $state;
return $this;
}
public function setStatus($text) {
$this->status = $text;
return $this;
}
protected function getTagName() {
return 'div';
}
protected function getTagAttributes() {
require_celerity_resource('phui-action-panel-css');
$classes = array();
$classes[] = 'phui-action-panel';
if ($this->state) {
$classes[] = $this->state;
}
if ($this->bigText) {
$classes[] = 'phui-action-panel-bigtext';
}
return array(
'class' => implode(' ', $classes),
);
}
protected function getTagContent() {
$icon = null;
if ($this->fontIcon) {
$fonticon = id(new PHUIIconView())
->setIcon($this->fontIcon);
$icon = phutil_tag(
'span',
array(
'class' => 'phui-action-panel-icon',
),
$fonticon);
}
$header = null;
if ($this->header) {
$header = phutil_tag(
'span',
array(
'class' => 'phui-action-panel-header',
),
$this->header);
}
$subheader = null;
if ($this->subHeader) {
$subheader = phutil_tag(
'span',
array(
'class' => 'phui-action-panel-subheader',
),
$this->subHeader);
}
$row = phutil_tag(
'span',
array(
'class' => 'phui-action-panel-row',
),
array(
$icon,
$subheader,
));
$table = phutil_tag(
'span',
array(
'class' => 'phui-action-panel-table',
),
$row);
return phutil_tag(
'a',
array(
'href' => $this->href,
'class' => 'phui-action-panel-hitarea',
),
array($header, $table));
}
}
diff --git a/src/view/phui/PHUIIconView.php b/src/view/phui/PHUIIconView.php
index 02e06be9e9..adfd33187d 100644
--- a/src/view/phui/PHUIIconView.php
+++ b/src/view/phui/PHUIIconView.php
@@ -1,768 +1,768 @@
<?php
final class PHUIIconView extends AphrontTagView {
const SPRITE_TOKENS = 'tokens';
const SPRITE_LOGIN = 'login';
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;
public function setHref($href) {
$this->href = $href;
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 setIcon($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() {
require_celerity_resource('phui-icon-view-css');
$style = null;
$classes = array();
$classes[] = 'phui-icon-view';
if ($this->spriteIcon) {
require_celerity_resource('sprite-'.$this->spriteSheet.'-css');
$classes[] = 'sprite-'.$this->spriteSheet;
$classes[] = $this->spriteSheet.'-'.$this->spriteIcon;
} else if ($this->iconFont) {
require_celerity_resource('phui-font-icon-base-css');
require_celerity_resource('font-fontawesome');
$classes[] = 'phui-font-fa';
$classes[] = $this->iconFont;
if ($this->iconColor) {
$classes[] = $this->iconColor;
}
} else {
if ($this->headSize) {
$classes[] = $this->headSize;
}
$style = 'background-image: url('.$this->image.');';
}
if ($this->text) {
$classes[] = 'phui-icon-has-text';
$this->appendChild($this->text);
}
return array(
'href' => $this->href,
'style' => $style,
'aural' => false,
'class' => $classes,
);
}
public static function getSheetManifest($sheet) {
$root = dirname(phutil_get_library_root('phabricator'));
$path = $root.'/resources/sprite/manifest/'.$sheet.'.json';
$data = Filesystem::readFile($path);
return idx(phutil_json_decode($data), 'sprites');
}
- public static function getFontIcons() {
+ public static function getIcons() {
return array(
'fa-glass',
'fa-music',
'fa-search',
'fa-envelope-o',
'fa-heart',
'fa-star',
'fa-star-o',
'fa-user',
'fa-film',
'fa-th-large',
'fa-th',
'fa-th-list',
'fa-check',
'fa-times',
'fa-search-plus',
'fa-search-minus',
'fa-power-off',
'fa-signal',
'fa-cog',
'fa-trash-o',
'fa-home',
'fa-file-o',
'fa-clock-o',
'fa-road',
'fa-download',
'fa-arrow-circle-o-down',
'fa-arrow-circle-o-up',
'fa-inbox',
'fa-play-circle-o',
'fa-repeat',
'fa-refresh',
'fa-list-alt',
'fa-lock',
'fa-flag',
'fa-headphones',
'fa-volume-off',
'fa-volume-down',
'fa-volume-up',
'fa-qrcode',
'fa-barcode',
'fa-tag',
'fa-tags',
'fa-book',
'fa-bookmark',
'fa-print',
'fa-camera',
'fa-font',
'fa-bold',
'fa-italic',
'fa-text-height',
'fa-text-width',
'fa-align-left',
'fa-align-center',
'fa-align-right',
'fa-align-justify',
'fa-list',
'fa-outdent',
'fa-indent',
'fa-video-camera',
'fa-picture-o',
'fa-pencil',
'fa-map-marker',
'fa-adjust',
'fa-tint',
'fa-pencil-square-o',
'fa-share-square-o',
'fa-check-square-o',
'fa-arrows',
'fa-step-backward',
'fa-fast-backward',
'fa-backward',
'fa-play',
'fa-pause',
'fa-stop',
'fa-forward',
'fa-fast-forward',
'fa-step-forward',
'fa-eject',
'fa-chevron-left',
'fa-chevron-right',
'fa-plus-circle',
'fa-minus-circle',
'fa-times-circle',
'fa-check-circle',
'fa-question-circle',
'fa-info-circle',
'fa-crosshairs',
'fa-times-circle-o',
'fa-check-circle-o',
'fa-ban',
'fa-arrow-left',
'fa-arrow-right',
'fa-arrow-up',
'fa-arrow-down',
'fa-share',
'fa-expand',
'fa-compress',
'fa-plus',
'fa-minus',
'fa-asterisk',
'fa-exclamation-circle',
'fa-gift',
'fa-leaf',
'fa-fire',
'fa-eye',
'fa-eye-slash',
'fa-exclamation-triangle',
'fa-plane',
'fa-calendar',
'fa-random',
'fa-comment',
'fa-magnet',
'fa-chevron-up',
'fa-chevron-down',
'fa-retweet',
'fa-shopping-cart',
'fa-folder',
'fa-folder-open',
'fa-arrows-v',
'fa-arrows-h',
'fa-bar-chart-o',
'fa-twitter-square',
'fa-facebook-square',
'fa-camera-retro',
'fa-key',
'fa-cogs',
'fa-comments',
'fa-thumbs-o-up',
'fa-thumbs-o-down',
'fa-star-half',
'fa-heart-o',
'fa-sign-out',
'fa-linkedin-square',
'fa-thumb-tack',
'fa-external-link',
'fa-sign-in',
'fa-trophy',
'fa-github-square',
'fa-upload',
'fa-lemon-o',
'fa-phone',
'fa-square-o',
'fa-bookmark-o',
'fa-phone-square',
'fa-twitter',
'fa-facebook',
'fa-github',
'fa-unlock',
'fa-credit-card',
'fa-rss',
'fa-hdd-o',
'fa-bullhorn',
'fa-bell',
'fa-certificate',
'fa-hand-o-right',
'fa-hand-o-left',
'fa-hand-o-up',
'fa-hand-o-down',
'fa-arrow-circle-left',
'fa-arrow-circle-right',
'fa-arrow-circle-up',
'fa-arrow-circle-down',
'fa-globe',
'fa-wrench',
'fa-tasks',
'fa-filter',
'fa-briefcase',
'fa-arrows-alt',
'fa-users',
'fa-link',
'fa-cloud',
'fa-flask',
'fa-scissors',
'fa-files-o',
'fa-paperclip',
'fa-floppy-o',
'fa-square',
'fa-bars',
'fa-list-ul',
'fa-list-ol',
'fa-strikethrough',
'fa-underline',
'fa-table',
'fa-magic',
'fa-truck',
'fa-pinterest',
'fa-pinterest-square',
'fa-google-plus-square',
'fa-google-plus',
'fa-money',
'fa-caret-down',
'fa-caret-up',
'fa-caret-left',
'fa-caret-right',
'fa-columns',
'fa-sort',
'fa-sort-asc',
'fa-sort-desc',
'fa-envelope',
'fa-linkedin',
'fa-undo',
'fa-gavel',
'fa-tachometer',
'fa-comment-o',
'fa-comments-o',
'fa-bolt',
'fa-sitemap',
'fa-umbrella',
'fa-clipboard',
'fa-lightbulb-o',
'fa-exchange',
'fa-cloud-download',
'fa-cloud-upload',
'fa-user-md',
'fa-stethoscope',
'fa-suitcase',
'fa-bell-o',
'fa-coffee',
'fa-cutlery',
'fa-file-text-o',
'fa-building-o',
'fa-hospital-o',
'fa-ambulance',
'fa-medkit',
'fa-fighter-jet',
'fa-beer',
'fa-h-square',
'fa-plus-square',
'fa-angle-double-left',
'fa-angle-double-right',
'fa-angle-double-up',
'fa-angle-double-down',
'fa-angle-left',
'fa-angle-right',
'fa-angle-up',
'fa-angle-down',
'fa-desktop',
'fa-laptop',
'fa-tablet',
'fa-mobile',
'fa-circle-o',
'fa-quote-left',
'fa-quote-right',
'fa-spinner',
'fa-circle',
'fa-reply',
'fa-github-alt',
'fa-folder-o',
'fa-folder-open-o',
'fa-smile-o',
'fa-frown-o',
'fa-meh-o',
'fa-gamepad',
'fa-keyboard-o',
'fa-flag-o',
'fa-flag-checkered',
'fa-terminal',
'fa-code',
'fa-reply-all',
'fa-mail-reply-all',
'fa-star-half-o',
'fa-location-arrow',
'fa-crop',
'fa-code-fork',
'fa-chain-broken',
'fa-question',
'fa-info',
'fa-exclamation',
'fa-superscript',
'fa-subscript',
'fa-eraser',
'fa-puzzle-piece',
'fa-microphone',
'fa-microphone-slash',
'fa-shield',
'fa-calendar-o',
'fa-fire-extinguisher',
'fa-rocket',
'fa-maxcdn',
'fa-chevron-circle-left',
'fa-chevron-circle-right',
'fa-chevron-circle-up',
'fa-chevron-circle-down',
'fa-html5',
'fa-css3',
'fa-anchor',
'fa-unlock-alt',
'fa-bullseye',
'fa-ellipsis-h',
'fa-ellipsis-v',
'fa-rss-square',
'fa-play-circle',
'fa-ticket',
'fa-minus-square',
'fa-minus-square-o',
'fa-level-up',
'fa-level-down',
'fa-check-square',
'fa-pencil-square',
'fa-external-link-square',
'fa-share-square',
'fa-compass',
'fa-caret-square-o-down',
'fa-caret-square-o-up',
'fa-caret-square-o-right',
'fa-eur',
'fa-gbp',
'fa-usd',
'fa-inr',
'fa-jpy',
'fa-rub',
'fa-krw',
'fa-btc',
'fa-file',
'fa-file-text',
'fa-sort-alpha-asc',
'fa-sort-alpha-desc',
'fa-sort-amount-asc',
'fa-sort-amount-desc',
'fa-sort-numeric-asc',
'fa-sort-numeric-desc',
'fa-thumbs-up',
'fa-thumbs-down',
'fa-youtube-square',
'fa-youtube',
'fa-xing',
'fa-xing-square',
'fa-youtube-play',
'fa-dropbox',
'fa-stack-overflow',
'fa-instagram',
'fa-flickr',
'fa-adn',
'fa-bitbucket',
'fa-bitbucket-square',
'fa-tumblr',
'fa-tumblr-square',
'fa-long-arrow-down',
'fa-long-arrow-up',
'fa-long-arrow-left',
'fa-long-arrow-right',
'fa-apple',
'fa-windows',
'fa-android',
'fa-linux',
'fa-dribbble',
'fa-skype',
'fa-foursquare',
'fa-trello',
'fa-female',
'fa-male',
'fa-gittip',
'fa-sun-o',
'fa-moon-o',
'fa-archive',
'fa-bug',
'fa-vk',
'fa-weibo',
'fa-renren',
'fa-pagelines',
'fa-stack-exchange',
'fa-arrow-circle-o-right',
'fa-arrow-circle-o-left',
'fa-caret-square-o-left',
'fa-dot-circle-o',
'fa-wheelchair',
'fa-vimeo-square',
'fa-try',
'fa-plus-square-o',
'fa-space-shuttle',
'fa-slack',
'fa-envelope-square',
'fa-wordpress',
'fa-openid',
'fa-institution',
'fa-bank',
'fa-university',
'fa-mortar-board',
'fa-graduation-cap',
'fa-yahoo',
'fa-google',
'fa-reddit',
'fa-reddit-square',
'fa-stumbleupon-circle',
'fa-stumbleupon',
'fa-delicious',
'fa-digg',
'fa-pied-piper-square',
'fa-pied-piper',
'fa-pied-piper-alt',
'fa-drupal',
'fa-joomla',
'fa-language',
'fa-fax',
'fa-building',
'fa-child',
'fa-paw',
'fa-spoon',
'fa-cube',
'fa-cubes',
'fa-behance',
'fa-behance-square',
'fa-steam',
'fa-steam-square',
'fa-recycle',
'fa-automobile',
'fa-car',
'fa-cab',
'fa-tree',
'fa-spotify',
'fa-deviantart',
'fa-soundcloud',
'fa-database',
'fa-file-pdf-o',
'fa-file-word-o',
'fa-file-excel-o',
'fa-file-powerpoint-o',
'fa-file-photo-o',
'fa-file-picture-o',
'fa-file-image-o',
'fa-file-zip-o',
'fa-file-archive-o',
'fa-file-sound-o',
'fa-file-movie-o',
'fa-file-code-o',
'fa-vine',
'fa-codepen',
'fa-jsfiddle',
'fa-life-bouy',
'fa-support',
'fa-life-ring',
'fa-circle-o-notch',
'fa-rebel',
'fa-empire',
'fa-git-square',
'fa-git',
'fa-hacker-news',
'fa-tencent-weibo',
'fa-qq',
'fa-wechat',
'fa-send',
'fa-paper-plane',
'fa-send-o',
'fa-paper-plane-o',
'fa-history',
'fa-circle-thin',
'fa-header',
'fa-paragraph',
'fa-sliders',
'fa-share-alt',
'fa-share-alt-square',
'fa-bomb',
'fa-soccer-ball',
'fa-futbol-o',
'fa-tty',
'fa-binoculars',
'fa-plug',
'fa-slideshare',
'fa-twitch',
'fa-yelp',
'fa-newspaper-o',
'fa-wifi',
'fa-calculator',
'fa-paypal',
'fa-google-wallet',
'fa-cc-visa',
'fa-cc-mastercard',
'fa-cc-discover',
'fa-cc-amex',
'fa-cc-paypal',
'fa-cc-stripe',
'fa-bell-slash',
'fa-bell-slash-o',
'fa-trash',
'fa-copyright',
'fa-at',
'fa-eyedropper',
'fa-paint-brush',
'fa-birthday-cake',
'fa-area-chart',
'fa-pie-chart',
'fa-line-chart',
'fa-lastfm',
'fa-lastfm-square',
'fa-toggle-off',
'fa-toggle-on',
'fa-bicycle',
'fa-bus',
'fa-ioxhost',
'fa-angellist',
'fa-cc',
'fa-shekel',
'fa-sheqel',
'fa-ils',
'fa-meanpath',
'fa-buysellads',
'fa-connectdevelop',
'fa-dashcube',
'fa-forumbee',
'fa-leanpub',
'fa-sellsy',
'fa-shirtsinbulk',
'fa-simplybuilt',
'fa-skyatlas',
'fa-cart-plus',
'fa-cart-arrow-down',
'fa-diamond',
'fa-ship',
'fa-user-secret',
'fa-motorcycle',
'fa-street-view',
'fa-heartbeat',
'fa-venus',
'fa-mars',
'fa-mercury',
'fa-transgender',
'fa-transgender-alt',
'fa-venus-double',
'fa-mars-double',
'fa-venus-mars',
'fa-mars-stroke',
'fa-mars-stroke-v',
'fa-mars-stroke-h',
'fa-neuter',
'fa-facebook-official',
'fa-pinterest-p',
'fa-whatsapp',
'fa-server',
'fa-user-plus',
'fa-user-times',
'fa-hotel',
'fa-bed',
'fa-viacoin',
'fa-train',
'fa-subway',
'fa-medium',
'fa-git',
'fa-y-combinator-square',
'fa-yc-square',
'fa-hacker-news',
'fa-yc',
'fa-y-combinator',
'fa-optin-monster',
'fa-opencart',
'fa-expeditedssl',
'fa-battery-4',
'fa-battery-full',
'fa-battery-3',
'fa-battery-three-quarters',
'fa-battery-2',
'fa-battery-half',
'fa-battery-1',
'fa-battery-quarter',
'fa-battery-0',
'fa-battery-empty',
'fa-mouse-pointer',
'fa-i-cursor',
'fa-object-group',
'fa-object-ungroup',
'fa-sticky-note',
'fa-sticky-note-o',
'fa-cc-jcb',
'fa-cc-diners-club',
'fa-clone',
'fa-balance-scale',
'fa-hourglass-o',
'fa-hourglass-1',
'fa-hourglass-start',
'fa-hourglass-2',
'fa-hourglass-half',
'fa-hourglass-3',
'fa-hourglass-end',
'fa-hourglass',
'fa-hand-grab-o',
'fa-hand-rock-o',
'fa-hand-stop-o',
'fa-hand-paper-o',
'fa-hand-scissors-o',
'fa-hand-lizard-o',
'fa-hand-spock-o',
'fa-hand-pointer-o',
'fa-hand-peace-o',
'fa-trademark',
'fa-registered',
'fa-creative-commons',
'fa-gg',
'fa-gg-circle',
'fa-tripadvisor',
'fa-odnoklassniki',
'fa-odnoklassniki-square',
'fa-get-pocket',
'fa-wikipedia-w',
'fa-safari',
'fa-chrome',
'fa-firefox',
'fa-opera',
'fa-internet-explorer',
'fa-tv',
'fa-television',
'fa-contao',
'fa-500px',
'fa-amazon',
'fa-calendar-plus-o',
'fa-calendar-minus-o',
'fa-calendar-times-o',
'fa-calendar-check-o',
'fa-industry',
'fa-map-pin',
'fa-map-signs',
'fa-map-o',
'fa-map',
'fa-commenting',
'fa-commenting-o',
'fa-houzz',
'fa-vimeo',
'fa-black-tie',
'fa-fonticons',
'fa-reddit-alien',
'fa-edge',
'fa-credit-card-alt',
'fa-codiepie:before',
'fa-modx',
'fa-fort-awesome',
'fa-usb',
'fa-product-hunt',
'fa-mixcloud',
'fa-scribd',
'fa-pause-circle',
'fa-pause-circle-o',
'fa-stop-circle',
'fa-stop-circle-o',
'fa-shopping-bag',
'fa-shopping-basket',
'fa-hashtag',
'fa-bluetooth',
'fa-bluetooth-b',
'fa-percent',
);
}
- public static function getFontIconColors() {
+ public static function getIconColors() {
return array(
'bluegrey',
'white',
'red',
'orange',
'yellow',
'green',
'blue',
'sky',
'indigo',
'violet',
'pink',
'lightgreytext',
'lightbluetext',
);
}
}
diff --git a/src/view/phui/PHUIObjectItemView.php b/src/view/phui/PHUIObjectItemView.php
index bc48351c96..b3c4368c22 100644
--- a/src/view/phui/PHUIObjectItemView.php
+++ b/src/view/phui/PHUIObjectItemView.php
@@ -1,759 +1,759 @@
<?php
final class PHUIObjectItemView extends AphrontTagView {
private $objectName;
private $header;
private $subhead;
private $href;
private $attributes = array();
private $icons = array();
private $barColor;
private $object;
private $effect;
private $statusIcon;
private $handleIcons = array();
private $bylines = array();
private $grippable;
private $actions = array();
private $headIcons = array();
private $disabled;
private $imageURI;
private $state;
private $fontIcon;
private $imageIcon;
private $titleText;
private $badge;
private $countdownNum;
private $countdownNoun;
private $launchButton;
const AGE_FRESH = 'fresh';
const AGE_STALE = 'stale';
const AGE_OLD = 'old';
const STATE_SUCCESS = 'green';
const STATE_FAIL = 'red';
const STATE_WARN = 'yellow';
const STATE_NOTE = 'blue';
const STATE_BUILD = 'sky';
public function setDisabled($disabled) {
$this->disabled = $disabled;
return $this;
}
public function getDisabled() {
return $this->disabled;
}
public function addHeadIcon($icon) {
$this->headIcons[] = $icon;
return $this;
}
public function setObjectName($name) {
$this->objectName = $name;
return $this;
}
public function setGrippable($grippable) {
$this->grippable = $grippable;
return $this;
}
public function getGrippable() {
return $this->grippable;
}
public function setEffect($effect) {
$this->effect = $effect;
return $this;
}
public function getEffect() {
return $this->effect;
}
public function setObject($object) {
$this->object = $object;
return $this;
}
public function getObject() {
return $this->object;
}
public function setHref($href) {
$this->href = $href;
return $this;
}
public function getHref() {
return $this->href;
}
public function setHeader($header) {
$this->header = $header;
return $this;
}
public function setSubHead($subhead) {
$this->subhead = $subhead;
return $this;
}
public function setBadge(PHUIBadgeMiniView $badge) {
$this->badge = $badge;
return $this;
}
public function setCountdown($num, $noun) {
$this->countdownNum = $num;
$this->countdownNoun = $noun;
return $this;
}
public function setTitleText($title_text) {
$this->titleText = $title_text;
return $this;
}
public function getTitleText() {
return $this->titleText;
}
public function getHeader() {
return $this->header;
}
public function addByline($byline) {
$this->bylines[] = $byline;
return $this;
}
public function setImageURI($image_uri) {
$this->imageURI = $image_uri;
return $this;
}
public function getImageURI() {
return $this->imageURI;
}
public function setImageIcon($image_icon) {
$this->imageIcon = $image_icon;
return $this;
}
public function getImageIcon() {
return $this->imageIcon;
}
public function setState($state) {
$this->state = $state;
switch ($state) {
case self::STATE_SUCCESS:
$fi = 'fa-check-circle green';
break;
case self::STATE_FAIL:
$fi = 'fa-times-circle red';
break;
case self::STATE_WARN:
$fi = 'fa-exclamation-circle yellow';
break;
case self::STATE_NOTE:
$fi = 'fa-info-circle blue';
break;
case self::STATE_BUILD:
$fi = 'fa-refresh ph-spin sky';
break;
}
- $this->setFontIcon($fi);
+ $this->setIcon($fi);
return $this;
}
- public function setFontIcon($icon) {
+ public function setIcon($icon) {
$this->fontIcon = id(new PHUIIconView())
->setIcon($icon);
return $this;
}
public function setEpoch($epoch, $age = self::AGE_FRESH) {
$date = phabricator_datetime($epoch, $this->getUser());
$days = floor((time() - $epoch) / 60 / 60 / 24);
switch ($age) {
case self::AGE_FRESH:
$this->addIcon('none', $date);
break;
case self::AGE_STALE:
$attr = array(
'tip' => pht('Stale (%s day(s))', new PhutilNumber($days)),
'class' => 'icon-age-stale',
);
$this->addIcon('fa-clock-o yellow', $date, $attr);
break;
case self::AGE_OLD:
$attr = array(
'tip' => pht('Old (%s day(s))', new PhutilNumber($days)),
'class' => 'icon-age-old',
);
$this->addIcon('fa-clock-o red', $date, $attr);
break;
default:
throw new Exception(pht("Unknown age '%s'!", $age));
}
return $this;
}
public function addAction(PHUIListItemView $action) {
if (count($this->actions) >= 3) {
throw new Exception(pht('Limit 3 actions per item.'));
}
$this->actions[] = $action;
return $this;
}
public function addIcon($icon, $label = null, $attributes = array()) {
$this->icons[] = array(
'icon' => $icon,
'label' => $label,
'attributes' => $attributes,
);
return $this;
}
public function setStatusIcon($icon, $label = null) {
$this->statusIcon = array(
'icon' => $icon,
'label' => $label,
);
return $this;
}
public function addHandleIcon(
PhabricatorObjectHandle $handle,
$label = null) {
$this->handleIcons[] = array(
'icon' => $handle,
'label' => $label,
);
return $this;
}
public function setBarColor($bar_color) {
$this->barColor = $bar_color;
return $this;
}
public function getBarColor() {
return $this->barColor;
}
public function addAttribute($attribute) {
if (!empty($attribute)) {
$this->attributes[] = $attribute;
}
return $this;
}
public function setLaunchButton(PHUIButtonView $button) {
$button->setSize(PHUIButtonView::SMALL);
$this->launchButton = $button;
return $this;
}
protected function getTagName() {
return 'li';
}
protected function getTagAttributes() {
$item_classes = array();
$item_classes[] = 'phui-object-item';
if ($this->icons) {
$item_classes[] = 'phui-object-item-with-icons';
}
if ($this->attributes) {
$item_classes[] = 'phui-object-item-with-attrs';
}
if ($this->handleIcons) {
$item_classes[] = 'phui-object-item-with-handle-icons';
}
if ($this->barColor) {
$item_classes[] = 'phui-object-item-bar-color-'.$this->barColor;
} else {
$item_classes[] = 'phui-object-item-no-bar';
}
if ($this->actions) {
$n = count($this->actions);
$item_classes[] = 'phui-object-item-with-actions';
$item_classes[] = 'phui-object-item-with-'.$n.'-actions';
}
if ($this->disabled) {
$item_classes[] = 'phui-object-item-disabled';
}
if ($this->state) {
$item_classes[] = 'phui-object-item-state-'.$this->state;
}
switch ($this->effect) {
case 'highlighted':
$item_classes[] = 'phui-object-item-highlighted';
break;
case 'selected':
$item_classes[] = 'phui-object-item-selected';
break;
case null:
break;
default:
throw new Exception(pht('Invalid effect!'));
}
if ($this->getGrippable()) {
$item_classes[] = 'phui-object-item-grippable';
}
if ($this->getImageURI()) {
$item_classes[] = 'phui-object-item-with-image';
}
if ($this->getImageIcon()) {
$item_classes[] = 'phui-object-item-with-image-icon';
}
if ($this->fontIcon) {
$item_classes[] = 'phui-object-item-with-ficon';
}
return array(
'class' => $item_classes,
);
}
protected function getTagContent() {
$viewer = $this->getUser();
$content_classes = array();
$content_classes[] = 'phui-object-item-content';
$header_name = array();
if ($viewer) {
$header_name[] = id(new PHUISpacesNamespaceContextView())
->setUser($viewer)
->setObject($this->object);
}
if ($this->objectName) {
$header_name[] = array(
phutil_tag(
'span',
array(
'class' => 'phui-object-item-objname',
),
$this->objectName),
' ',
);
}
$title_text = null;
if ($this->titleText) {
$title_text = $this->titleText;
} else if ($this->href) {
$title_text = $this->header;
}
$header_link = phutil_tag(
$this->href ? 'a' : 'div',
array(
'href' => $this->href,
'class' => 'phui-object-item-link',
'title' => $title_text,
),
$this->header);
$header = javelin_tag(
'div',
array(
'class' => 'phui-object-item-name',
'sigil' => 'slippery',
),
array(
$this->headIcons,
$header_name,
$header_link,
));
$icons = array();
if ($this->icons) {
$icon_list = array();
foreach ($this->icons as $spec) {
$icon = $spec['icon'];
$icon = id(new PHUIIconView())
->setIcon($icon)
->addClass('phui-object-item-icon-image');
if (isset($spec['attributes']['tip'])) {
$sigil = 'has-tooltip';
$meta = array(
'tip' => $spec['attributes']['tip'],
'align' => 'W',
);
$icon->addSigil($sigil);
$icon->setMetadata($meta);
}
$label = phutil_tag(
'span',
array(
'class' => 'phui-object-item-icon-label',
),
$spec['label']);
if (isset($spec['attributes']['href'])) {
$icon_href = phutil_tag(
'a',
array('href' => $spec['attributes']['href']),
array($icon, $label));
} else {
$icon_href = array($icon, $label);
}
$classes = array();
$classes[] = 'phui-object-item-icon';
if (isset($spec['attributes']['class'])) {
$classes[] = $spec['attributes']['class'];
}
$icon_list[] = javelin_tag(
'li',
array(
'class' => implode(' ', $classes),
),
$icon_href);
}
$icons[] = phutil_tag(
'ul',
array(
'class' => 'phui-object-item-icons',
),
$icon_list);
}
if ($this->handleIcons) {
$handle_bar = array();
foreach ($this->handleIcons as $handleicon) {
$handle_bar[] =
$this->renderHandleIcon($handleicon['icon'], $handleicon['label']);
}
$icons[] = phutil_tag(
'div',
array(
'class' => 'phui-object-item-handle-icons',
),
$handle_bar);
}
$bylines = array();
if ($this->bylines) {
foreach ($this->bylines as $byline) {
$bylines[] = phutil_tag(
'div',
array(
'class' => 'phui-object-item-byline',
),
$byline);
}
$bylines = phutil_tag(
'div',
array(
'class' => 'phui-object-item-bylines',
),
$bylines);
}
$subhead = null;
if ($this->subhead) {
$subhead = phutil_tag(
'div',
array(
'class' => 'phui-object-item-subhead',
),
$this->subhead);
}
if ($icons) {
$icons = phutil_tag(
'div',
array(
'class' => 'phui-object-icon-pane',
),
$icons);
}
$attrs = null;
if ($this->attributes) {
$attrs = array();
$spacer = phutil_tag(
'span',
array(
'class' => 'phui-object-item-attribute-spacer',
),
"\xC2\xB7");
$first = true;
foreach ($this->attributes as $attribute) {
$attrs[] = phutil_tag(
'li',
array(
'class' => 'phui-object-item-attribute',
),
array(
($first ? null : $spacer),
$attribute,
));
$first = false;
}
$attrs = phutil_tag(
'ul',
array(
'class' => 'phui-object-item-attributes',
),
$attrs);
}
$status = null;
if ($this->statusIcon) {
$icon = $this->statusIcon;
$status = $this->renderStatusIcon($icon['icon'], $icon['label']);
}
$grippable = null;
if ($this->getGrippable()) {
$grippable = phutil_tag(
'div',
array(
'class' => 'phui-object-item-grip',
),
'');
}
$content = phutil_tag(
'div',
array(
'class' => implode(' ', $content_classes),
),
array(
$subhead,
$attrs,
$this->renderChildren(),
));
$image = null;
if ($this->getImageURI()) {
$image = phutil_tag(
'div',
array(
'class' => 'phui-object-item-image',
'style' => 'background-image: url('.$this->getImageURI().')',
),
'');
} else if ($this->getImageIcon()) {
$image = phutil_tag(
'div',
array(
'class' => 'phui-object-item-image-icon',
),
$this->getImageIcon());
}
$ficon = null;
if ($this->fontIcon) {
$image = phutil_tag(
'div',
array(
'class' => 'phui-object-item-ficon',
),
$this->fontIcon);
}
if ($image && $this->href) {
$image = phutil_tag(
'a',
array(
'href' => $this->href,
),
$image);
}
/* Build a fake table */
$column0 = null;
if ($status) {
$column0 = phutil_tag(
'div',
array(
'class' => 'phui-object-item-col0',
),
$status);
}
if ($this->badge) {
$column0 = phutil_tag(
'div',
array(
'class' => 'phui-object-item-col0 phui-object-item-badge',
),
$this->badge);
}
if ($this->countdownNum) {
$countdown = phutil_tag(
'div',
array(
'class' => 'phui-object-item-countdown-number',
),
array(
phutil_tag_div('', $this->countdownNum),
phutil_tag_div('', $this->countdownNoun),
));
$column0 = phutil_tag(
'div',
array(
'class' => 'phui-object-item-col0 phui-object-item-countdown',
),
$countdown);
}
$column1 = phutil_tag(
'div',
array(
'class' => 'phui-object-item-col1',
),
array(
$header,
$content,
));
$column2 = null;
if ($icons || $bylines) {
$column2 = phutil_tag(
'div',
array(
'class' => 'phui-object-item-col2',
),
array(
$icons,
$bylines,
));
}
if ($this->launchButton) {
$column2 = phutil_tag(
'div',
array(
'class' => 'phui-object-item-col2 phui-object-item-launch-button',
),
array(
$this->launchButton,
));
}
$table = phutil_tag(
'div',
array(
'class' => 'phui-object-item-table',
),
phutil_tag_div(
'phui-object-item-table-row',
array(
$column0,
$column1,
$column2,
)));
$box = phutil_tag(
'div',
array(
'class' => 'phui-object-item-content-box',
),
array(
$grippable,
$table,
));
$actions = array();
if ($this->actions) {
Javelin::initBehavior('phabricator-tooltips');
foreach (array_reverse($this->actions) as $action) {
$action->setRenderNameAsTooltip(true);
$actions[] = $action;
}
$actions = phutil_tag(
'ul',
array(
'class' => 'phui-object-item-actions',
),
$actions);
}
return phutil_tag(
'div',
array(
'class' => 'phui-object-item-frame',
),
array(
$actions,
$image,
$box,
));
}
private function renderStatusIcon($icon, $label) {
Javelin::initBehavior('phabricator-tooltips');
$icon = id(new PHUIIconView())
->setIcon($icon);
$options = array(
'class' => 'phui-object-item-status-icon',
);
if (strlen($label)) {
$options['sigil'] = 'has-tooltip';
$options['meta'] = array('tip' => $label, 'size' => 300);
}
return javelin_tag('div', $options, $icon);
}
private function renderHandleIcon(PhabricatorObjectHandle $handle, $label) {
Javelin::initBehavior('phabricator-tooltips');
$options = array(
'class' => 'phui-object-item-handle-icon',
'style' => 'background-image: url('.$handle->getImageURI().')',
);
if (strlen($label)) {
$options['sigil'] = 'has-tooltip';
$options['meta'] = array('tip' => $label);
}
return javelin_tag('span', $options, '');
}
}

File Metadata

Mime Type
text/x-diff
Expires
Mon, Dec 1, 4:23 PM (1 d, 16 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
430725
Default Alt Text
(669 KB)

Event Timeline