3 final class PhabricatorProjectIconSet
4 extends PhabricatorIconSet
{
6 const ICONSETKEY
= 'projects';
8 const SPECIAL_MILESTONE
= 'milestone';
10 public function getSelectIconTitleText() {
11 return pht('Choose Project Icon');
14 public static function getDefaultConfiguration() {
18 'icon' => 'fa-briefcase',
19 'name' => pht('Project'),
21 'image' => 'v3/briefcase.png',
27 'image' => 'v3/tag.png',
32 'name' => pht('Policy'),
33 'image' => 'v3/lock.png',
38 'name' => pht('Group'),
39 'image' => 'v3/people.png',
43 'icon' => 'fa-folder',
44 'name' => pht('Folder'),
45 'image' => 'v3/folder.png',
49 'icon' => 'fa-calendar',
50 'name' => pht('Timeline'),
51 'image' => 'v3/calendar.png',
55 'icon' => 'fa-flag-checkered',
56 'name' => pht('Goal'),
57 'image' => 'v3/flag.png',
62 'name' => pht('Release'),
63 'image' => 'v3/truck.png',
68 'name' => pht('Bugs'),
69 'image' => 'v3/bug.png',
73 'icon' => 'fa-trash-o',
74 'name' => pht('Cleanup'),
75 'image' => 'v3/trash.png',
79 'icon' => 'fa-umbrella',
80 'name' => pht('Umbrella'),
81 'image' => 'v3/umbrella.png',
84 'key' => 'communication',
85 'icon' => 'fa-envelope',
86 'name' => pht('Communication'),
87 'image' => 'v3/mail.png',
90 'key' => 'organization',
91 'icon' => 'fa-building',
92 'name' => pht('Organization'),
93 'image' => 'v3/organization.png',
96 'key' => 'infrastructure',
98 'name' => pht('Infrastructure'),
99 'image' => 'v3/cloud.png',
103 'icon' => 'fa-credit-card',
104 'name' => pht('Account'),
105 'image' => 'v3/creditcard.png',
108 'key' => 'experimental',
109 'icon' => 'fa-flask',
110 'name' => pht('Experimental'),
111 'image' => 'v3/experimental.png',
114 'key' => 'milestone',
115 'icon' => 'fa-map-marker',
116 'name' => pht('Milestone'),
117 'special' => self
::SPECIAL_MILESTONE
,
118 'image' => 'v3/marker.png',
124 protected function newIcons() {
125 $map = self
::getIconSpecifications();
128 foreach ($map as $spec) {
129 $special = idx($spec, 'special');
131 if ($special === self
::SPECIAL_MILESTONE
) {
135 $icons[] = id(new PhabricatorIconSetIcon())
136 ->setKey($spec['key'])
137 ->setIsDisabled(idx($spec, 'disabled'))
138 ->setIcon($spec['icon'])
139 ->setLabel($spec['name']);
145 private static function getIconSpecifications() {
146 return PhabricatorEnv
::getEnvConfig('projects.icons');
149 public static function getDefaultIconKey() {
150 $icons = self
::getIconSpecifications();
151 foreach ($icons as $icon) {
152 if (idx($icon, 'default')) {
159 public static function getIconIcon($key) {
160 $spec = self
::getIconSpec($key);
161 return idx($spec, 'icon', null);
164 public static function getIconName($key) {
165 $spec = self
::getIconSpec($key);
166 return idx($spec, 'name', null);
169 public static function getIconImage($key) {
170 $spec = self
::getIconSpec($key);
171 return idx($spec, 'image', 'v3/briefcase.png');
174 private static function getIconSpec($key) {
175 $icons = self
::getIconSpecifications();
176 foreach ($icons as $icon) {
177 if (idx($icon, 'key') === $key) {
185 public static function getMilestoneIconKey() {
186 $icons = self
::getIconSpecifications();
187 foreach ($icons as $icon) {
188 if (idx($icon, 'special') === self
::SPECIAL_MILESTONE
) {
189 return idx($icon, 'key');
195 public static function validateConfiguration($config) {
196 if (!is_array($config)) {
198 pht('Configuration must be a list of project icon specifications.'));
201 foreach ($config as $idx => $value) {
202 if (!is_array($value)) {
205 'Value for index "%s" should be a dictionary.',
209 PhutilTypeSpec
::checkMap(
215 'image' => 'optional string',
216 'special' => 'optional string',
217 'disabled' => 'optional bool',
218 'default' => 'optional bool',
221 if (!preg_match('/^[a-z]{1,32}\z/', $value['key'])) {
224 'Icon key "%s" is not a valid icon key. Icon keys must be 1-32 '.
225 'characters long and contain only lowercase letters. For example, '.
226 '"%s" and "%s" are reasonable keys.',
232 $special = idx($value, 'special');
234 self
::SPECIAL_MILESTONE
=> true,
237 if ($special !== null) {
238 if (empty($valid[$special])) {
241 'Icon special attribute "%s" is not valid. Recognized special '.
242 'attributes are: %s.',
244 implode(', ', array_keys($valid))));
252 foreach ($config as $idx => $value) {
253 $key = $value['key'];
254 if (isset($keys[$key])) {
257 'Project icons must have unique keys, but two icons share the '.
264 $is_disabled = idx($value, 'disabled');
266 $image = idx($value, 'image');
267 if ($image !== null) {
268 $builtin = idx($value, 'image');
269 $builtin_map = id(new PhabricatorFilesOnDiskBuiltinFile())
270 ->getProjectBuiltinFiles();
271 $builtin_map = array_flip($builtin_map);
273 $root = dirname(phutil_get_library_root('phabricator'));
274 $image = $root.'/resources/builtin/projects/'.$builtin;
276 if (!array_key_exists($image, $builtin_map)) {
279 'The project image ("%s") specified for ("%s") '.
280 'was not found in the folder "resources/builtin/projects/".',
286 if (idx($value, 'default')) {
287 if ($default === null) {
291 'The project icon marked as the default icon ("%s") must not '.
297 $original_key = $default['key'];
300 'Two different icons ("%s", "%s") are marked as the default '.
301 'icon. Only one icon may be marked as the default.',
307 $special = idx($value, 'special');
308 if ($special === self
::SPECIAL_MILESTONE
) {
309 if ($milestone === null) {
313 'The project icon ("%s") with special attribute "%s" must '.
316 self
::SPECIAL_MILESTONE
));
320 $original_key = $milestone['key'];
323 'Two different icons ("%s", "%s") are marked with special '.
324 'attribute "%s". Only one icon may be marked with this '.
328 self
::SPECIAL_MILESTONE
));
333 if ($default === null) {
336 'Project icons must include one icon marked as the "%s" icon, '.
337 'but no such icon exists.',
341 if ($milestone === null) {
344 'Project icons must include one icon marked with special attribute '.
345 '"%s", but no such icon exists.',
346 self
::SPECIAL_MILESTONE
));
351 private static function getColorSpecifications() {
352 return PhabricatorEnv
::getEnvConfig('projects.colors');
355 public static function getColorMap() {
356 $specifications = self
::getColorSpecifications();
357 return ipull($specifications, 'name', 'key');
360 public static function getDefaultColorKey() {
361 $specifications = self
::getColorSpecifications();
363 foreach ($specifications as $specification) {
364 if (idx($specification, 'default')) {
365 return $specification['key'];
372 private static function getAvailableColorKeys() {
375 $specifications = self
::getDefaultColorMap();
376 foreach ($specifications as $specification) {
377 $list[] = $specification['key'];
383 public static function getColorName($color_key) {
384 $map = self
::getColorMap();
385 return idx($map, $color_key);
388 public static function getDefaultColorMap() {
391 'key' => PHUITagView
::COLOR_RED
,
392 'name' => pht('Red'),
395 'key' => PHUITagView
::COLOR_ORANGE
,
396 'name' => pht('Orange'),
399 'key' => PHUITagView
::COLOR_YELLOW
,
400 'name' => pht('Yellow'),
403 'key' => PHUITagView
::COLOR_GREEN
,
404 'name' => pht('Green'),
407 'key' => PHUITagView
::COLOR_BLUE
,
408 'name' => pht('Blue'),
412 'key' => PHUITagView
::COLOR_INDIGO
,
413 'name' => pht('Indigo'),
416 'key' => PHUITagView
::COLOR_VIOLET
,
417 'name' => pht('Violet'),
420 'key' => PHUITagView
::COLOR_PINK
,
421 'name' => pht('Pink'),
424 'key' => PHUITagView
::COLOR_GREY
,
425 'name' => pht('Grey'),
428 'key' => PHUITagView
::COLOR_CHECKERED
,
429 'name' => pht('Checkered'),
434 public static function validateColorConfiguration($config) {
435 if (!is_array($config)) {
437 pht('Configuration must be a list of project color specifications.'));
440 $available_keys = self
::getAvailableColorKeys();
441 $available_keys = array_fuse($available_keys);
443 foreach ($config as $idx => $value) {
444 if (!is_array($value)) {
447 'Value for index "%s" should be a dictionary.',
451 PhutilTypeSpec
::checkMap(
456 'default' => 'optional bool',
459 $key = $value['key'];
460 if (!isset($available_keys[$key])) {
463 'Color key "%s" is not a valid color key. The supported color '.
466 implode(', ', $available_keys)));
472 foreach ($config as $idx => $value) {
473 $key = $value['key'];
474 if (isset($keys[$key])) {
477 'Project colors must have unique keys, but two icons share the '.
484 if (idx($value, 'default')) {
485 if ($default === null) {
488 $original_key = $default['key'];
491 'Two different colors ("%s", "%s") are marked as the default '.
492 'color. Only one color may be marked as the default.',
499 if ($default === null) {
502 'Project colors must include one color marked as the "%s" color, '.
503 'but no such color exists.',