Correct a parameter order swap in "diffusion.historyquery" for Mercurial
[phabricator.git] / src / applications / project / icon / PhabricatorProjectIconSet.php
blob5462da78d66c10794fe92e4740b8274799b277fb
1 <?php
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() {
15 return array(
16 array(
17 'key' => 'project',
18 'icon' => 'fa-briefcase',
19 'name' => pht('Project'),
20 'default' => true,
21 'image' => 'v3/briefcase.png',
23 array(
24 'key' => 'tag',
25 'icon' => 'fa-tags',
26 'name' => pht('Tag'),
27 'image' => 'v3/tag.png',
29 array(
30 'key' => 'policy',
31 'icon' => 'fa-lock',
32 'name' => pht('Policy'),
33 'image' => 'v3/lock.png',
35 array(
36 'key' => 'group',
37 'icon' => 'fa-users',
38 'name' => pht('Group'),
39 'image' => 'v3/people.png',
41 array(
42 'key' => 'folder',
43 'icon' => 'fa-folder',
44 'name' => pht('Folder'),
45 'image' => 'v3/folder.png',
47 array(
48 'key' => 'timeline',
49 'icon' => 'fa-calendar',
50 'name' => pht('Timeline'),
51 'image' => 'v3/calendar.png',
53 array(
54 'key' => 'goal',
55 'icon' => 'fa-flag-checkered',
56 'name' => pht('Goal'),
57 'image' => 'v3/flag.png',
59 array(
60 'key' => 'release',
61 'icon' => 'fa-truck',
62 'name' => pht('Release'),
63 'image' => 'v3/truck.png',
65 array(
66 'key' => 'bugs',
67 'icon' => 'fa-bug',
68 'name' => pht('Bugs'),
69 'image' => 'v3/bug.png',
71 array(
72 'key' => 'cleanup',
73 'icon' => 'fa-trash-o',
74 'name' => pht('Cleanup'),
75 'image' => 'v3/trash.png',
77 array(
78 'key' => 'umbrella',
79 'icon' => 'fa-umbrella',
80 'name' => pht('Umbrella'),
81 'image' => 'v3/umbrella.png',
83 array(
84 'key' => 'communication',
85 'icon' => 'fa-envelope',
86 'name' => pht('Communication'),
87 'image' => 'v3/mail.png',
89 array(
90 'key' => 'organization',
91 'icon' => 'fa-building',
92 'name' => pht('Organization'),
93 'image' => 'v3/organization.png',
95 array(
96 'key' => 'infrastructure',
97 'icon' => 'fa-cloud',
98 'name' => pht('Infrastructure'),
99 'image' => 'v3/cloud.png',
101 array(
102 'key' => 'account',
103 'icon' => 'fa-credit-card',
104 'name' => pht('Account'),
105 'image' => 'v3/creditcard.png',
107 array(
108 'key' => 'experimental',
109 'icon' => 'fa-flask',
110 'name' => pht('Experimental'),
111 'image' => 'v3/experimental.png',
113 array(
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();
127 $icons = array();
128 foreach ($map as $spec) {
129 $special = idx($spec, 'special');
131 if ($special === self::SPECIAL_MILESTONE) {
132 continue;
135 $icons[] = id(new PhabricatorIconSetIcon())
136 ->setKey($spec['key'])
137 ->setIsDisabled(idx($spec, 'disabled'))
138 ->setIcon($spec['icon'])
139 ->setLabel($spec['name']);
142 return $icons;
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')) {
153 return $icon['key'];
156 return null;
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) {
178 return $icon;
182 return array();
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');
192 return null;
195 public static function validateConfiguration($config) {
196 if (!is_array($config)) {
197 throw new Exception(
198 pht('Configuration must be a list of project icon specifications.'));
201 foreach ($config as $idx => $value) {
202 if (!is_array($value)) {
203 throw new Exception(
204 pht(
205 'Value for index "%s" should be a dictionary.',
206 $idx));
209 PhutilTypeSpec::checkMap(
210 $value,
211 array(
212 'key' => 'string',
213 'name' => 'string',
214 'icon' => 'string',
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'])) {
222 throw new Exception(
223 pht(
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.',
227 $value['key'],
228 'tag',
229 'group'));
232 $special = idx($value, 'special');
233 $valid = array(
234 self::SPECIAL_MILESTONE => true,
237 if ($special !== null) {
238 if (empty($valid[$special])) {
239 throw new Exception(
240 pht(
241 'Icon special attribute "%s" is not valid. Recognized special '.
242 'attributes are: %s.',
243 $special,
244 implode(', ', array_keys($valid))));
249 $default = null;
250 $milestone = null;
251 $keys = array();
252 foreach ($config as $idx => $value) {
253 $key = $value['key'];
254 if (isset($keys[$key])) {
255 throw new Exception(
256 pht(
257 'Project icons must have unique keys, but two icons share the '.
258 'same key ("%s").',
259 $key));
260 } else {
261 $keys[$key] = true;
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)) {
277 throw new Exception(
278 pht(
279 'The project image ("%s") specified for ("%s") '.
280 'was not found in the folder "resources/builtin/projects/".',
281 $builtin,
282 $key));
286 if (idx($value, 'default')) {
287 if ($default === null) {
288 if ($is_disabled) {
289 throw new Exception(
290 pht(
291 'The project icon marked as the default icon ("%s") must not '.
292 'be disabled.',
293 $key));
295 $default = $value;
296 } else {
297 $original_key = $default['key'];
298 throw new Exception(
299 pht(
300 'Two different icons ("%s", "%s") are marked as the default '.
301 'icon. Only one icon may be marked as the default.',
302 $key,
303 $original_key));
307 $special = idx($value, 'special');
308 if ($special === self::SPECIAL_MILESTONE) {
309 if ($milestone === null) {
310 if ($is_disabled) {
311 throw new Exception(
312 pht(
313 'The project icon ("%s") with special attribute "%s" must '.
314 'not be disabled',
315 $key,
316 self::SPECIAL_MILESTONE));
318 $milestone = $value;
319 } else {
320 $original_key = $milestone['key'];
321 throw new Exception(
322 pht(
323 'Two different icons ("%s", "%s") are marked with special '.
324 'attribute "%s". Only one icon may be marked with this '.
325 'attribute.',
326 $key,
327 $original_key,
328 self::SPECIAL_MILESTONE));
333 if ($default === null) {
334 throw new Exception(
335 pht(
336 'Project icons must include one icon marked as the "%s" icon, '.
337 'but no such icon exists.',
338 'default'));
341 if ($milestone === null) {
342 throw new Exception(
343 pht(
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'];
369 return null;
372 private static function getAvailableColorKeys() {
373 $list = array();
375 $specifications = self::getDefaultColorMap();
376 foreach ($specifications as $specification) {
377 $list[] = $specification['key'];
380 return $list;
383 public static function getColorName($color_key) {
384 $map = self::getColorMap();
385 return idx($map, $color_key);
388 public static function getDefaultColorMap() {
389 return array(
390 array(
391 'key' => PHUITagView::COLOR_RED,
392 'name' => pht('Red'),
394 array(
395 'key' => PHUITagView::COLOR_ORANGE,
396 'name' => pht('Orange'),
398 array(
399 'key' => PHUITagView::COLOR_YELLOW,
400 'name' => pht('Yellow'),
402 array(
403 'key' => PHUITagView::COLOR_GREEN,
404 'name' => pht('Green'),
406 array(
407 'key' => PHUITagView::COLOR_BLUE,
408 'name' => pht('Blue'),
409 'default' => true,
411 array(
412 'key' => PHUITagView::COLOR_INDIGO,
413 'name' => pht('Indigo'),
415 array(
416 'key' => PHUITagView::COLOR_VIOLET,
417 'name' => pht('Violet'),
419 array(
420 'key' => PHUITagView::COLOR_PINK,
421 'name' => pht('Pink'),
423 array(
424 'key' => PHUITagView::COLOR_GREY,
425 'name' => pht('Grey'),
427 array(
428 'key' => PHUITagView::COLOR_CHECKERED,
429 'name' => pht('Checkered'),
434 public static function validateColorConfiguration($config) {
435 if (!is_array($config)) {
436 throw new Exception(
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)) {
445 throw new Exception(
446 pht(
447 'Value for index "%s" should be a dictionary.',
448 $idx));
451 PhutilTypeSpec::checkMap(
452 $value,
453 array(
454 'key' => 'string',
455 'name' => 'string',
456 'default' => 'optional bool',
459 $key = $value['key'];
460 if (!isset($available_keys[$key])) {
461 throw new Exception(
462 pht(
463 'Color key "%s" is not a valid color key. The supported color '.
464 'keys are: %s.',
465 $key,
466 implode(', ', $available_keys)));
470 $default = null;
471 $keys = array();
472 foreach ($config as $idx => $value) {
473 $key = $value['key'];
474 if (isset($keys[$key])) {
475 throw new Exception(
476 pht(
477 'Project colors must have unique keys, but two icons share the '.
478 'same key ("%s").',
479 $key));
480 } else {
481 $keys[$key] = true;
484 if (idx($value, 'default')) {
485 if ($default === null) {
486 $default = $value;
487 } else {
488 $original_key = $default['key'];
489 throw new Exception(
490 pht(
491 'Two different colors ("%s", "%s") are marked as the default '.
492 'color. Only one color may be marked as the default.',
493 $key,
494 $original_key));
499 if ($default === null) {
500 throw new Exception(
501 pht(
502 'Project colors must include one color marked as the "%s" color, '.
503 'but no such color exists.',
504 'default'));