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',
|
'PhabricatorProjectBoardImportController' => 'applications/project/controller/PhabricatorProjectBoardImportController.php',
|
||||||
'PhabricatorProjectBoardReorderController' => 'applications/project/controller/PhabricatorProjectBoardReorderController.php',
|
'PhabricatorProjectBoardReorderController' => 'applications/project/controller/PhabricatorProjectBoardReorderController.php',
|
||||||
'PhabricatorProjectBoardViewController' => 'applications/project/controller/PhabricatorProjectBoardViewController.php',
|
'PhabricatorProjectBoardViewController' => 'applications/project/controller/PhabricatorProjectBoardViewController.php',
|
||||||
|
'PhabricatorProjectColorsConfigOptionType' => 'applications/project/config/PhabricatorProjectColorsConfigOptionType.php',
|
||||||
'PhabricatorProjectColumn' => 'applications/project/storage/PhabricatorProjectColumn.php',
|
'PhabricatorProjectColumn' => 'applications/project/storage/PhabricatorProjectColumn.php',
|
||||||
'PhabricatorProjectColumnDetailController' => 'applications/project/controller/PhabricatorProjectColumnDetailController.php',
|
'PhabricatorProjectColumnDetailController' => 'applications/project/controller/PhabricatorProjectColumnDetailController.php',
|
||||||
'PhabricatorProjectColumnEditController' => 'applications/project/controller/PhabricatorProjectColumnEditController.php',
|
'PhabricatorProjectColumnEditController' => 'applications/project/controller/PhabricatorProjectColumnEditController.php',
|
||||||
|
@ -2890,6 +2891,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorProjectHeraldFieldGroup' => 'applications/project/herald/PhabricatorProjectHeraldFieldGroup.php',
|
'PhabricatorProjectHeraldFieldGroup' => 'applications/project/herald/PhabricatorProjectHeraldFieldGroup.php',
|
||||||
'PhabricatorProjectHistoryController' => 'applications/project/controller/PhabricatorProjectHistoryController.php',
|
'PhabricatorProjectHistoryController' => 'applications/project/controller/PhabricatorProjectHistoryController.php',
|
||||||
'PhabricatorProjectIconSet' => 'applications/project/icon/PhabricatorProjectIconSet.php',
|
'PhabricatorProjectIconSet' => 'applications/project/icon/PhabricatorProjectIconSet.php',
|
||||||
|
'PhabricatorProjectIconsConfigOptionType' => 'applications/project/config/PhabricatorProjectIconsConfigOptionType.php',
|
||||||
'PhabricatorProjectInterface' => 'applications/project/interface/PhabricatorProjectInterface.php',
|
'PhabricatorProjectInterface' => 'applications/project/interface/PhabricatorProjectInterface.php',
|
||||||
'PhabricatorProjectListController' => 'applications/project/controller/PhabricatorProjectListController.php',
|
'PhabricatorProjectListController' => 'applications/project/controller/PhabricatorProjectListController.php',
|
||||||
'PhabricatorProjectListView' => 'applications/project/view/PhabricatorProjectListView.php',
|
'PhabricatorProjectListView' => 'applications/project/view/PhabricatorProjectListView.php',
|
||||||
|
@ -2937,7 +2939,6 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorProjectTransaction' => 'applications/project/storage/PhabricatorProjectTransaction.php',
|
'PhabricatorProjectTransaction' => 'applications/project/storage/PhabricatorProjectTransaction.php',
|
||||||
'PhabricatorProjectTransactionEditor' => 'applications/project/editor/PhabricatorProjectTransactionEditor.php',
|
'PhabricatorProjectTransactionEditor' => 'applications/project/editor/PhabricatorProjectTransactionEditor.php',
|
||||||
'PhabricatorProjectTransactionQuery' => 'applications/project/query/PhabricatorProjectTransactionQuery.php',
|
'PhabricatorProjectTransactionQuery' => 'applications/project/query/PhabricatorProjectTransactionQuery.php',
|
||||||
'PhabricatorProjectTypeConfigOptionType' => 'applications/project/config/PhabricatorProjectTypeConfigOptionType.php',
|
|
||||||
'PhabricatorProjectUIEventListener' => 'applications/project/events/PhabricatorProjectUIEventListener.php',
|
'PhabricatorProjectUIEventListener' => 'applications/project/events/PhabricatorProjectUIEventListener.php',
|
||||||
'PhabricatorProjectUpdateController' => 'applications/project/controller/PhabricatorProjectUpdateController.php',
|
'PhabricatorProjectUpdateController' => 'applications/project/controller/PhabricatorProjectUpdateController.php',
|
||||||
'PhabricatorProjectUserFunctionDatasource' => 'applications/project/typeahead/PhabricatorProjectUserFunctionDatasource.php',
|
'PhabricatorProjectUserFunctionDatasource' => 'applications/project/typeahead/PhabricatorProjectUserFunctionDatasource.php',
|
||||||
|
@ -7255,6 +7256,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorProjectBoardImportController' => 'PhabricatorProjectBoardController',
|
'PhabricatorProjectBoardImportController' => 'PhabricatorProjectBoardController',
|
||||||
'PhabricatorProjectBoardReorderController' => 'PhabricatorProjectBoardController',
|
'PhabricatorProjectBoardReorderController' => 'PhabricatorProjectBoardController',
|
||||||
'PhabricatorProjectBoardViewController' => 'PhabricatorProjectBoardController',
|
'PhabricatorProjectBoardViewController' => 'PhabricatorProjectBoardController',
|
||||||
|
'PhabricatorProjectColorsConfigOptionType' => 'PhabricatorConfigJSONOptionType',
|
||||||
'PhabricatorProjectColumn' => array(
|
'PhabricatorProjectColumn' => array(
|
||||||
'PhabricatorProjectDAO',
|
'PhabricatorProjectDAO',
|
||||||
'PhabricatorApplicationTransactionInterface',
|
'PhabricatorApplicationTransactionInterface',
|
||||||
|
@ -7298,6 +7300,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorProjectHeraldFieldGroup' => 'HeraldFieldGroup',
|
'PhabricatorProjectHeraldFieldGroup' => 'HeraldFieldGroup',
|
||||||
'PhabricatorProjectHistoryController' => 'PhabricatorProjectController',
|
'PhabricatorProjectHistoryController' => 'PhabricatorProjectController',
|
||||||
'PhabricatorProjectIconSet' => 'PhabricatorIconSet',
|
'PhabricatorProjectIconSet' => 'PhabricatorIconSet',
|
||||||
|
'PhabricatorProjectIconsConfigOptionType' => 'PhabricatorConfigJSONOptionType',
|
||||||
'PhabricatorProjectListController' => 'PhabricatorProjectController',
|
'PhabricatorProjectListController' => 'PhabricatorProjectController',
|
||||||
'PhabricatorProjectListView' => 'AphrontView',
|
'PhabricatorProjectListView' => 'AphrontView',
|
||||||
'PhabricatorProjectLockController' => 'PhabricatorProjectController',
|
'PhabricatorProjectLockController' => 'PhabricatorProjectController',
|
||||||
|
@ -7347,7 +7350,6 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorProjectTransaction' => 'PhabricatorApplicationTransaction',
|
'PhabricatorProjectTransaction' => 'PhabricatorApplicationTransaction',
|
||||||
'PhabricatorProjectTransactionEditor' => 'PhabricatorApplicationTransactionEditor',
|
'PhabricatorProjectTransactionEditor' => 'PhabricatorApplicationTransactionEditor',
|
||||||
'PhabricatorProjectTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
|
'PhabricatorProjectTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
|
||||||
'PhabricatorProjectTypeConfigOptionType' => 'PhabricatorConfigJSONOptionType',
|
|
||||||
'PhabricatorProjectUIEventListener' => 'PhabricatorEventListener',
|
'PhabricatorProjectUIEventListener' => 'PhabricatorEventListener',
|
||||||
'PhabricatorProjectUpdateController' => 'PhabricatorProjectController',
|
'PhabricatorProjectUpdateController' => 'PhabricatorProjectController',
|
||||||
'PhabricatorProjectUserFunctionDatasource' => 'PhabricatorTypeaheadCompositeDatasource',
|
'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() {
|
public function getOptions() {
|
||||||
$default_icons = PhabricatorProjectIconSet::getDefaultConfiguration();
|
$default_icons = PhabricatorProjectIconSet::getDefaultConfiguration();
|
||||||
$icons_type = 'custom:PhabricatorProjectTypeConfigOptionType';
|
$icons_type = 'custom:PhabricatorProjectIconsConfigOptionType';
|
||||||
|
|
||||||
$icons_description = $this->deformat(pht(<<<EOTEXT
|
$icons_description = $this->deformat(pht(<<<EOTEXT
|
||||||
Allows you to change and customize the available project icons.
|
Allows you to change and customize the available project icons.
|
||||||
|
@ -47,6 +47,27 @@ configuration.
|
||||||
EOTEXT
|
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(
|
$default_fields = array(
|
||||||
'std:project:internal:description' => true,
|
'std:project:internal:description' => true,
|
||||||
|
@ -76,6 +97,9 @@ EOTEXT
|
||||||
$this->newOption('projects.icons', $icons_type, $default_icons)
|
$this->newOption('projects.icons', $icons_type, $default_icons)
|
||||||
->setSummary(pht('Adjust project icons.'))
|
->setSummary(pht('Adjust project icons.'))
|
||||||
->setDescription($icons_description),
|
->setDescription($icons_description),
|
||||||
|
$this->newOption('projects.colors', $colors_type, $default_colors)
|
||||||
|
->setSummary(pht('Adjust project colors.'))
|
||||||
|
->setDescription($colors_description),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
final class PhabricatorProjectTypeConfigOptionType
|
final class PhabricatorProjectIconsConfigOptionType
|
||||||
extends PhabricatorConfigJSONOptionType {
|
extends PhabricatorConfigJSONOptionType {
|
||||||
|
|
||||||
public function validateOption(PhabricatorConfigOption $option, $value) {
|
public function validateOption(PhabricatorConfigOption $option, $value) {
|
|
@ -125,16 +125,6 @@ final class PhabricatorProjectIconSet
|
||||||
return $icons;
|
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() {
|
private static function getIconSpecifications() {
|
||||||
return PhabricatorEnv::getEnvConfig('projects.icons');
|
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();
|
$query = $this->newQuery();
|
||||||
|
|
||||||
if (strlen($map['name'])) {
|
if (strlen($map['name'])) {
|
||||||
|
@ -155,8 +155,6 @@ protected function buildQueryFromParameters(array $map) {
|
||||||
->setType(PHUITagView::TYPE_SHADE)
|
->setType(PHUITagView::TYPE_SHADE)
|
||||||
->setShade($color)
|
->setShade($color)
|
||||||
->setName($name),
|
->setName($name),
|
||||||
' ',
|
|
||||||
$name,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -44,8 +44,6 @@ final class PhabricatorProject extends PhabricatorProjectDAO
|
||||||
private $slugs = self::ATTACHABLE;
|
private $slugs = self::ATTACHABLE;
|
||||||
private $parentProject = self::ATTACHABLE;
|
private $parentProject = self::ATTACHABLE;
|
||||||
|
|
||||||
const DEFAULT_COLOR = 'blue';
|
|
||||||
|
|
||||||
const TABLE_DATASOURCE_TOKEN = 'project_datasourcetoken';
|
const TABLE_DATASOURCE_TOKEN = 'project_datasourcetoken';
|
||||||
|
|
||||||
const PANEL_PROFILE = 'project.profile';
|
const PANEL_PROFILE = 'project.profile';
|
||||||
|
@ -68,11 +66,12 @@ final class PhabricatorProject extends PhabricatorProjectDAO
|
||||||
ProjectDefaultJoinCapability::CAPABILITY);
|
ProjectDefaultJoinCapability::CAPABILITY);
|
||||||
|
|
||||||
$default_icon = PhabricatorProjectIconSet::getDefaultIconKey();
|
$default_icon = PhabricatorProjectIconSet::getDefaultIconKey();
|
||||||
|
$default_color = PhabricatorProjectIconSet::getDefaultColorKey();
|
||||||
|
|
||||||
return id(new PhabricatorProject())
|
return id(new PhabricatorProject())
|
||||||
->setAuthorPHID($actor->getPHID())
|
->setAuthorPHID($actor->getPHID())
|
||||||
->setIcon($default_icon)
|
->setIcon($default_icon)
|
||||||
->setColor(self::DEFAULT_COLOR)
|
->setColor($default_color)
|
||||||
->setViewPolicy($view_policy)
|
->setViewPolicy($view_policy)
|
||||||
->setEditPolicy($edit_policy)
|
->setEditPolicy($edit_policy)
|
||||||
->setJoinPolicy($join_policy)
|
->setJoinPolicy($join_policy)
|
||||||
|
@ -511,7 +510,7 @@ final class PhabricatorProject extends PhabricatorProjectDAO
|
||||||
|
|
||||||
public function getDisplayColor() {
|
public function getDisplayColor() {
|
||||||
if ($this->isMilestone()) {
|
if ($this->isMilestone()) {
|
||||||
return self::DEFAULT_COLOR;
|
return PhabricatorProjectIconSet::getDefaultColorKey();
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->getColor();
|
return $this->getColor();
|
||||||
|
|
Loading…
Reference in a new issue