mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-10 00:42:41 +01:00
Provide UI hints about task subtypes
Summary: Ref T12314. Open to counterdiffs / iterating / suggestions / skipping most or all of this, mostly just throwing this out there as a maybe-reasonable first pass. When a task has a subtype (like "Plant" or "Animal"), provide some hints on the task list, workboards, and task detail. To make these hints more useful, allow subtypes to have icons and colors. Also use these icons and colors in the typeahead tokens. The current rule is that we show the subtype if it's not the default subtype. Another rule we could use is "show the subtype if there's more than one subtype defined", but my guess is that most installs will mostly have something like "normal task" as the default subtype. Test Plan: The interfaces this affects are: task detail view, task list view, workboard cards, subtype typeahead. {F3539128} {F3539144} {F3539167} {F3539185} Reviewers: chad Reviewed By: chad Subscribers: johnny-bit, bbrdaric, benwick, fooishbar Maniphest Tasks: T12314 Differential Revision: https://secure.phabricator.com/D17451
This commit is contained in:
parent
81809713e0
commit
742c3a834f
9 changed files with 113 additions and 13 deletions
|
@ -335,9 +335,16 @@ dictionary with these keys:
|
||||||
"task", "feature", or "bug".
|
"task", "feature", or "bug".
|
||||||
- `name` //Required string.// Human-readable name for this subtype, like
|
- `name` //Required string.// Human-readable name for this subtype, like
|
||||||
"Task", "Feature Request" or "Bug Report".
|
"Task", "Feature Request" or "Bug Report".
|
||||||
|
- `tag` //Optional string.// Tag text for this subtype.
|
||||||
|
- `color` //Optional string.// Display color for this subtype.
|
||||||
|
- `icon` //Optional string.// Icon for the subtype.
|
||||||
|
|
||||||
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.
|
||||||
|
|
||||||
|
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
|
||||||
|
no subtype tag and other subtypes will use their name as tag text.
|
||||||
EOTEXT
|
EOTEXT
|
||||||
,
|
,
|
||||||
$subtype_default_key));
|
$subtype_default_key));
|
||||||
|
|
|
@ -240,6 +240,12 @@ final class ManiphestTaskDetailController extends ManiphestController {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$subtype = $task->newSubtypeObject();
|
||||||
|
if ($subtype && $subtype->hasTagView()) {
|
||||||
|
$subtype_tag = $subtype->newTagView();
|
||||||
|
$view->addTag($subtype_tag);
|
||||||
|
}
|
||||||
|
|
||||||
return $view;
|
return $view;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -540,6 +540,11 @@ final class ManiphestTask extends ManiphestDAO
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function newSubtypeObject() {
|
||||||
|
$subtype_key = $this->getEditEngineSubtype();
|
||||||
|
$subtype_map = $this->newEditEngineSubtypeMap();
|
||||||
|
return idx($subtype_map, $subtype_key);
|
||||||
|
}
|
||||||
|
|
||||||
/* -( PhabricatorFulltextInterface )--------------------------------------- */
|
/* -( PhabricatorFulltextInterface )--------------------------------------- */
|
||||||
|
|
||||||
|
|
|
@ -211,4 +211,14 @@ final class ManiphestTransaction
|
||||||
return parent::getNoEffectDescription();
|
return parent::getNoEffectDescription();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function renderSubtypeName($value) {
|
||||||
|
$object = $this->getObject();
|
||||||
|
$map = $object->newEditEngineSubtypeMap();
|
||||||
|
if (!isset($map[$value])) {
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $map[$value]->getName();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,6 +32,7 @@ final class ManiphestTaskSubtypeDatasource
|
||||||
|
|
||||||
$result = id(new PhabricatorTypeaheadResult())
|
$result = id(new PhabricatorTypeaheadResult())
|
||||||
->setIcon($subtype->getIcon())
|
->setIcon($subtype->getIcon())
|
||||||
|
->setColor($subtype->getColor())
|
||||||
->setPHID($key)
|
->setPHID($key)
|
||||||
->setName($subtype->getName());
|
->setName($subtype->getName());
|
||||||
|
|
||||||
|
|
|
@ -56,6 +56,9 @@ final class ManiphestTaskListView extends ManiphestView {
|
||||||
Javelin::initBehavior('maniphest-list-editor');
|
Javelin::initBehavior('maniphest-list-editor');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$subtype_map = id(new ManiphestTask())
|
||||||
|
->newEditEngineSubtypeMap();
|
||||||
|
|
||||||
foreach ($this->tasks as $task) {
|
foreach ($this->tasks as $task) {
|
||||||
$item = id(new PHUIObjectItemView())
|
$item = id(new PHUIObjectItemView())
|
||||||
->setUser($this->getUser())
|
->setUser($this->getUser())
|
||||||
|
@ -94,6 +97,13 @@ final class ManiphestTaskListView extends ManiphestView {
|
||||||
$item->addSigil('maniphest-task');
|
$item->addSigil('maniphest-task');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$subtype = $task->newSubtypeObject();
|
||||||
|
if ($subtype && $subtype->hasTagView()) {
|
||||||
|
$subtype_tag = $subtype->newTagView()
|
||||||
|
->setSlimShady(true);
|
||||||
|
$item->addAttribute($subtype_tag);
|
||||||
|
}
|
||||||
|
|
||||||
$project_handles = array_select_keys(
|
$project_handles = array_select_keys(
|
||||||
$handles,
|
$handles,
|
||||||
array_reverse($task->getProjectPHIDs()));
|
array_reverse($task->getProjectPHIDs()));
|
||||||
|
|
|
@ -3,14 +3,4 @@
|
||||||
abstract class ManiphestTaskTransactionType
|
abstract class ManiphestTaskTransactionType
|
||||||
extends PhabricatorModularTransactionType {
|
extends PhabricatorModularTransactionType {
|
||||||
|
|
||||||
public function renderSubtypeName($value) {
|
|
||||||
$object = $this->getObject();
|
|
||||||
$map = $object->newEditEngineSubtypeMap();
|
|
||||||
if (!isset($map[$value])) {
|
|
||||||
return $value;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $map[$value]->getName();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -108,6 +108,13 @@ final class ProjectBoardTaskCard extends Phobject {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$subtype = $task->newSubtypeObject();
|
||||||
|
if ($subtype && $subtype->hasTagView()) {
|
||||||
|
$subtype_tag = $subtype->newTagView()
|
||||||
|
->setSlimShady(true);
|
||||||
|
$card->addAttribute($subtype_tag);
|
||||||
|
}
|
||||||
|
|
||||||
if ($task->isClosed()) {
|
if ($task->isClosed()) {
|
||||||
$icon = ManiphestTaskStatus::getStatusIcon($task->getStatus());
|
$icon = ManiphestTaskStatus::getStatusIcon($task->getStatus());
|
||||||
$icon = id(new PHUIIconView())
|
$icon = id(new PHUIIconView())
|
||||||
|
|
|
@ -8,6 +8,9 @@ final class PhabricatorEditEngineSubtype
|
||||||
|
|
||||||
private $key;
|
private $key;
|
||||||
private $name;
|
private $name;
|
||||||
|
private $icon;
|
||||||
|
private $tagText;
|
||||||
|
private $color;
|
||||||
|
|
||||||
public function setKey($key) {
|
public function setKey($key) {
|
||||||
$this->key = $key;
|
$this->key = $key;
|
||||||
|
@ -27,8 +30,48 @@ final class PhabricatorEditEngineSubtype
|
||||||
return $this->name;
|
return $this->name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function setIcon($icon) {
|
||||||
|
$this->icon = $icon;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
public function getIcon() {
|
public function getIcon() {
|
||||||
return 'fa-drivers-license-o';
|
return $this->icon;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setTagText($text) {
|
||||||
|
$this->tagText = $text;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTagText() {
|
||||||
|
return $this->tagText;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setColor($color) {
|
||||||
|
$this->color = $color;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getColor() {
|
||||||
|
return $this->color;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function hasTagView() {
|
||||||
|
return (bool)strlen($this->getTagText());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function newTagView() {
|
||||||
|
$view = id(new PHUITagView())
|
||||||
|
->setType(PHUITagView::TYPE_OUTLINE)
|
||||||
|
->setName($this->getTagText());
|
||||||
|
|
||||||
|
$color = $this->getColor();
|
||||||
|
if ($color) {
|
||||||
|
$view->setColor($color);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $view;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function validateSubtypeKey($subtype) {
|
public static function validateSubtypeKey($subtype) {
|
||||||
|
@ -72,6 +115,9 @@ final class PhabricatorEditEngineSubtype
|
||||||
array(
|
array(
|
||||||
'key' => 'string',
|
'key' => 'string',
|
||||||
'name' => 'string',
|
'name' => 'string',
|
||||||
|
'tag' => 'optional string',
|
||||||
|
'color' => 'optional string',
|
||||||
|
'icon' => 'optional string',
|
||||||
));
|
));
|
||||||
|
|
||||||
$key = $value['key'];
|
$key = $value['key'];
|
||||||
|
@ -113,9 +159,27 @@ final class PhabricatorEditEngineSubtype
|
||||||
$key = $entry['key'];
|
$key = $entry['key'];
|
||||||
$name = $entry['name'];
|
$name = $entry['name'];
|
||||||
|
|
||||||
$map[$key] = id(new self())
|
$tag_text = idx($entry, 'tag');
|
||||||
|
if ($tag_text === null) {
|
||||||
|
if ($key != self::SUBTYPE_DEFAULT) {
|
||||||
|
$tag_text = phutil_utf8_strtoupper($name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$color = idx($entry, 'color', 'blue');
|
||||||
|
$icon = idx($entry, 'icon', 'fa-drivers-license-o');
|
||||||
|
|
||||||
|
$subtype = id(new self())
|
||||||
->setKey($key)
|
->setKey($key)
|
||||||
->setName($name);
|
->setName($name)
|
||||||
|
->setTagText($tag_text)
|
||||||
|
->setIcon($icon);
|
||||||
|
|
||||||
|
if ($color) {
|
||||||
|
$subtype->setColor($color);
|
||||||
|
}
|
||||||
|
|
||||||
|
$map[$key] = $subtype;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $map;
|
return $map;
|
||||||
|
|
Loading…
Reference in a new issue