mirror of
https://we.phorge.it/source/phorge.git
synced 2024-12-19 12:00:55 +01:00
Allow project colors to be relabeled
Summary: Fixes T5819. Adds configuration for setting color labels on projects and changing the default. Options are locked to what we make available. Test Plan: {F1066823} Reviewers: chad Reviewed By: chad Maniphest Tasks: T5819 Differential Revision: https://secure.phabricator.com/D15088
This commit is contained in:
parent
12a8726783
commit
c25de5e02f
7 changed files with 197 additions and 21 deletions
|
@ -2858,6 +2858,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorProjectBoardImportController' => 'applications/project/controller/PhabricatorProjectBoardImportController.php',
|
||||
'PhabricatorProjectBoardReorderController' => 'applications/project/controller/PhabricatorProjectBoardReorderController.php',
|
||||
'PhabricatorProjectBoardViewController' => 'applications/project/controller/PhabricatorProjectBoardViewController.php',
|
||||
'PhabricatorProjectColorsConfigOptionType' => 'applications/project/config/PhabricatorProjectColorsConfigOptionType.php',
|
||||
'PhabricatorProjectColumn' => 'applications/project/storage/PhabricatorProjectColumn.php',
|
||||
'PhabricatorProjectColumnDetailController' => 'applications/project/controller/PhabricatorProjectColumnDetailController.php',
|
||||
'PhabricatorProjectColumnEditController' => 'applications/project/controller/PhabricatorProjectColumnEditController.php',
|
||||
|
@ -2890,6 +2891,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorProjectHeraldFieldGroup' => 'applications/project/herald/PhabricatorProjectHeraldFieldGroup.php',
|
||||
'PhabricatorProjectHistoryController' => 'applications/project/controller/PhabricatorProjectHistoryController.php',
|
||||
'PhabricatorProjectIconSet' => 'applications/project/icon/PhabricatorProjectIconSet.php',
|
||||
'PhabricatorProjectIconsConfigOptionType' => 'applications/project/config/PhabricatorProjectIconsConfigOptionType.php',
|
||||
'PhabricatorProjectInterface' => 'applications/project/interface/PhabricatorProjectInterface.php',
|
||||
'PhabricatorProjectListController' => 'applications/project/controller/PhabricatorProjectListController.php',
|
||||
'PhabricatorProjectListView' => 'applications/project/view/PhabricatorProjectListView.php',
|
||||
|
@ -2937,7 +2939,6 @@ phutil_register_library_map(array(
|
|||
'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',
|
||||
|
@ -7255,6 +7256,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorProjectBoardImportController' => 'PhabricatorProjectBoardController',
|
||||
'PhabricatorProjectBoardReorderController' => 'PhabricatorProjectBoardController',
|
||||
'PhabricatorProjectBoardViewController' => 'PhabricatorProjectBoardController',
|
||||
'PhabricatorProjectColorsConfigOptionType' => 'PhabricatorConfigJSONOptionType',
|
||||
'PhabricatorProjectColumn' => array(
|
||||
'PhabricatorProjectDAO',
|
||||
'PhabricatorApplicationTransactionInterface',
|
||||
|
@ -7298,6 +7300,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorProjectHeraldFieldGroup' => 'HeraldFieldGroup',
|
||||
'PhabricatorProjectHistoryController' => 'PhabricatorProjectController',
|
||||
'PhabricatorProjectIconSet' => 'PhabricatorIconSet',
|
||||
'PhabricatorProjectIconsConfigOptionType' => 'PhabricatorConfigJSONOptionType',
|
||||
'PhabricatorProjectListController' => 'PhabricatorProjectController',
|
||||
'PhabricatorProjectListView' => 'AphrontView',
|
||||
'PhabricatorProjectLockController' => 'PhabricatorProjectController',
|
||||
|
@ -7347,7 +7350,6 @@ phutil_register_library_map(array(
|
|||
'PhabricatorProjectTransaction' => 'PhabricatorApplicationTransaction',
|
||||
'PhabricatorProjectTransactionEditor' => 'PhabricatorApplicationTransactionEditor',
|
||||
'PhabricatorProjectTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
|
||||
'PhabricatorProjectTypeConfigOptionType' => 'PhabricatorConfigJSONOptionType',
|
||||
'PhabricatorProjectUIEventListener' => 'PhabricatorEventListener',
|
||||
'PhabricatorProjectUpdateController' => 'PhabricatorProjectController',
|
||||
'PhabricatorProjectUserFunctionDatasource' => 'PhabricatorTypeaheadCompositeDatasource',
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorProjectColorsConfigOptionType
|
||||
extends PhabricatorConfigJSONOptionType {
|
||||
|
||||
public function validateOption(PhabricatorConfigOption $option, $value) {
|
||||
PhabricatorProjectIconSet::validateColorConfiguration($value);
|
||||
}
|
||||
|
||||
}
|
|
@ -21,7 +21,7 @@ final class PhabricatorProjectConfigOptions
|
|||
|
||||
public function getOptions() {
|
||||
$default_icons = PhabricatorProjectIconSet::getDefaultConfiguration();
|
||||
$icons_type = 'custom:PhabricatorProjectTypeConfigOptionType';
|
||||
$icons_type = 'custom:PhabricatorProjectIconsConfigOptionType';
|
||||
|
||||
$icons_description = $this->deformat(pht(<<<EOTEXT
|
||||
Allows you to change and customize the available project icons.
|
||||
|
@ -47,6 +47,27 @@ 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,
|
||||
|
@ -76,6 +97,9 @@ EOTEXT
|
|||
$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),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorProjectTypeConfigOptionType
|
||||
final class PhabricatorProjectIconsConfigOptionType
|
||||
extends PhabricatorConfigJSONOptionType {
|
||||
|
||||
public function validateOption(PhabricatorConfigOption $option, $value) {
|
|
@ -125,16 +125,6 @@ final class PhabricatorProjectIconSet
|
|||
return $icons;
|
||||
}
|
||||
|
||||
public static function getColorMap() {
|
||||
$shades = PHUITagView::getShadeMap();
|
||||
$shades = array_select_keys(
|
||||
$shades,
|
||||
array(PhabricatorProject::DEFAULT_COLOR)) + $shades;
|
||||
unset($shades[PHUITagView::COLOR_DISABLED]);
|
||||
|
||||
return $shades;
|
||||
}
|
||||
|
||||
private static function getIconSpecifications() {
|
||||
return PhabricatorEnv::getEnvConfig('projects.icons');
|
||||
}
|
||||
|
@ -314,4 +304,157 @@ final class PhabricatorProjectIconSet
|
|||
|
||||
}
|
||||
|
||||
private static function getColorSpecifications() {
|
||||
return PhabricatorEnv::getEnvConfig('projects.colors');
|
||||
}
|
||||
|
||||
public static function getColorMap() {
|
||||
$specifications = self::getColorSpecifications();
|
||||
return ipull($specifications, 'name', 'key');
|
||||
}
|
||||
|
||||
public static function getDefaultColorKey() {
|
||||
$specifications = self::getColorSpecifications();
|
||||
|
||||
foreach ($specifications as $specification) {
|
||||
if (idx($specification, 'default')) {
|
||||
return $specification['key'];
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static function getAvailableColorKeys() {
|
||||
$list = array();
|
||||
|
||||
$specifications = self::getDefaultColorMap();
|
||||
foreach ($specifications as $specification) {
|
||||
$list[] = $specification['key'];
|
||||
}
|
||||
|
||||
return $list;
|
||||
}
|
||||
|
||||
public static function getDefaultColorMap() {
|
||||
return array(
|
||||
array(
|
||||
'key' => PHUITagView::COLOR_RED,
|
||||
'name' => pht('Red'),
|
||||
),
|
||||
array(
|
||||
'key' => PHUITagView::COLOR_ORANGE,
|
||||
'name' => pht('Orange'),
|
||||
),
|
||||
array(
|
||||
'key' => PHUITagView::COLOR_YELLOW,
|
||||
'name' => pht('Yellow'),
|
||||
),
|
||||
array(
|
||||
'key' => PHUITagView::COLOR_GREEN,
|
||||
'name' => pht('Green'),
|
||||
),
|
||||
array(
|
||||
'key' => PHUITagView::COLOR_BLUE,
|
||||
'name' => pht('Blue'),
|
||||
'default' => true,
|
||||
),
|
||||
array(
|
||||
'key' => PHUITagView::COLOR_INDIGO,
|
||||
'name' => pht('Indigo'),
|
||||
),
|
||||
array(
|
||||
'key' => PHUITagView::COLOR_VIOLET,
|
||||
'name' => pht('Violet'),
|
||||
),
|
||||
array(
|
||||
'key' => PHUITagView::COLOR_PINK,
|
||||
'name' => pht('Pink'),
|
||||
),
|
||||
array(
|
||||
'key' => PHUITagView::COLOR_GREY,
|
||||
'name' => pht('Grey'),
|
||||
),
|
||||
array(
|
||||
'key' => PHUITagView::COLOR_CHECKERED,
|
||||
'name' => pht('Checkered'),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
public static function validateColorConfiguration($config) {
|
||||
if (!is_array($config)) {
|
||||
throw new Exception(
|
||||
pht('Configuration must be a list of project color specifications.'));
|
||||
}
|
||||
|
||||
$available_keys = self::getAvailableColorKeys();
|
||||
$available_keys = array_fuse($available_keys);
|
||||
|
||||
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',
|
||||
'default' => 'optional bool',
|
||||
));
|
||||
|
||||
$key = $value['key'];
|
||||
if (!isset($available_keys[$key])) {
|
||||
throw new Exception(
|
||||
pht(
|
||||
'Color key "%s" is not a valid color key. The supported color '.
|
||||
'keys are: %s.',
|
||||
$key,
|
||||
implode(', ', $available_keys)));
|
||||
}
|
||||
}
|
||||
|
||||
$default = null;
|
||||
$keys = array();
|
||||
foreach ($config as $idx => $value) {
|
||||
$key = $value['key'];
|
||||
if (isset($keys[$key])) {
|
||||
throw new Exception(
|
||||
pht(
|
||||
'Project colors must have unique keys, but two icons share the '.
|
||||
'same key ("%s").',
|
||||
$key));
|
||||
} else {
|
||||
$keys[$key] = true;
|
||||
}
|
||||
|
||||
if (idx($value, 'default')) {
|
||||
if ($default === null) {
|
||||
$default = $value;
|
||||
} else {
|
||||
$original_key = $default['key'];
|
||||
throw new Exception(
|
||||
pht(
|
||||
'Two different colors ("%s", "%s") are marked as the default '.
|
||||
'color. Only one color may be marked as the default.',
|
||||
$key,
|
||||
$original_key));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($default === null) {
|
||||
throw new Exception(
|
||||
pht(
|
||||
'Project colors must include one color marked as the "%s" color, '.
|
||||
'but no such color exists.',
|
||||
'default'));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -42,7 +42,7 @@ final class PhabricatorProjectSearchEngine
|
|||
}
|
||||
|
||||
|
||||
protected function buildQueryFromParameters(array $map) {
|
||||
protected function buildQueryFromParameters(array $map) {
|
||||
$query = $this->newQuery();
|
||||
|
||||
if (strlen($map['name'])) {
|
||||
|
@ -155,8 +155,6 @@ protected function buildQueryFromParameters(array $map) {
|
|||
->setType(PHUITagView::TYPE_SHADE)
|
||||
->setShade($color)
|
||||
->setName($name),
|
||||
' ',
|
||||
$name,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -44,8 +44,6 @@ final class PhabricatorProject extends PhabricatorProjectDAO
|
|||
private $slugs = self::ATTACHABLE;
|
||||
private $parentProject = self::ATTACHABLE;
|
||||
|
||||
const DEFAULT_COLOR = 'blue';
|
||||
|
||||
const TABLE_DATASOURCE_TOKEN = 'project_datasourcetoken';
|
||||
|
||||
const PANEL_PROFILE = 'project.profile';
|
||||
|
@ -68,11 +66,12 @@ final class PhabricatorProject extends PhabricatorProjectDAO
|
|||
ProjectDefaultJoinCapability::CAPABILITY);
|
||||
|
||||
$default_icon = PhabricatorProjectIconSet::getDefaultIconKey();
|
||||
$default_color = PhabricatorProjectIconSet::getDefaultColorKey();
|
||||
|
||||
return id(new PhabricatorProject())
|
||||
->setAuthorPHID($actor->getPHID())
|
||||
->setIcon($default_icon)
|
||||
->setColor(self::DEFAULT_COLOR)
|
||||
->setColor($default_color)
|
||||
->setViewPolicy($view_policy)
|
||||
->setEditPolicy($edit_policy)
|
||||
->setJoinPolicy($join_policy)
|
||||
|
@ -511,7 +510,7 @@ final class PhabricatorProject extends PhabricatorProjectDAO
|
|||
|
||||
public function getDisplayColor() {
|
||||
if ($this->isMilestone()) {
|
||||
return self::DEFAULT_COLOR;
|
||||
return PhabricatorProjectIconSet::getDefaultColorKey();
|
||||
}
|
||||
|
||||
return $this->getColor();
|
||||
|
|
Loading…
Reference in a new issue