diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -1471,6 +1471,7 @@ 'ManiphestStatusConfigOptionType' => 'applications/maniphest/config/ManiphestStatusConfigOptionType.php', 'ManiphestStatusEmailCommand' => 'applications/maniphest/command/ManiphestStatusEmailCommand.php', 'ManiphestSubpriorityController' => 'applications/maniphest/controller/ManiphestSubpriorityController.php', + 'ManiphestSubtypesConfigOptionsType' => 'applications/maniphest/config/ManiphestSubtypesConfigOptionsType.php', 'ManiphestTask' => 'applications/maniphest/storage/ManiphestTask.php', 'ManiphestTaskAssignHeraldAction' => 'applications/maniphest/herald/ManiphestTaskAssignHeraldAction.php', 'ManiphestTaskAssignOtherHeraldAction' => 'applications/maniphest/herald/ManiphestTaskAssignOtherHeraldAction.php', @@ -6348,6 +6349,7 @@ 'ManiphestStatusConfigOptionType' => 'PhabricatorConfigJSONOptionType', 'ManiphestStatusEmailCommand' => 'ManiphestEmailCommand', 'ManiphestSubpriorityController' => 'ManiphestController', + 'ManiphestSubtypesConfigOptionsType' => 'PhabricatorConfigJSONOptionType', 'ManiphestTask' => array( 'ManiphestDAO', 'PhabricatorSubscribableInterface', diff --git a/src/applications/maniphest/config/ManiphestSubtypesConfigOptionsType.php b/src/applications/maniphest/config/ManiphestSubtypesConfigOptionsType.php new file mode 100644 --- /dev/null +++ b/src/applications/maniphest/config/ManiphestSubtypesConfigOptionsType.php @@ -0,0 +1,10 @@ + $subtype_default_key, + 'name' => pht('Task'), + ), + array( + 'key' => 'bug', + 'name' => pht('Bug'), + ), + array( + 'key' => 'feature', + 'name' => pht('Feature Request'), + ), + ); + $subtype_example = id(new PhutilJSON())->encodeAsList($subtype_example); + + $subtype_default = array( + array( + 'key' => $subtype_default_key, + 'name' => pht('Task'), + ), + ); + + $subtype_description = $this->deformat(pht(<<newOption('maniphest.custom-field-definitions', 'wild', array()) ->setSummary(pht('Custom Maniphest fields.')) @@ -361,6 +405,10 @@ ->setDescription($points_description) ->addExample($points_json_1, pht('Points Config')) ->addExample($points_json_2, pht('Hours Config')), + $this->newOption('maniphest.subtypes', $subtype_type, $subtype_default) + ->setSummary(pht('Define task subtypes.')) + ->setDescription($subtype_description) + ->addExample($subtype_example, pht('Simple Subtypes')), ); } 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 @@ -32,5 +32,53 @@ } } + public static function validateConfiguration($config) { + if (!is_array($config)) { + throw new Exception( + pht( + 'Subtype configuration is invalid: it must be a list of subtype '. + 'specifications.')); + } + + $map = array(); + foreach ($config as $value) { + PhutilTypeSpec::checkMap( + $value, + array( + 'key' => 'string', + 'name' => 'string', + )); + + $key = $value['key']; + self::validateSubtypeKey($key); + + if (isset($map[$key])) { + throw new Exception( + pht( + 'Subtype configuration is invalid: two subtypes use the same '. + 'key ("%s"). Each subtype must have a unique key.', + $key)); + } + + $map[$key] = true; + + $name = $value['name']; + if (!strlen($name)) { + throw new Exception( + pht( + 'Subtype configuration is invalid: subtype with key "%s" has '. + 'no name. Subtypes must have a name.', + $key)); + } + } + + if (!isset($map[self::SUBTYPE_DEFAULT])) { + throw new Exception( + pht( + 'Subtype configuration is invalid: there is no subtype defined '. + 'with key "%s". This subtype is required and must be defined.', + self::SUBTYPE_DEFAULT)); + } + } }