Remove all "FileHasObject" edge reads and writes
[phabricator.git] / src / applications / maniphest / config / PhabricatorManiphestConfigOptions.php
blob9bb39874155a762b40a0be5c6d2ff071e1176013
1 <?php
3 final class PhabricatorManiphestConfigOptions
4 extends PhabricatorApplicationConfigOptions {
6 public function getName() {
7 return pht('Maniphest');
10 public function getDescription() {
11 return pht('Configure Maniphest.');
14 public function getIcon() {
15 return 'fa-anchor';
18 public function getGroup() {
19 return 'apps';
22 public function getOptions() {
23 $priority_type = 'maniphest.priorities';
24 $priority_defaults = array(
25 100 => array(
26 'name' => pht('Unbreak Now!'),
27 'keywords' => array('unbreak'),
28 'short' => pht('Unbreak!'),
29 'color' => 'pink',
31 90 => array(
32 'name' => pht('Needs Triage'),
33 'keywords' => array('triage'),
34 'short' => pht('Triage'),
35 'color' => 'violet',
37 80 => array(
38 'name' => pht('High'),
39 'keywords' => array('high'),
40 'short' => pht('High'),
41 'color' => 'red',
43 50 => array(
44 'name' => pht('Normal'),
45 'keywords' => array('normal'),
46 'short' => pht('Normal'),
47 'color' => 'orange',
49 25 => array(
50 'name' => pht('Low'),
51 'keywords' => array('low'),
52 'short' => pht('Low'),
53 'color' => 'yellow',
55 0 => array(
56 'name' => pht('Wishlist'),
57 'keywords' => array('wish', 'wishlist'),
58 'short' => pht('Wish'),
59 'color' => 'sky',
63 $status_type = 'maniphest.statuses';
64 $status_defaults = array(
65 'open' => array(
66 'name' => pht('Open'),
67 'special' => ManiphestTaskStatus::SPECIAL_DEFAULT,
68 'prefixes' => array(
69 'open',
70 'opens',
71 'reopen',
72 'reopens',
75 'resolved' => array(
76 'name' => pht('Resolved'),
77 'name.full' => pht('Closed, Resolved'),
78 'closed' => true,
79 'special' => ManiphestTaskStatus::SPECIAL_CLOSED,
80 'transaction.icon' => 'fa-check-circle',
81 'prefixes' => array(
82 'closed',
83 'closes',
84 'close',
85 'fix',
86 'fixes',
87 'fixed',
88 'resolve',
89 'resolves',
90 'resolved',
92 'suffixes' => array(
93 'as resolved',
94 'as fixed',
96 'keywords' => array('closed', 'fixed', 'resolved'),
98 'wontfix' => array(
99 'name' => pht('Wontfix'),
100 'name.full' => pht('Closed, Wontfix'),
101 'transaction.icon' => 'fa-ban',
102 'closed' => true,
103 'prefixes' => array(
104 'wontfix',
105 'wontfixes',
106 'wontfixed',
108 'suffixes' => array(
109 'as wontfix',
112 'invalid' => array(
113 'name' => pht('Invalid'),
114 'name.full' => pht('Closed, Invalid'),
115 'transaction.icon' => 'fa-minus-circle',
116 'closed' => true,
117 'claim' => false,
118 'prefixes' => array(
119 'invalidate',
120 'invalidates',
121 'invalidated',
123 'suffixes' => array(
124 'as invalid',
127 'duplicate' => array(
128 'name' => pht('Duplicate'),
129 'name.full' => pht('Closed, Duplicate'),
130 'transaction.icon' => 'fa-files-o',
131 'special' => ManiphestTaskStatus::SPECIAL_DUPLICATE,
132 'closed' => true,
133 'claim' => false,
135 'spite' => array(
136 'name' => pht('Spite'),
137 'name.full' => pht('Closed, Spite'),
138 'name.action' => pht('Spited'),
139 'transaction.icon' => 'fa-thumbs-o-down',
140 'silly' => true,
141 'closed' => true,
142 'prefixes' => array(
143 'spite',
144 'spites',
145 'spited',
147 'suffixes' => array(
148 'out of spite',
149 'as spite',
154 $status_description = $this->deformat(pht(<<<EOTEXT
155 Allows you to edit, add, or remove the task statuses available in Maniphest,
156 like "Open", "Resolved" and "Invalid". The configuration should contain a map
157 of status constants to status specifications (see defaults below for examples).
159 The constant for each status should be 1-12 characters long and contain only
160 lowercase letters and digits. Valid examples are "open", "closed", and
161 "invalid". Users will not normally see these values.
163 The keys you can provide in a specification are:
165 - `name` //Required string.// Name of the status, like "Invalid".
166 - `name.full` //Optional string.// Longer name, like "Closed, Invalid". This
167 appears on the task detail view in the header.
168 - `name.action` //Optional string.// Action name for email subjects, like
169 "Marked Invalid".
170 - `closed` //Optional bool.// Statuses are either "open" or "closed".
171 Specifying `true` here will mark the status as closed (like "Resolved" or
172 "Invalid"). By default, statuses are open.
173 - `special` //Optional string.// Mark this status as special. The special
174 statuses are:
175 - `default` This is the default status for newly created tasks. You must
176 designate one status as default, and it must be an open status.
177 - `closed` This is the default status for closed tasks (for example, tasks
178 closed via the "!close" action in email or via the quick close button in
179 Maniphest). You must designate one status as the default closed status,
180 and it must be a closed status.
181 - `duplicate` This is the status used when tasks are merged into one
182 another as duplicates. You must designate one status for duplicates,
183 and it must be a closed status.
184 - `transaction.icon` //Optional string.// Allows you to choose a different
185 icon to use for this status when showing status changes in the transaction
186 log. Please see UIExamples, Icons and Images for a list.
187 - `transaction.color` //Optional string.// Allows you to choose a different
188 color to use for this status when showing status changes in the transaction
189 log.
190 - `silly` //Optional bool.// Marks this status as silly, and thus wholly
191 inappropriate for use by serious businesses.
192 - `prefixes` //Optional list<string>.// Allows you to specify a list of
193 text prefixes which will trigger a task transition into this status
194 when mentioned in a commit message. For example, providing "closes" here
195 will allow users to move tasks to this status by writing `Closes T123` in
196 commit messages.
197 - `suffixes` //Optional list<string>.// Allows you to specify a list of
198 text suffixes which will trigger a task transition into this status
199 when mentioned in a commit message, after a valid prefix. For example,
200 providing "as invalid" here will allow users to move tasks
201 to this status by writing `Closes T123 as invalid`, even if another status
202 is selected by the "Closes" prefix.
203 - `keywords` //Optional list<string>.// Allows you to specify a list
204 of keywords which can be used with `!status` commands in email to select
205 this status.
206 - `disabled` //Optional bool.// Marks this status as no longer in use so
207 tasks can not be created or edited to have this status. Existing tasks with
208 this status will not be affected, but you can batch edit them or let them
209 die out on their own.
210 - `claim` //Optional bool.// By default, closing an unassigned task claims
211 it. You can set this to `false` to disable this behavior for a particular
212 status.
213 - `locked` //Optional string.// Lock tasks in this status. Specify "comments"
214 to lock comments (users who can edit the task may override this lock).
215 Specify "edits" to prevent anyone except the task owner from making edits.
216 - `mfa` //Optional bool.// Require all edits to this task to be signed with
217 multi-factor authentication.
219 Statuses will appear in the UI in the order specified. Note the status marked
220 `special` as `duplicate` is not settable directly and will not appear in UI
221 elements, and that any status marked `silly` does not appear if the software
222 is configured with `phabricator.serious-business` set to true.
224 Examining the default configuration and examples below will probably be helpful
225 in understanding these options.
227 EOTEXT
230 $status_example = array(
231 'open' => array(
232 'name' => pht('Open'),
233 'special' => 'default',
235 'closed' => array(
236 'name' => pht('Closed'),
237 'special' => 'closed',
238 'closed' => true,
240 'duplicate' => array(
241 'name' => pht('Duplicate'),
242 'special' => 'duplicate',
243 'closed' => true,
247 $json = new PhutilJSON();
248 $status_example = $json->encodeFormatted($status_example);
250 // This is intentionally blank for now, until we can move more Maniphest
251 // logic to custom fields.
252 $default_fields = array();
254 foreach ($default_fields as $key => $enabled) {
255 $default_fields[$key] = array(
256 'disabled' => !$enabled,
260 $custom_field_type = 'custom:PhabricatorCustomFieldConfigOptionType';
262 $fields_example = array(
263 'mycompany.estimated-hours' => array(
264 'name' => pht('Estimated Hours'),
265 'type' => 'int',
266 'caption' => pht('Estimated number of hours this will take.'),
269 $fields_json = id(new PhutilJSON())->encodeFormatted($fields_example);
271 $points_type = 'maniphest.points';
273 $points_example_1 = array(
274 'enabled' => true,
275 'label' => pht('Story Points'),
276 'action' => pht('Change Story Points'),
278 $points_json_1 = id(new PhutilJSON())->encodeFormatted($points_example_1);
280 $points_example_2 = array(
281 'enabled' => true,
282 'label' => pht('Estimated Hours'),
283 'action' => pht('Change Estimate'),
285 $points_json_2 = id(new PhutilJSON())->encodeFormatted($points_example_2);
287 $points_description = $this->deformat(pht(<<<EOTEXT
288 Activates a points field on tasks. You can use points for estimation or
289 planning. If configured, points will appear on workboards.
291 To activate points, set this value to a map with these keys:
293 - `enabled` //Optional bool.// Use `true` to enable points, or
294 `false` to disable them.
295 - `label` //Optional string.// Label for points, like "Story Points" or
296 "Estimated Hours". If omitted, points will be called "Points".
297 - `action` //Optional string.// Label for the action which changes points
298 in Maniphest, like "Change Estimate". If omitted, the action will
299 be called "Change Points".
301 See the example below for a starting point.
302 EOTEXT
305 $subtype_type = 'maniphest.subtypes';
306 $subtype_default_key = PhabricatorEditEngineSubtype::SUBTYPE_DEFAULT;
307 $subtype_example = array(
308 array(
309 'key' => $subtype_default_key,
310 'name' => pht('Task'),
312 array(
313 'key' => 'bug',
314 'name' => pht('Bug'),
316 array(
317 'key' => 'feature',
318 'name' => pht('Feature Request'),
321 $subtype_example = id(new PhutilJSON())->encodeAsList($subtype_example);
323 $subtype_default = array(
324 array(
325 'key' => $subtype_default_key,
326 'name' => pht('Task'),
330 $subtype_description = $this->deformat(pht(<<<EOTEXT
331 Allows you to define task subtypes. Subtypes let you hide fields you don't
332 need to simplify the workflows for editing tasks.
334 To define subtypes, provide a list of subtypes. Each subtype should be a
335 dictionary with these keys:
337 - `key` //Required string.// Internal identifier for the subtype, like
338 "task", "feature", or "bug".
339 - `name` //Required string.// Human-readable name for this subtype, like
340 "Task", "Feature Request" or "Bug Report".
341 - `tag` //Optional string.// Tag text for this subtype.
342 - `color` //Optional string.// Display color for this subtype.
343 - `icon` //Optional string.// Icon for the subtype.
344 - `children` //Optional map.// Configure options shown to the user when
345 they "Create Subtask". See below.
346 - `fields` //Optional map.// Configure field behaviors. See below.
347 - `mutations` //Optional list.// Configure which subtypes this subtype
348 can easily be converted to by using the "Change Subtype" action. See below.
350 Each subtype must have a unique key, and you must define a subtype with
351 the key "%s", which is used as a default subtype.
353 The tag text (`tag`) is used to set the text shown in the subtype tag on list
354 views and workboards. If you do not configure it, the default subtype will have
355 no subtype tag and other subtypes will use their name as tag text.
357 The `children` key allows you to configure which options are presented to the
358 user when they "Create Subtask" from a task of this subtype. You can specify
359 these keys:
361 - `subtypes`: //Optional list<string>.// Show users creation forms for these
362 task subtypes.
363 - `forms`: //Optional list<string|int>.// Show users these specific forms,
364 in order.
366 If you don't specify either constraint, users will be shown creation forms
367 for the same subtype.
369 For example, if you have a "quest" subtype and do not configure `children`,
370 users who click "Create Subtask" will be presented with all create forms for
371 "quest" tasks.
373 If you want to present them with forms for a different task subtype or set of
374 subtypes instead, use `subtypes`:
379 "children": {
380 "subtypes": ["objective", "boss", "reward"]
386 If you want to present them with specific forms, use `forms` and specify form
387 IDs:
392 "children": {
393 "forms": [12, 16]
399 When specifying forms by ID explicitly, the order you specify the forms in will
400 be used when presenting options to the user.
402 If only one option would be presented, the user will be taken directly to the
403 appropriate form instead of being prompted to choose a form.
405 The `fields` key can configure the behavior of custom fields on specific
406 task subtypes. For example:
411 "fields": {
412 "custom.some-field": {
413 "disabled": true
420 Each field supports these options:
422 - `disabled` //Optional bool.// Allows you to disable fields on certain
423 subtypes.
424 - `name` //Optional string.// Custom name of this field for the subtype.
427 The `mutations` key allows you to control the behavior of the "Change Subtype"
428 action above the comment area. By default, this action allows users to change
429 the task subtype into any other subtype.
431 If you'd prefer to make it more difficult to change subtypes or offer only a
432 subset of subtypes, you can specify the list of subtypes that "Change Subtypes"
433 offers. For example, if you have several similar subtypes and want to allow
434 tasks to be converted between them but not easily converted to other types,
435 you can make the "Change Subtypes" control show only these options like this:
440 "mutations": ["bug", "issue", "defect"]
445 If you specify an empty list, the "Change Subtypes" action will be completely
446 hidden.
448 This mutation list is advisory and only configures the UI. Tasks may still be
449 converted across subtypes freely by using the Bulk Editor or API.
451 EOTEXT
453 $subtype_default_key));
455 $priorities_description = $this->deformat(pht(<<<EOTEXT
456 Allows you to edit or override the default priorities available in Maniphest,
457 like "High", "Normal" and "Low". The configuration should contain a map of
458 numeric priority values (where larger numbers correspond to higher priorities)
459 to priority specifications (see defaults below for examples).
461 The keys you can define for a priority are:
463 - `name` //Required string.// Name of the priority.
464 - `keywords` //Required list<string>.// List of unique keywords which identify
465 this priority, like "high" or "low". Each priority must have at least one
466 keyword and two priorities may not share the same keyword.
467 - `short` //Optional string.// Alternate shorter name, used in UIs where
468 there is less space available.
469 - `color` //Optional string.// Color for this priority, like "red" or
470 "blue".
471 - `disabled` //Optional bool.// Set to true to prevent users from choosing
472 this priority when creating or editing tasks. Existing tasks will not be
473 affected, and can be batch edited to a different priority or left to
474 eventually die out.
476 You can choose the default priority for newly created tasks with
477 "maniphest.default-priority".
478 EOTEXT
481 $fields_description = $this->deformat(pht(<<<EOTEXT
482 List of custom fields for Maniphest tasks.
484 For details on adding custom fields to Maniphest, see [[ %s | %s ]] in the
485 documentation.
486 EOTEXT
488 PhabricatorEnv::getDoclink('Configuring Custom Fields'),
489 pht('Configuring Custom Fields')));
491 return array(
492 $this->newOption('maniphest.custom-field-definitions', 'wild', array())
493 ->setSummary(pht('Custom Maniphest fields.'))
494 ->setDescription($fields_description)
495 ->addExample($fields_json, pht('Valid setting')),
496 $this->newOption('maniphest.fields', $custom_field_type, $default_fields)
497 ->setCustomData(id(new ManiphestTask())->getCustomFieldBaseClass())
498 ->setDescription(pht('Select and reorder task fields.')),
499 $this->newOption(
500 'maniphest.priorities',
501 $priority_type,
502 $priority_defaults)
503 ->setSummary(pht('Configure Maniphest priority names.'))
504 ->setDescription($priorities_description),
505 $this->newOption('maniphest.statuses', $status_type, $status_defaults)
506 ->setSummary(pht('Configure Maniphest task statuses.'))
507 ->setDescription($status_description)
508 ->addExample($status_example, pht('Minimal Valid Config')),
509 $this->newOption('maniphest.default-priority', 'int', 90)
510 ->setSummary(pht('Default task priority for create flows.'))
511 ->setDescription(
512 pht(
513 'Choose a default priority for newly created tasks. You can '.
514 'review and adjust available priorities by using the '.
515 '%s configuration option. The default value (`90`) '.
516 'corresponds to the default "Needs Triage" priority.',
517 'maniphest.priorities')),
518 $this->newOption('maniphest.points', $points_type, array())
519 ->setSummary(pht('Configure point values for tasks.'))
520 ->setDescription($points_description)
521 ->addExample($points_json_1, pht('Points Config'))
522 ->addExample($points_json_2, pht('Hours Config')),
523 $this->newOption('maniphest.subtypes', $subtype_type, $subtype_default)
524 ->setSummary(pht('Define task subtypes.'))
525 ->setDescription($subtype_description)
526 ->addExample($subtype_example, pht('Simple Subtypes')),