@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at upstream/main 519 lines 14 kB view raw
1<?php 2 3final class PhabricatorProjectIconSet 4 extends PhabricatorIconSet { 5 6 const ICONSETKEY = 'projects'; 7 8 const SPECIAL_MILESTONE = 'milestone'; 9 10 public function getSelectIconTitleText() { 11 return pht('Choose Project Icon'); 12 } 13 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', 22 ), 23 array( 24 'key' => 'tag', 25 'icon' => 'fa-tags', 26 'name' => pht('Tag'), 27 'image' => 'v3/tag.png', 28 ), 29 array( 30 'key' => 'policy', 31 'icon' => 'fa-lock', 32 'name' => pht('Policy'), 33 'image' => 'v3/lock.png', 34 ), 35 array( 36 'key' => 'group', 37 'icon' => 'fa-users', 38 'name' => pht('Group'), 39 'image' => 'v3/people.png', 40 ), 41 array( 42 'key' => 'folder', 43 'icon' => 'fa-folder', 44 'name' => pht('Folder'), 45 'image' => 'v3/folder.png', 46 ), 47 array( 48 'key' => 'timeline', 49 'icon' => 'fa-calendar', 50 'name' => pht('Timeline'), 51 'image' => 'v3/calendar.png', 52 ), 53 array( 54 'key' => 'goal', 55 'icon' => 'fa-flag-checkered', 56 'name' => pht('Goal'), 57 'image' => 'v3/flag.png', 58 ), 59 array( 60 'key' => 'release', 61 'icon' => 'fa-truck', 62 'name' => pht('Release'), 63 'image' => 'v3/truck.png', 64 ), 65 array( 66 'key' => 'bugs', 67 'icon' => 'fa-bug', 68 'name' => pht('Bugs'), 69 'image' => 'v3/bug.png', 70 ), 71 array( 72 'key' => 'cleanup', 73 'icon' => 'fa-trash-o', 74 'name' => pht('Cleanup'), 75 'image' => 'v3/trash.png', 76 ), 77 array( 78 'key' => 'umbrella', 79 'icon' => 'fa-umbrella', 80 'name' => pht('Umbrella'), 81 'image' => 'v3/umbrella.png', 82 ), 83 array( 84 'key' => 'communication', 85 'icon' => 'fa-envelope', 86 'name' => pht('Communication'), 87 'image' => 'v3/mail.png', 88 ), 89 array( 90 'key' => 'organization', 91 'icon' => 'fa-building', 92 'name' => pht('Organization'), 93 'image' => 'v3/organization.png', 94 ), 95 array( 96 'key' => 'infrastructure', 97 'icon' => 'fa-cloud', 98 'name' => pht('Infrastructure'), 99 'image' => 'v3/cloud.png', 100 ), 101 array( 102 'key' => 'account', 103 'icon' => 'fa-credit-card', 104 'name' => pht('Account'), 105 'image' => 'v3/creditcard.png', 106 ), 107 array( 108 'key' => 'experimental', 109 'icon' => 'fa-flask', 110 'name' => pht('Experimental'), 111 'image' => 'v3/experimental.png', 112 ), 113 array( 114 'key' => 'milestone', 115 'icon' => 'fa-map-marker', 116 'name' => pht('Milestone'), 117 'special' => self::SPECIAL_MILESTONE, 118 'image' => 'v3/marker.png', 119 ), 120 ); 121 } 122 123 124 protected function newIcons() { 125 $map = self::getIconSpecifications(); 126 127 $icons = array(); 128 foreach ($map as $spec) { 129 $special = idx($spec, 'special'); 130 131 if ($special === self::SPECIAL_MILESTONE) { 132 continue; 133 } 134 135 $icons[] = id(new PhabricatorIconSetIcon()) 136 ->setKey($spec['key']) 137 ->setIsDisabled(idx($spec, 'disabled')) 138 ->setIcon($spec['icon']) 139 ->setLabel($spec['name']); 140 } 141 142 return $icons; 143 } 144 145 private static function getIconSpecifications() { 146 return PhabricatorEnv::getEnvConfig('projects.icons'); 147 } 148 149 public static function getDefaultIconKey() { 150 $icons = self::getIconSpecifications(); 151 foreach ($icons as $icon) { 152 if (idx($icon, 'default')) { 153 return $icon['key']; 154 } 155 } 156 return null; 157 } 158 159 public static function getIconIcon($key) { 160 $spec = self::getIconSpec($key); 161 return idx($spec, 'icon', null); 162 } 163 164 public static function getIconName($key) { 165 $spec = self::getIconSpec($key); 166 return idx($spec, 'name', null); 167 } 168 169 public static function getIconImage($key) { 170 $spec = self::getIconSpec($key); 171 return idx($spec, 'image', 'v3/briefcase.png'); 172 } 173 174 private static function getIconSpec($key) { 175 $icons = self::getIconSpecifications(); 176 foreach ($icons as $icon) { 177 if (idx($icon, 'key') === $key) { 178 return $icon; 179 } 180 } 181 182 return array(); 183 } 184 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'); 190 } 191 } 192 return null; 193 } 194 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.')); 199 } 200 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)); 207 } 208 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', 219 )); 220 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')); 230 } 231 232 $special = idx($value, 'special'); 233 $valid = array( 234 self::SPECIAL_MILESTONE => true, 235 ); 236 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)))); 245 } 246 } 247 } 248 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; 262 } 263 264 $is_disabled = idx($value, 'disabled'); 265 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); 272 273 $root = dirname(phutil_get_library_root('phabricator')); 274 $image = $root.'/resources/builtin/projects/'.$builtin; 275 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)); 283 } 284 } 285 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)); 294 } 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)); 304 } 305 } 306 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)); 317 } 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)); 329 } 330 } 331 } 332 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')); 339 } 340 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)); 347 } 348 349 } 350 351 private static function getColorSpecifications() { 352 return PhabricatorEnv::getEnvConfig('projects.colors'); 353 } 354 355 public static function getColorMap() { 356 $specifications = self::getColorSpecifications(); 357 return ipull($specifications, 'name', 'key'); 358 } 359 360 public static function getDefaultColorKey() { 361 $specifications = self::getColorSpecifications(); 362 363 foreach ($specifications as $specification) { 364 if (idx($specification, 'default')) { 365 return $specification['key']; 366 } 367 } 368 369 return null; 370 } 371 372 private static function getAvailableColorKeys() { 373 $list = array(); 374 375 $specifications = self::getDefaultColorMap(); 376 foreach ($specifications as $specification) { 377 $list[] = $specification['key']; 378 } 379 380 return $list; 381 } 382 383 public static function getColorName($color_key) { 384 $map = self::getColorMap(); 385 return idx($map, $color_key); 386 } 387 388 /** 389 * Get the default value for the config `project.colors`. 390 * 391 * The result is simple enough to be easily JSON-encoded later. 392 * @return array Array of colors. Each color is an associative array with 393 * these keys: 'key' (color key) and 'name' (translated label). 394 */ 395 public static function getDefaultColorMap() { 396 // In the future, generate this list using PHUITagView::getShadeMapCached(), 397 // instead of re-defining these colors also here. 398 // https://we.phorge.it/T16240 399 return array( 400 array( 401 'key' => PHUITagView::COLOR_RED, 402 'name' => pht('Red'), 403 ), 404 array( 405 'key' => PHUITagView::COLOR_ORANGE, 406 'name' => pht('Orange'), 407 ), 408 array( 409 'key' => PHUITagView::COLOR_YELLOW, 410 'name' => pht('Yellow'), 411 ), 412 array( 413 'key' => PHUITagView::COLOR_GREEN, 414 'name' => pht('Green'), 415 ), 416 array( 417 'key' => PHUITagView::COLOR_BLUE, 418 'name' => pht('Blue'), 419 'default' => true, 420 ), 421 array( 422 'key' => PHUITagView::COLOR_INDIGO, 423 'name' => pht('Indigo'), 424 ), 425 array( 426 'key' => PHUITagView::COLOR_VIOLET, 427 'name' => pht('Violet'), 428 ), 429 array( 430 'key' => PHUITagView::COLOR_PINK, 431 'name' => pht('Pink'), 432 ), 433 array( 434 'key' => PHUITagView::COLOR_GREY, 435 'name' => pht('Grey'), 436 ), 437 array( 438 'key' => PHUITagView::COLOR_CHECKERED, 439 'name' => pht('Checkered'), 440 ), 441 ); 442 } 443 444 public static function validateColorConfiguration($config) { 445 if (!is_array($config)) { 446 throw new Exception( 447 pht('Configuration must be a list of project color specifications.')); 448 } 449 450 $available_keys = self::getAvailableColorKeys(); 451 $available_keys = array_fuse($available_keys); 452 453 foreach ($config as $idx => $value) { 454 if (!is_array($value)) { 455 throw new Exception( 456 pht( 457 'Value for index "%s" should be a dictionary.', 458 $idx)); 459 } 460 461 PhutilTypeSpec::checkMap( 462 $value, 463 array( 464 'key' => 'string', 465 'name' => 'string', 466 'default' => 'optional bool', 467 )); 468 469 $key = $value['key']; 470 if (!isset($available_keys[$key])) { 471 throw new Exception( 472 pht( 473 'Color key "%s" is not a valid color key. The supported color '. 474 'keys are: %s.', 475 $key, 476 implode(', ', $available_keys))); 477 } 478 } 479 480 $default = null; 481 $keys = array(); 482 foreach ($config as $idx => $value) { 483 $key = $value['key']; 484 if (isset($keys[$key])) { 485 throw new Exception( 486 pht( 487 'Project colors must have unique keys, but two icons share the '. 488 'same key ("%s").', 489 $key)); 490 } else { 491 $keys[$key] = true; 492 } 493 494 if (idx($value, 'default')) { 495 if ($default === null) { 496 $default = $value; 497 } else { 498 $original_key = $default['key']; 499 throw new Exception( 500 pht( 501 'Two different colors ("%s", "%s") are marked as the default '. 502 'color. Only one color may be marked as the default.', 503 $key, 504 $original_key)); 505 } 506 } 507 } 508 509 if ($default === null) { 510 throw new Exception( 511 pht( 512 'Project colors must include one color marked as the "%s" color, '. 513 'but no such color exists.', 514 'default')); 515 } 516 517 } 518 519}