Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F15411863
D14918.id36050.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
28 KB
Referenced Files
None
Subscribers
None
D14918.id36050.diff
View Options
diff --git a/resources/celerity/map.php b/resources/celerity/map.php
--- a/resources/celerity/map.php
+++ b/resources/celerity/map.php
@@ -37,7 +37,6 @@
'rsrc/css/application/base/phabricator-application-launch-view.css' => '95351601',
'rsrc/css/application/base/phui-theme.css' => '6b451f24',
'rsrc/css/application/base/standard-page-view.css' => '3c99cdf4',
- 'rsrc/css/application/calendar/calendar-icon.css' => 'c69aa59f',
'rsrc/css/application/chatlog/chatlog.css' => 'd295b020',
'rsrc/css/application/conduit/conduit-api.css' => '7bc725c4',
'rsrc/css/application/config/config-options.css' => '0ede4c9b',
@@ -94,7 +93,6 @@
'rsrc/css/application/policy/policy-transaction-detail.css' => '82100a43',
'rsrc/css/application/policy/policy.css' => '957ea14c',
'rsrc/css/application/ponder/ponder-view.css' => '7b0df4da',
- 'rsrc/css/application/projects/project-icon.css' => '4e3eaa5a',
'rsrc/css/application/releeph/releeph-core.css' => '9b3c5733',
'rsrc/css/application/releeph/releeph-preview-branch.css' => 'b7a6f4a5',
'rsrc/css/application/releeph/releeph-request-differential-create-dialog.css' => '8d8b92cd',
@@ -135,6 +133,7 @@
'rsrc/css/phui/phui-form-view.css' => '4a1a0f5e',
'rsrc/css/phui/phui-form.css' => '0b98e572',
'rsrc/css/phui/phui-header-view.css' => '55bb32dd',
+ 'rsrc/css/phui/phui-icon-set-selector.css' => '1ab67aad',
'rsrc/css/phui/phui-icon.css' => 'b0a6b1b6',
'rsrc/css/phui/phui-image-mask.css' => '5a8b09c8',
'rsrc/css/phui/phui-info-panel.css' => '27ea50a1',
@@ -465,7 +464,7 @@
'rsrc/js/core/behavior-active-nav.js' => 'e379b58e',
'rsrc/js/core/behavior-audio-source.js' => '59b251eb',
'rsrc/js/core/behavior-autofocus.js' => '7319e029',
- 'rsrc/js/core/behavior-choose-control.js' => '8fee767e',
+ 'rsrc/js/core/behavior-choose-control.js' => '327a00d1',
'rsrc/js/core/behavior-crop.js' => 'fa0f4fc2',
'rsrc/js/core/behavior-dark-console.js' => 'f411b6ae',
'rsrc/js/core/behavior-device.js' => 'a205cf28',
@@ -524,7 +523,6 @@
'aphront-typeahead-control-css' => '0e403212',
'auth-css' => '0877ed6e',
'bulk-job-css' => 'df9c1d4a',
- 'calendar-icon-css' => 'c69aa59f',
'changeset-view-manager' => '58562350',
'conduit-api-css' => '7bc725c4',
'config-options-css' => '0ede4c9b',
@@ -571,7 +569,7 @@
'javelin-behavior-audio-source' => '59b251eb',
'javelin-behavior-audit-preview' => 'd835b03a',
'javelin-behavior-bulk-job-reload' => 'edf8a145',
- 'javelin-behavior-choose-control' => '8fee767e',
+ 'javelin-behavior-choose-control' => '327a00d1',
'javelin-behavior-comment-actions' => 'b65559c0',
'javelin-behavior-config-reorder-fields' => 'b6993408',
'javelin-behavior-conpherence-drag-and-drop-photo' => 'cf86d16a',
@@ -809,6 +807,7 @@
'phui-form-css' => '0b98e572',
'phui-form-view-css' => '4a1a0f5e',
'phui-header-view-css' => '55bb32dd',
+ 'phui-icon-set-selector-css' => '1ab67aad',
'phui-icon-view-css' => 'b0a6b1b6',
'phui-image-mask-css' => '5a8b09c8',
'phui-info-panel-css' => '27ea50a1',
@@ -839,7 +838,6 @@
'policy-edit-css' => '815c66f7',
'policy-transaction-detail-css' => '82100a43',
'ponder-view-css' => '7b0df4da',
- 'project-icon-css' => '4e3eaa5a',
'raphael-core' => '51ee6b43',
'raphael-g' => '40dde778',
'raphael-g-line' => '40da039e',
@@ -1044,6 +1042,12 @@
'2f670a96' => array(
'phui-theme-css',
),
+ '327a00d1' => array(
+ 'javelin-behavior',
+ 'javelin-stratcom',
+ 'javelin-dom',
+ 'javelin-workflow',
+ ),
'331b1611' => array(
'javelin-install',
),
@@ -1517,12 +1521,6 @@
'javelin-install',
'javelin-dom',
),
- '8fee767e' => array(
- 'javelin-behavior',
- 'javelin-stratcom',
- 'javelin-dom',
- 'javelin-workflow',
- ),
'9007c197' => array(
'javelin-behavior',
'javelin-dom',
diff --git a/resources/sql/autopatches/20151231.proj.01.icon.php b/resources/sql/autopatches/20151231.proj.01.icon.php
new file mode 100644
--- /dev/null
+++ b/resources/sql/autopatches/20151231.proj.01.icon.php
@@ -0,0 +1,34 @@
+<?php
+
+$icon_map = array(
+ 'fa-briefcase' => 'project',
+ 'fa-tags' => 'tag',
+ 'fa-lock' => 'policy',
+ 'fa-users' => 'group',
+
+ 'fa-folder' => 'folder',
+ 'fa-calendar' => 'timeline',
+ 'fa-flag-checkered' => 'goal',
+ 'fa-truck' => 'release',
+
+ 'fa-bug' => 'bugs',
+ 'fa-trash-o' => 'cleanup',
+ 'fa-umbrella' => 'umbrella',
+ 'fa-envelope' => 'communication',
+
+ 'fa-building' => 'organization',
+ 'fa-cloud' => 'infrastructure',
+ 'fa-credit-card' => 'account',
+ 'fa-flask' => 'experimental',
+);
+
+$table = new PhabricatorProject();
+$conn_w = $table->establishConnection('w');
+foreach ($icon_map as $old_icon => $new_key) {
+ queryfx(
+ $conn_w,
+ 'UPDATE %T SET icon = %s WHERE icon = %s',
+ $table->getTableName(),
+ $new_key,
+ $old_icon);
+}
diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php
--- a/src/__phutil_library_map__.php
+++ b/src/__phutil_library_map__.php
@@ -2893,6 +2893,7 @@
'PhabricatorProjectTransaction' => 'applications/project/storage/PhabricatorProjectTransaction.php',
'PhabricatorProjectTransactionEditor' => 'applications/project/editor/PhabricatorProjectTransactionEditor.php',
'PhabricatorProjectTransactionQuery' => 'applications/project/query/PhabricatorProjectTransactionQuery.php',
+ 'PhabricatorProjectTypeConfigOptionType' => 'applications/project/config/PhabricatorProjectTypeConfigOptionType.php',
'PhabricatorProjectUIEventListener' => 'applications/project/events/PhabricatorProjectUIEventListener.php',
'PhabricatorProjectUpdateController' => 'applications/project/controller/PhabricatorProjectUpdateController.php',
'PhabricatorProjectUserFunctionDatasource' => 'applications/project/typeahead/PhabricatorProjectUserFunctionDatasource.php',
@@ -7248,6 +7249,7 @@
'PhabricatorProjectTransaction' => 'PhabricatorApplicationTransaction',
'PhabricatorProjectTransactionEditor' => 'PhabricatorApplicationTransactionEditor',
'PhabricatorProjectTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
+ 'PhabricatorProjectTypeConfigOptionType' => 'PhabricatorConfigJSONOptionType',
'PhabricatorProjectUIEventListener' => 'PhabricatorEventListener',
'PhabricatorProjectUpdateController' => 'PhabricatorProjectController',
'PhabricatorProjectUserFunctionDatasource' => 'PhabricatorTypeaheadCompositeDatasource',
diff --git a/src/applications/config/custom/PhabricatorConfigOptionType.php b/src/applications/config/custom/PhabricatorConfigOptionType.php
--- a/src/applications/config/custom/PhabricatorConfigOptionType.php
+++ b/src/applications/config/custom/PhabricatorConfigOptionType.php
@@ -24,8 +24,7 @@
$value) {
if (is_array($value)) {
- $json = new PhutilJSON();
- return $json->encodeFormatted($value);
+ return PhabricatorConfigJSON::prettyPrintJSON($value);
} else {
return $value;
}
diff --git a/src/applications/files/controller/PhabricatorFileIconSetSelectController.php b/src/applications/files/controller/PhabricatorFileIconSetSelectController.php
--- a/src/applications/files/controller/PhabricatorFileIconSetSelectController.php
+++ b/src/applications/files/controller/PhabricatorFileIconSetSelectController.php
@@ -26,7 +26,7 @@
}
}
- require_celerity_resource('project-icon-css');
+ require_celerity_resource('phui-icon-set-selector-css');
Javelin::initBehavior('phabricator-tooltips');
$ii = 0;
@@ -37,6 +37,20 @@
$view = id(new PHUIIconView())
->setIconFont($icon->getIcon());
+ $classes = array();
+ $classes[] = 'icon-button';
+
+ $is_selected = ($icon->getKey() == $v_icon);
+
+ if ($is_selected) {
+ $classes[] = 'selected';
+ }
+
+ $is_disabled = $icon->getIsDisabled();
+ if ($is_disabled && !$is_selected) {
+ continue;
+ }
+
$aural = javelin_tag(
'span',
array(
@@ -44,13 +58,6 @@
),
pht('Choose "%s" Icon', $label));
- $classes = array();
- $classes[] = 'icon-button';
-
- if ($icon->getKey() == $v_icon) {
- $classes[] = 'selected';
- }
-
$buttons[] = javelin_tag(
'button',
array(
diff --git a/src/applications/files/iconset/PhabricatorIconSetIcon.php b/src/applications/files/iconset/PhabricatorIconSetIcon.php
--- a/src/applications/files/iconset/PhabricatorIconSetIcon.php
+++ b/src/applications/files/iconset/PhabricatorIconSetIcon.php
@@ -6,6 +6,7 @@
private $key;
private $icon;
private $label;
+ private $isDisabled;
public function setKey($key) {
$this->key = $key;
@@ -28,6 +29,15 @@
return $this->icon;
}
+ public function setIsDisabled($is_disabled) {
+ $this->isDisabled = $is_disabled;
+ return $this;
+ }
+
+ public function getIsDisabled() {
+ return $this->isDisabled;
+ }
+
public function setLabel($label) {
$this->label = $label;
return $this;
diff --git a/src/applications/project/conduit/ProjectConduitAPIMethod.php b/src/applications/project/conduit/ProjectConduitAPIMethod.php
--- a/src/applications/project/conduit/ProjectConduitAPIMethod.php
+++ b/src/applications/project/conduit/ProjectConduitAPIMethod.php
@@ -26,7 +26,7 @@
$project_slugs = $project->getSlugs();
$project_slugs = array_values(mpull($project_slugs, 'getSlug'));
- $project_icon = substr($project->getIcon(), 3);
+ $project_icon = $project->getDisplayIconKey();
$result[$project->getPHID()] = array(
'id' => $project->getID(),
diff --git a/src/applications/project/conduit/ProjectQueryConduitAPIMethod.php b/src/applications/project/conduit/ProjectQueryConduitAPIMethod.php
--- a/src/applications/project/conduit/ProjectQueryConduitAPIMethod.php
+++ b/src/applications/project/conduit/ProjectQueryConduitAPIMethod.php
@@ -76,11 +76,6 @@
$request->getValue('icons');
if ($request->getValue('icons')) {
$icons = array();
- // the internal 'fa-' prefix is a detail hidden from api clients
- // but needs to pre prepended to the values in the icons array:
- foreach ($request->getValue('icons') as $value) {
- $icons[] = 'fa-'.$value;
- }
$query->withIcons($icons);
}
diff --git a/src/applications/project/config/PhabricatorProjectConfigOptions.php b/src/applications/project/config/PhabricatorProjectConfigOptions.php
--- a/src/applications/project/config/PhabricatorProjectConfigOptions.php
+++ b/src/applications/project/config/PhabricatorProjectConfigOptions.php
@@ -20,6 +20,34 @@
}
public function getOptions() {
+ $default_icons = PhabricatorProjectIconSet::getDefaultConfiguration();
+ $icons_type = 'custom:PhabricatorProjectTypeConfigOptionType';
+
+ $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_fields = array(
'std:project:internal:description' => true,
);
@@ -45,6 +73,9 @@
$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),
);
}
diff --git a/src/applications/project/config/PhabricatorProjectTypeConfigOptionType.php b/src/applications/project/config/PhabricatorProjectTypeConfigOptionType.php
new file mode 100644
--- /dev/null
+++ b/src/applications/project/config/PhabricatorProjectTypeConfigOptionType.php
@@ -0,0 +1,10 @@
+<?php
+
+final class PhabricatorProjectTypeConfigOptionType
+ extends PhabricatorConfigJSONOptionType {
+
+ public function validateOption(PhabricatorConfigOption $option, $value) {
+ PhabricatorProjectIconSet::validateConfiguration($value);
+ }
+
+}
diff --git a/src/applications/project/controller/PhabricatorProjectController.php b/src/applications/project/controller/PhabricatorProjectController.php
--- a/src/applications/project/controller/PhabricatorProjectController.php
+++ b/src/applications/project/controller/PhabricatorProjectController.php
@@ -156,10 +156,10 @@
$subprojects_icon = 'fa-sitemap grey';
}
- if ($project->supportsMilestones()) {
- $milestones_icon = 'fa-map-marker';
- } else {
- $milestones_icon = 'fa-map-marker grey';
+ $key = PhabricatorProjectIconSet::getMilestoneIconKey();
+ $milestones_icon = PhabricatorProjectIconSet::getIconIcon($key);
+ if (!$project->supportsMilestones()) {
+ $milestones_icon = "{$milestones_icon} grey";
}
$nav->addIcon(
diff --git a/src/applications/project/icon/PhabricatorProjectIconSet.php b/src/applications/project/icon/PhabricatorProjectIconSet.php
--- a/src/applications/project/icon/PhabricatorProjectIconSet.php
+++ b/src/applications/project/icon/PhabricatorProjectIconSet.php
@@ -5,38 +5,121 @@
const ICONSETKEY = 'projects';
+ const SPECIAL_MILESTONE = 'milestone';
+
public function getSelectIconTitleText() {
return pht('Choose Project Icon');
}
- protected function newIcons() {
- $map = array(
- 'fa-briefcase' => pht('Briefcase'),
- 'fa-tags' => pht('Tag'),
- 'fa-folder' => pht('Folder'),
- 'fa-users' => pht('Team'),
-
- 'fa-bug' => pht('Bug'),
- 'fa-trash-o' => pht('Garbage'),
- 'fa-calendar' => pht('Deadline'),
- 'fa-flag-checkered' => pht('Goal'),
-
- 'fa-envelope' => pht('Communication'),
- 'fa-truck' => pht('Release'),
- 'fa-lock' => pht('Policy'),
- 'fa-umbrella' => pht('An Umbrella'),
-
- 'fa-cloud' => pht('The Cloud'),
- 'fa-building' => pht('Company'),
- 'fa-credit-card' => pht('Accounting'),
- 'fa-flask' => pht('Experimental'),
+ public static function getDefaultConfiguration() {
+ return array(
+ array(
+ 'key' => 'project',
+ 'icon' => 'fa-briefcase',
+ 'name' => pht('Project'),
+ 'default' => true,
+ ),
+ array(
+ 'key' => 'tag',
+ 'icon' => 'fa-tags',
+ 'name' => pht('Tag'),
+ ),
+ array(
+ 'key' => 'policy',
+ 'icon' => 'fa-lock',
+ 'name' => pht('Policy'),
+ ),
+ array(
+ 'key' => 'group',
+ 'icon' => 'fa-users',
+ 'name' => pht('Group'),
+ ),
+ array(
+ 'key' => 'folder',
+ 'icon' => 'fa-folder',
+ 'name' => pht('Folder'),
+ ),
+ array(
+ 'key' => 'timeline',
+ 'icon' => 'fa-calendar',
+ 'name' => pht('Timeline'),
+ ),
+ array(
+ 'key' => 'goal',
+ 'icon' => 'fa-flag-checkered',
+ 'name' => pht('Goal'),
+ ),
+ array(
+ 'key' => 'release',
+ 'icon' => 'fa-truck',
+ 'name' => pht('Release'),
+ ),
+ array(
+ 'key' => 'bugs',
+ 'icon' => 'fa-bug',
+ 'name' => pht('Bugs'),
+ ),
+ array(
+ 'key' => 'cleanup',
+ 'icon' => 'fa-trash-o',
+ 'name' => pht('Cleanup'),
+ ),
+ array(
+ 'key' => 'umbrella',
+ 'icon' => 'fa-umbrella',
+ 'name' => pht('Umbrella'),
+ ),
+ array(
+ 'key' => 'communication',
+ 'icon' => 'fa-envelope',
+ 'name' => pht('Communication'),
+ ),
+ array(
+ 'key' => 'organization',
+ 'icon' => 'fa-building',
+ 'name' => pht('Organization'),
+ ),
+ array(
+ 'key' => 'infrastructure',
+ 'icon' => 'fa-cloud',
+ 'name' => pht('Infrastructure'),
+ ),
+ array(
+ 'key' => 'account',
+ 'icon' => 'fa-credit-card',
+ 'name' => pht('Account'),
+ ),
+ array(
+ 'key' => 'experimental',
+ 'icon' => 'fa-flask',
+ 'name' => pht('Experimental'),
+ ),
+ array(
+ 'key' => 'milestone',
+ 'icon' => 'fa-map-marker',
+ 'name' => pht('Milestone'),
+ 'special' => self::SPECIAL_MILESTONE,
+ ),
);
+ }
+
+
+ protected function newIcons() {
+ $map = self::getIconSpecifications();
$icons = array();
- foreach ($map as $key => $label) {
+ foreach ($map as $spec) {
+ $special = idx($spec, 'special');
+
+ if ($special === self::SPECIAL_MILESTONE) {
+ continue;
+ }
+
$icons[] = id(new PhabricatorIconSetIcon())
- ->setKey($key)
- ->setLabel($label);
+ ->setKey($spec['key'])
+ ->setIsDisabled(idx($spec, 'disabled'))
+ ->setIcon($spec['icon'])
+ ->setLabel($spec['name']);
}
return $icons;
@@ -52,4 +135,183 @@
return $shades;
}
+ private static function getIconSpecifications() {
+ return PhabricatorEnv::getEnvConfig('projects.icons');
+ }
+
+ public static function getDefaultIconKey() {
+ $icons = self::getIconSpecifications();
+ foreach ($icons as $icon) {
+ if (idx($icon, 'default')) {
+ return $icon['key'];
+ }
+ }
+ return null;
+ }
+
+ public static function getIconIcon($key) {
+ $spec = self::getIconSpec($key);
+ return idx($spec, 'icon', null);
+ }
+
+ public static function getIconName($key) {
+ $spec = self::getIconSpec($key);
+ return idx($spec, 'name', null);
+ }
+
+ private static function getIconSpec($key) {
+ $icons = self::getIconSpecifications();
+ foreach ($icons as $icon) {
+ if (idx($icon, 'key') === $key) {
+ return $icon;
+ }
+ }
+
+ return array();
+ }
+
+ public static function getMilestoneIconKey() {
+ $icons = self::getIconSpecifications();
+ foreach ($icons as $icon) {
+ if (idx($icon, 'special') === self::SPECIAL_MILESTONE) {
+ return idx($icon, 'key');
+ }
+ }
+ return null;
+ }
+
+ public static function validateConfiguration($config) {
+ if (!is_array($config)) {
+ throw new Exception(
+ pht('Configuration must be a list of project icon specifications.'));
+ }
+
+ foreach ($config as $idx => $value) {
+ if (!is_array($value)) {
+ throw new Exception(
+ pht(
+ 'Value for index "%s" should be a dictionary.',
+ $idx));
+ }
+
+ PhutilTypeSpec::checkMap(
+ $value,
+ array(
+ 'key' => 'string',
+ 'name' => 'string',
+ 'icon' => 'string',
+ 'special' => 'optional string',
+ 'disabled' => 'optional bool',
+ 'default' => 'optional bool',
+ ));
+
+ if (!preg_match('/^[a-z]{1,32}\z/', $value['key'])) {
+ throw new Exception(
+ pht(
+ 'Icon key "%s" is not a valid icon key. Icon keys must be 1-32 '.
+ 'characters long and contain only lowercase letters. For example, '.
+ '"%s" and "%s" are reasonable keys.',
+ 'tag',
+ 'group'));
+ }
+
+ $special = idx($value, 'special');
+ $valid = array(
+ self::SPECIAL_MILESTONE => true,
+ );
+
+ if ($special !== null) {
+ if (empty($valid[$special])) {
+ throw new Exception(
+ pht(
+ 'Icon special attribute "%s" is not valid. Recognized special '.
+ 'attributes are: %s.',
+ $special,
+ implode(', ', array_keys($valid))));
+ }
+ }
+ }
+
+ $default = null;
+ $milestone = null;
+ $keys = array();
+ foreach ($config as $idx => $value) {
+ $key = $value['key'];
+ if (isset($keys[$key])) {
+ throw new Exception(
+ pht(
+ 'Project icons must have unique keys, but two icons share the '.
+ 'same key ("%s").',
+ $key));
+ } else {
+ $keys[$key] = true;
+ }
+
+ $is_disabled = idx($value, 'disabled');
+
+ if (idx($value, 'default')) {
+ if ($default === null) {
+ if ($is_disabled) {
+ throw new Exception(
+ pht(
+ 'The project icon marked as the default icon ("%s") must not '.
+ 'be disabled.',
+ $key));
+ }
+ $default = $value;
+ } else {
+ $original_key = $default['key'];
+ throw new Exception(
+ pht(
+ 'Two different icons ("%s", "%s") are marked as the default '.
+ 'icon. Only one icon may be marked as the default.',
+ $key,
+ $original_key));
+ }
+ }
+
+ $special = idx($value, 'special');
+ if ($special === self::SPECIAL_MILESTONE) {
+ if ($milestone === null) {
+ if ($is_disabled) {
+ throw new Exception(
+ pht(
+ 'The project icon ("%s") with special attribute "%s" must '.
+ 'not be disabled',
+ $key,
+ self::SPECIAL_MIILESTONE));
+ }
+ $milestone = $value;
+ } else {
+ $original_key = $milestone['key'];
+ throw new Exception(
+ pht(
+ 'Two different icons ("%s", "%s") are marked with special '.
+ 'attribute "%s". Only one icon may be marked with this '.
+ 'attribute.',
+ $key,
+ $original_key,
+ self::SPECIAL_MILESTONE));
+ }
+ }
+ }
+
+ if ($default === null) {
+ throw new Exception(
+ pht(
+ 'Project icons must include one icon marked as the "%s" icon, '.
+ 'but no such icon exists.',
+ 'default'));
+ }
+
+ if ($milestone === null) {
+ throw new Exception(
+ pht(
+ 'Project icons must include one icon marked with special attribute '.
+ '"%s", but no such icon exists.',
+ self::SPECIAL_MILESTONE));
+ }
+
+ }
+
}
diff --git a/src/applications/project/phid/PhabricatorProjectProjectPHIDType.php b/src/applications/project/phid/PhabricatorProjectProjectPHIDType.php
--- a/src/applications/project/phid/PhabricatorProjectProjectPHIDType.php
+++ b/src/applications/project/phid/PhabricatorProjectProjectPHIDType.php
@@ -51,7 +51,7 @@
}
$handle->setImageURI($project->getProfileImageURI());
- $handle->setIcon($project->getDisplayIcon());
+ $handle->setIcon($project->getDisplayIconIcon());
$handle->setTagColor($project->getDisplayColor());
if ($project->isArchived()) {
diff --git a/src/applications/project/query/PhabricatorProjectSearchEngine.php b/src/applications/project/query/PhabricatorProjectSearchEngine.php
--- a/src/applications/project/query/PhabricatorProjectSearchEngine.php
+++ b/src/applications/project/query/PhabricatorProjectSearchEngine.php
@@ -131,6 +131,10 @@
$set = new PhabricatorProjectIconSet();
foreach ($set->getIcons() as $icon) {
+ if ($icon->getIsDisabled()) {
+ continue;
+ }
+
$options[$icon->getKey()] = array(
id(new PHUIIconView())
->setIconFont($icon->getIcon()),
diff --git a/src/applications/project/storage/PhabricatorProject.php b/src/applications/project/storage/PhabricatorProject.php
--- a/src/applications/project/storage/PhabricatorProject.php
+++ b/src/applications/project/storage/PhabricatorProject.php
@@ -45,7 +45,6 @@
private $slugs = self::ATTACHABLE;
private $parentProject = self::ATTACHABLE;
- const DEFAULT_ICON = 'fa-briefcase';
const DEFAULT_COLOR = 'blue';
const TABLE_DATASOURCE_TOKEN = 'project_datasourcetoken';
@@ -63,9 +62,11 @@
$join_policy = $app->getPolicy(
ProjectDefaultJoinCapability::CAPABILITY);
+ $default_icon = PhabricatorProjectIconSet::getDefaultIconKey();
+
return id(new PhabricatorProject())
->setAuthorPHID($actor->getPHID())
- ->setIcon(self::DEFAULT_ICON)
+ ->setIcon($default_icon)
->setColor(self::DEFAULT_COLOR)
->setViewPolicy($view_policy)
->setEditPolicy($edit_policy)
@@ -484,12 +485,24 @@
return $number;
}
- public function getDisplayIcon() {
+ public function getDisplayIconKey() {
if ($this->isMilestone()) {
- return 'fa-map-marker';
+ $key = PhabricatorProjectIconSet::getMilestoneIconKey();
+ } else {
+ $key = $this->getIcon();
}
- return $this->getIcon();
+ return $key;
+ }
+
+ public function getDisplayIconIcon() {
+ $key = $this->getDisplayIconKey();
+ return PhabricatorProjectIconSet::getIconIcon($key);
+ }
+
+ public function getDisplayIconName() {
+ $key = $this->getDisplayIconKey();
+ return PhabricatorProjectIconSet::getIconName($key);
}
public function getDisplayColor() {
@@ -608,6 +621,10 @@
->setKey('slug')
->setType('string')
->setDescription(pht('Primary slug/hashtag.')),
+ id(new PhabricatorConduitSearchFieldSpecification())
+ ->setKey('icon')
+ ->setType('map<string, wild>')
+ ->setDescription(pht('Information about the project icon.')),
);
}
@@ -615,6 +632,11 @@
return array(
'name' => $this->getName(),
'slug' => $this->getPrimarySlug(),
+ 'icon' => array(
+ 'key' => $this->getDisplayIconKey(),
+ 'name' => $this->getDisplayIconName(),
+ 'icon' => $this->getDisplayIconIcon(),
+ ),
);
}
diff --git a/src/applications/project/view/PhabricatorProjectListView.php b/src/applications/project/view/PhabricatorProjectListView.php
--- a/src/applications/project/view/PhabricatorProjectListView.php
+++ b/src/applications/project/view/PhabricatorProjectListView.php
@@ -25,15 +25,24 @@
foreach ($projects as $key => $project) {
$id = $project->getID();
- $tag_list = id(new PHUIHandleTagListView())
- ->setSlim(true)
- ->setHandles(array($handles[$project->getPHID()]));
+ $icon = $project->getDisplayIconIcon();
+ $color = $project->getColor();
+
+ $icon_icon = id(new PHUIIconView())
+ ->setIconFont("{$icon} {$color}");
+
+ $icon_name = $project->getDisplayIconName();
$item = id(new PHUIObjectItemView())
->setHeader($project->getName())
->setHref("/project/view/{$id}/")
->setImageURI($project->getProfileImageURI())
- ->addAttribute($tag_list);
+ ->addAttribute(
+ array(
+ $icon_icon,
+ ' ',
+ $icon_name,
+ ));
if ($project->getStatus() == PhabricatorProjectStatus::STATUS_ARCHIVED) {
$item->addIcon('delete-grey', pht('Archived'));
diff --git a/webroot/rsrc/css/application/calendar/calendar-icon.css b/webroot/rsrc/css/application/calendar/calendar-icon.css
deleted file mode 100644
--- a/webroot/rsrc/css/application/calendar/calendar-icon.css
+++ /dev/null
@@ -1,28 +0,0 @@
-/**
- * @provides calendar-icon-css
- */
-
-button.icon-button {
- background: {$lightgreybackground};
- border: 1px solid {$lightblueborder};
- position: relative;
- width: 16px;
- height: 16px;
- padding: 12px;
- margin: 4px;
- text-shadow: none;
- box-shadow: none;
- box-sizing: content-box;
-}
-
-.icon-grid {
- text-align: center;
-}
-
-.icon-icon + .icon-icon {
- margin-left: 4px;
-}
-
-button.icon-button.selected {
- background: {$bluebackground};
-}
diff --git a/webroot/rsrc/css/application/projects/project-icon.css b/webroot/rsrc/css/phui/phui-icon-set-selector.css
rename from webroot/rsrc/css/application/projects/project-icon.css
rename to webroot/rsrc/css/phui/phui-icon-set-selector.css
--- a/webroot/rsrc/css/application/projects/project-icon.css
+++ b/webroot/rsrc/css/phui/phui-icon-set-selector.css
@@ -1,5 +1,5 @@
/**
- * @provides project-icon-css
+ * @provides phui-icon-set-selector-css
*/
button.icon-button {
@@ -25,4 +25,5 @@
button.icon-button.selected {
background: {$bluebackground};
+ border: 1px solid {$blueborder};
}
diff --git a/webroot/rsrc/js/core/behavior-choose-control.js b/webroot/rsrc/js/core/behavior-choose-control.js
--- a/webroot/rsrc/js/core/behavior-choose-control.js
+++ b/webroot/rsrc/js/core/behavior-choose-control.js
@@ -22,7 +22,7 @@
}
var params = {
- value: input.value
+ icon: input.value
};
new JX.Workflow(data.uri, params)
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Thu, Mar 20, 10:04 AM (1 d, 12 h ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
7583766
Default Alt Text
D14918.id36050.diff (28 KB)
Attached To
Mode
D14918: Allow installs to customize project icons
Attached
Detach File
Event Timeline
Log In to Comment