1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-11-22 23:02:42 +01:00

Allow "maniphest.subtypes" to configure which options are presented by "Create Subtask"

Summary:
Ref T13222. Ref T12588. See PHI683. After D19853, "Create Subtask" may pop a dialog to let you choose between multiple forms.

Allow users to configure which forms are available by using `maniphest.subtypes` to choose available children for each subtype. Users may either specify particular subtypes or specific forms.

Test Plan: Configured "Quest" tasks to have "Objective" children, got appropriate prompt behavior. Used "subtypes" and "forms" to select forms; used "forms" to reorder forms.

Reviewers: amckinley

Reviewed By: amckinley

Maniphest Tasks: T13222, T12588

Differential Revision: https://secure.phabricator.com/D19854
This commit is contained in:
epriestley 2018-12-06 11:42:53 -08:00
parent d1bcdaeda4
commit a6632f8c18
4 changed files with 135 additions and 16 deletions

View file

@ -338,6 +338,8 @@ dictionary with these keys:
- `tag` //Optional string.// Tag text for this subtype. - `tag` //Optional string.// Tag text for this subtype.
- `color` //Optional string.// Display color for this subtype. - `color` //Optional string.// Display color for this subtype.
- `icon` //Optional string.// Icon for the subtype. - `icon` //Optional string.// Icon for the subtype.
- `children` //Optional map.// Configure options shown to the user when
they "Create Subtask". See below.
Each subtype must have a unique key, and you must define a subtype with Each subtype must have a unique key, and you must define a subtype with
the key "%s", which is used as a default subtype. the key "%s", which is used as a default subtype.
@ -345,6 +347,54 @@ the key "%s", which is used as a default subtype.
The tag text (`tag`) is used to set the text shown in the subtype tag on list The tag text (`tag`) is used to set the text shown in the subtype tag on list
views and workboards. If you do not configure it, the default subtype will have views and workboards. If you do not configure it, the default subtype will have
no subtype tag and other subtypes will use their name as tag text. no subtype tag and other subtypes will use their name as tag text.
The `children` key allows you to configure which options are presented to the
user when they "Create Subtask" from a task of this subtype. You can specify
these keys:
- `subtypes`: //Optional list<string>.// Show users creation forms for these
task subtypes.
- `forms`: //Optional list<string|int>.// Show users these specific forms,
in order.
If you don't specify either constraint, users will be shown creation forms
for the same subtype.
For example, if you have a "quest" subtype and do not configure `children`,
users who click "Create Subtask" will be presented with all create forms for
"quest" tasks.
If you want to present them with forms for a different task subtype or set of
subtypes instead, use `subtypes`:
```
{
...
"children": {
"subtypes": ["objective", "boss", "reward"]
}
...
}
```
If you want to present them with specific forms, use `forms` and specify form
IDs:
```
{
...
"children": {
"forms": [12, 16]
}
...
}
```
When specifying forms by ID explicitly, the order you specify the forms in will
be used when presenting options to the user.
If only one option would be presented, the user will be taken directly to the
appropriate form instead of being prompted to choose a form.
EOTEXT EOTEXT
, ,
$subtype_default_key)); $subtype_default_key));

View file

@ -11,6 +11,8 @@ final class PhabricatorEditEngineSubtype
private $icon; private $icon;
private $tagText; private $tagText;
private $color; private $color;
private $childSubtypes = array();
private $childIdentifiers = array();
public function setKey($key) { public function setKey($key) {
$this->key = $key; $this->key = $key;
@ -57,6 +59,24 @@ final class PhabricatorEditEngineSubtype
return $this->color; return $this->color;
} }
public function setChildSubtypes(array $child_subtypes) {
$this->childSubtypes = $child_subtypes;
return $this;
}
public function getChildSubtypes() {
return $this->childSubtypes;
}
public function setChildFormIdentifiers(array $child_identifiers) {
$this->childIdentifiers = $child_identifiers;
return $this;
}
public function getChildFormIdentifiers() {
return $this->childIdentifiers;
}
public function hasTagView() { public function hasTagView() {
return (bool)strlen($this->getTagText()); return (bool)strlen($this->getTagText());
} }
@ -118,6 +138,7 @@ final class PhabricatorEditEngineSubtype
'tag' => 'optional string', 'tag' => 'optional string',
'color' => 'optional string', 'color' => 'optional string',
'icon' => 'optional string', 'icon' => 'optional string',
'children' => 'optional map<string, wild>',
)); ));
$key = $value['key']; $key = $value['key'];
@ -141,6 +162,27 @@ final class PhabricatorEditEngineSubtype
'no name. Subtypes must have a name.', 'no name. Subtypes must have a name.',
$key)); $key));
} }
$children = idx($value, 'children');
if ($children) {
PhutilTypeSpec::checkMap(
$children,
array(
'subtypes' => 'optional list<string>',
'forms' => 'optional list<string|int>',
));
$child_subtypes = idx($children, 'subtypes');
$child_forms = idx($children, 'forms');
if ($child_subtypes && $child_forms) {
throw new Exception(
pht(
'Subtype configuration is invalid: subtype with key "%s" '.
'specifies both child subtypes and child forms. Specify one '.
'or the other, but not both.'));
}
}
} }
if (!isset($map[self::SUBTYPE_DEFAULT])) { if (!isset($map[self::SUBTYPE_DEFAULT])) {
@ -179,6 +221,18 @@ final class PhabricatorEditEngineSubtype
$subtype->setColor($color); $subtype->setColor($color);
} }
$children = idx($entry, 'children', array());
$child_subtypes = idx($children, 'subtypes');
$child_forms = idx($children, 'forms');
if ($child_subtypes) {
$subtype->setChildSubtypes($child_subtypes);
}
if ($child_forms) {
$subtype->setChildFormIdentifiers($child_forms);
}
$map[$key] = $subtype; $map[$key] = $subtype;
} }

View file

@ -46,16 +46,14 @@ final class PhabricatorEditEngineSubtypeMap
$subtype_key = $object->getEditEngineSubtype(); $subtype_key = $object->getEditEngineSubtype();
$subtype = $this->getSubtype($subtype_key); $subtype = $this->getSubtype($subtype_key);
// TODO: Allow subtype configuration to specify that children should be $select_identifiers = $subtype->getChildFormIdentifiers();
// created from particular forms or subtypes. $select_subtypes = $subtype->getChildSubtypes();
$select_ids = array();
$select_subtypes = array();
$query = $edit_engine->newConfigurationQuery() $query = $edit_engine->newConfigurationQuery()
->withIsDisabled(false); ->withIsDisabled(false);
if ($select_ids) { if ($select_identifiers) {
$query->withIDs($select_ids); $query->withIdentifiers($select_identifiers);
} else { } else {
// If we're selecting by subtype rather than selecting specific forms, // If we're selecting by subtype rather than selecting specific forms,
// only select create forms. // only select create forms.
@ -73,8 +71,8 @@ final class PhabricatorEditEngineSubtypeMap
// If we're selecting by ID, respect the order specified in the // If we're selecting by ID, respect the order specified in the
// constraint. Otherwise, use the create form sort order. // constraint. Otherwise, use the create form sort order.
if ($select_ids) { if ($select_identifiers) {
$forms = array_select_keys($forms, $select_ids) + $forms; $forms = array_select_keys($forms, $select_identifiers) + $forms;
} else { } else {
$forms = msort($forms, 'getCreateSortKey'); $forms = msort($forms, 'getCreateSortKey');
} }

View file

@ -115,14 +115,6 @@ final class PhabricatorEditEngineConfigurationSearchEngine
->setHeader($config->getDisplayName()); ->setHeader($config->getDisplayName());
$id = $config->getID(); $id = $config->getID();
if ($id) {
$item->addIcon('fa-file-text-o bluegrey', pht('Form %d', $id));
$key = $id;
} else {
$item->addIcon('fa-file-text bluegrey', pht('Builtin'));
$key = $config->getBuiltinKey();
}
$item->setHref("/transactions/editengine/{$engine_key}/view/{$key}/");
if ($config->getIsDefault()) { if ($config->getIsDefault()) {
$item->addAttribute(pht('Default Create Form')); $item->addAttribute(pht('Default Create Form'));
@ -139,6 +131,31 @@ final class PhabricatorEditEngineConfigurationSearchEngine
$item->setStatusIcon('fa-file-text-o green', pht('Enabled')); $item->setStatusIcon('fa-file-text-o green', pht('Enabled'));
} }
$subtype_key = $config->getSubtype();
if ($subtype_key !== PhabricatorEditEngineSubtype::SUBTYPE_DEFAULT) {
$engine = $config->getEngine();
if ($engine->supportsSubtypes()) {
$map = $engine->newSubtypeMap();
if ($map->isValidSubtype($subtype_key)) {
$subtype = $map->getSubtype($subtype_key);
$icon = $subtype->getIcon();
$color = $subtype->getColor();
$item->addIcon("{$icon} {$color}", $subtype->getName());
}
}
}
if ($id) {
$item->setObjectName(pht('Form %d', $id));
$key = $id;
} else {
$item->addIcon('fa-file-text bluegrey', pht('Builtin'));
$key = $config->getBuiltinKey();
}
$item->setHref("/transactions/editengine/{$engine_key}/view/{$key}/");
$list->addItem($item); $list->addItem($item);
} }