Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F15200455
D20810.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
7 KB
Referenced Files
None
Subscribers
None
D20810.diff
View Options
diff --git a/src/applications/maniphest/config/PhabricatorManiphestConfigOptions.php b/src/applications/maniphest/config/PhabricatorManiphestConfigOptions.php
--- a/src/applications/maniphest/config/PhabricatorManiphestConfigOptions.php
+++ b/src/applications/maniphest/config/PhabricatorManiphestConfigOptions.php
@@ -344,6 +344,8 @@
- `children` //Optional map.// Configure options shown to the user when
they "Create Subtask". See below.
- `fields` //Optional map.// Configure field behaviors. See below.
+ - `mutations` //Optional list.// Configure which subtypes this subtype
+ can easily be converted to by using the "Change Subtype" action. See below.
Each subtype must have a unique key, and you must define a subtype with
the key "%s", which is used as a default subtype.
@@ -404,15 +406,15 @@
task subtypes. For example:
```
-{
- ...
- "fields": {
- "custom.some-field": {
- "disabled": true
+ {
+ ...
+ "fields": {
+ "custom.some-field": {
+ "disabled": true
+ }
}
+ ...
}
- ...
-}
```
Each field supports these options:
@@ -421,6 +423,31 @@
subtypes.
- `name` //Optional string.// Custom name of this field for the subtype.
+
+The `mutations` key allows you to control the behavior of the "Change Subtype"
+action above the comment area. By default, this action allows users to change
+the task subtype into any other subtype.
+
+If you'd prefer to make it more difficult to change subtypes or offer only a
+subset of subtypes, you can specify the list of subtypes that "Change Subtypes"
+offers. For example, if you have several similar subtypes and want to allow
+tasks to be converted between them but not easily converted to other types,
+you can make the "Change Subtypes" control show only these options like this:
+
+```
+ {
+ ...
+ "mutations": ["bug", "issue", "defect"]
+ ...
+ }
+```
+
+If you specify an empty list, the "Change Subtypes" action will be completely
+hidden.
+
+This mutation list is advisory and only configures the UI. Tasks may still be
+converted across subtypes freely by using the Bulk Editor or API.
+
EOTEXT
,
$subtype_default_key));
diff --git a/src/applications/transactions/editengine/PhabricatorEditEngineSubtype.php b/src/applications/transactions/editengine/PhabricatorEditEngineSubtype.php
--- a/src/applications/transactions/editengine/PhabricatorEditEngineSubtype.php
+++ b/src/applications/transactions/editengine/PhabricatorEditEngineSubtype.php
@@ -14,6 +14,7 @@
private $childSubtypes = array();
private $childIdentifiers = array();
private $fieldConfiguration = array();
+ private $mutations;
public function setKey($key) {
$this->key = $key;
@@ -78,6 +79,15 @@
return $this->childIdentifiers;
}
+ public function setMutations($mutations) {
+ $this->mutations = $mutations;
+ return $this;
+ }
+
+ public function getMutations() {
+ return $this->mutations;
+ }
+
public function hasTagView() {
return (bool)strlen($this->getTagText());
}
@@ -152,6 +162,7 @@
'icon' => 'optional string',
'children' => 'optional map<string, wild>',
'fields' => 'optional map<string, wild>',
+ 'mutations' => 'optional list<string>',
));
$key = $value['key'];
@@ -217,6 +228,28 @@
'with key "%s". This subtype is required and must be defined.',
self::SUBTYPE_DEFAULT));
}
+
+ foreach ($config as $value) {
+ $key = idx($value, 'key');
+
+ $mutations = idx($value, 'mutations');
+ if (!$mutations) {
+ continue;
+ }
+
+ foreach ($mutations as $mutation) {
+ if (!isset($map[$mutation])) {
+ throw new Exception(
+ pht(
+ 'Subtype configuration is invalid: subtype with key "%s" '.
+ 'specifies that it can mutate into subtype "%s", but that is '.
+ 'not a valid subtype.',
+ $key,
+ $mutation));
+ }
+ }
+ }
+
}
public static function newSubtypeMap(array $config) {
@@ -267,6 +300,8 @@
}
}
+ $subtype->setMutations(idx($entry, 'mutations'));
+
$map[$key] = $subtype;
}
diff --git a/src/applications/transactions/editengine/PhabricatorEditEngineSubtypeMap.php b/src/applications/transactions/editengine/PhabricatorEditEngineSubtypeMap.php
--- a/src/applications/transactions/editengine/PhabricatorEditEngineSubtypeMap.php
+++ b/src/applications/transactions/editengine/PhabricatorEditEngineSubtypeMap.php
@@ -53,6 +53,44 @@
return clone($this->datasource);
}
+ public function getMutationMap($source_key) {
+ return mpull($this->getMutations($source_key), 'getName');
+ }
+
+ public function getMutations($source_key) {
+ $mutations = $this->subtypes;
+
+ $subtype = idx($this->subtypes, $source_key);
+ if ($subtype) {
+ $map = $subtype->getMutations();
+ if ($map !== null) {
+ $map = array_fuse($map);
+ foreach ($mutations as $key => $mutation) {
+ if ($key === $source_key) {
+ // This is the current subtype, so we always want to show it.
+ continue;
+ }
+
+ if (isset($map[$key])) {
+ // This is an allowed mutation, so keep it.
+ continue;
+ }
+
+ // Discard other subtypes as mutation options.
+ unset($mutations[$key]);
+ }
+ }
+ }
+
+ // If the only available mutation is the current subtype, treat this like
+ // no mutations are available.
+ if (array_keys($mutations) === array($source_key)) {
+ $mutations = array();
+ }
+
+ return $mutations;
+ }
+
public function getCreateFormsForSubtype(
PhabricatorEditEngine $edit_engine,
PhabricatorEditEngineSubtypeInterface $object) {
diff --git a/src/applications/transactions/engineextension/PhabricatorSubtypeEditEngineExtension.php b/src/applications/transactions/engineextension/PhabricatorSubtypeEditEngineExtension.php
--- a/src/applications/transactions/engineextension/PhabricatorSubtypeEditEngineExtension.php
+++ b/src/applications/transactions/engineextension/PhabricatorSubtypeEditEngineExtension.php
@@ -29,9 +29,17 @@
PhabricatorApplicationTransactionInterface $object) {
$subtype_type = PhabricatorTransactions::TYPE_SUBTYPE;
+ $subtype_value = $object->getEditEngineSubtype();
$map = $object->newEditEngineSubtypeMap();
- $options = $map->getDisplayMap();
+
+ if ($object->getID()) {
+ $options = $map->getMutationMap($subtype_value);
+ } else {
+ // NOTE: This is a crude proxy for "are we in the bulk edit workflow".
+ // We want to allow any mutation.
+ $options = $map->getDisplayMap();
+ }
$subtype_field = id(new PhabricatorSelectEditField())
->setKey(self::EDITKEY)
@@ -40,12 +48,12 @@
->setTransactionType($subtype_type)
->setConduitDescription(pht('Change the object subtype.'))
->setConduitTypeDescription(pht('New object subtype key.'))
- ->setValue($object->getEditEngineSubtype())
+ ->setValue($subtype_value)
->setOptions($options);
- // If subtypes are configured, enable changing them from the bulk editor
- // and comment action stack.
- if ($map->getCount() > 1) {
+ // If subtypes are configured, enable changing them from the bulk editor.
+ // Bulk editor
+ if ($options) {
$subtype_field
->setBulkEditLabel(pht('Change subtype to'))
->setCommentActionLabel(pht('Change Subtype'))
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Mon, Feb 24, 1:15 PM (14 h, 21 m)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
7190189
Default Alt Text
D20810.diff (7 KB)
Attached To
Mode
D20810: Allow subtypes to specify "mutations", to control the behavior of the "Change Subtype" action
Attached
Detach File
Event Timeline
Log In to Comment