1
0
Fork 0
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:
epriestley 2017-03-02 05:02:53 -08:00
parent 81809713e0
commit 742c3a834f
9 changed files with 113 additions and 13 deletions

View file

@ -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));

View file

@ -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;
} }

View file

@ -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 )--------------------------------------- */

View file

@ -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();
}
} }

View file

@ -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());

View file

@ -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()));

View file

@ -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();
}
} }

View file

@ -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())

View file

@ -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;