From 742c3a834fc5cd19a4b53e9ff31f7b0efd67e239 Mon Sep 17 00:00:00 2001 From: epriestley Date: Thu, 2 Mar 2017 05:02:53 -0800 Subject: [PATCH] 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 --- .../PhabricatorManiphestConfigOptions.php | 7 ++ .../ManiphestTaskDetailController.php | 6 ++ .../maniphest/storage/ManiphestTask.php | 5 ++ .../storage/ManiphestTransaction.php | 10 +++ .../ManiphestTaskSubtypeDatasource.php | 1 + .../maniphest/view/ManiphestTaskListView.php | 10 +++ .../xaction/ManiphestTaskTransactionType.php | 10 --- .../project/view/ProjectBoardTaskCard.php | 7 ++ .../PhabricatorEditEngineSubtype.php | 70 ++++++++++++++++++- 9 files changed, 113 insertions(+), 13 deletions(-) diff --git a/src/applications/maniphest/config/PhabricatorManiphestConfigOptions.php b/src/applications/maniphest/config/PhabricatorManiphestConfigOptions.php index 4a1927c5a8..9d927ffca1 100644 --- a/src/applications/maniphest/config/PhabricatorManiphestConfigOptions.php +++ b/src/applications/maniphest/config/PhabricatorManiphestConfigOptions.php @@ -335,9 +335,16 @@ dictionary with these keys: "task", "feature", or "bug". - `name` //Required string.// Human-readable name for this subtype, like "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 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 , $subtype_default_key)); diff --git a/src/applications/maniphest/controller/ManiphestTaskDetailController.php b/src/applications/maniphest/controller/ManiphestTaskDetailController.php index 7859599a2f..92fe703f91 100644 --- a/src/applications/maniphest/controller/ManiphestTaskDetailController.php +++ b/src/applications/maniphest/controller/ManiphestTaskDetailController.php @@ -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; } diff --git a/src/applications/maniphest/storage/ManiphestTask.php b/src/applications/maniphest/storage/ManiphestTask.php index 16937da2f2..7cf9d3353f 100644 --- a/src/applications/maniphest/storage/ManiphestTask.php +++ b/src/applications/maniphest/storage/ManiphestTask.php @@ -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 )--------------------------------------- */ diff --git a/src/applications/maniphest/storage/ManiphestTransaction.php b/src/applications/maniphest/storage/ManiphestTransaction.php index 0d27ddc5da..e2739c1d09 100644 --- a/src/applications/maniphest/storage/ManiphestTransaction.php +++ b/src/applications/maniphest/storage/ManiphestTransaction.php @@ -211,4 +211,14 @@ final class ManiphestTransaction return parent::getNoEffectDescription(); } + public function renderSubtypeName($value) { + $object = $this->getObject(); + $map = $object->newEditEngineSubtypeMap(); + if (!isset($map[$value])) { + return $value; + } + + return $map[$value]->getName(); + } + } diff --git a/src/applications/maniphest/typeahead/ManiphestTaskSubtypeDatasource.php b/src/applications/maniphest/typeahead/ManiphestTaskSubtypeDatasource.php index 2678e946b4..c061c694e4 100644 --- a/src/applications/maniphest/typeahead/ManiphestTaskSubtypeDatasource.php +++ b/src/applications/maniphest/typeahead/ManiphestTaskSubtypeDatasource.php @@ -32,6 +32,7 @@ final class ManiphestTaskSubtypeDatasource $result = id(new PhabricatorTypeaheadResult()) ->setIcon($subtype->getIcon()) + ->setColor($subtype->getColor()) ->setPHID($key) ->setName($subtype->getName()); diff --git a/src/applications/maniphest/view/ManiphestTaskListView.php b/src/applications/maniphest/view/ManiphestTaskListView.php index 6f714d0c5c..de6b386ac8 100644 --- a/src/applications/maniphest/view/ManiphestTaskListView.php +++ b/src/applications/maniphest/view/ManiphestTaskListView.php @@ -56,6 +56,9 @@ final class ManiphestTaskListView extends ManiphestView { Javelin::initBehavior('maniphest-list-editor'); } + $subtype_map = id(new ManiphestTask()) + ->newEditEngineSubtypeMap(); + foreach ($this->tasks as $task) { $item = id(new PHUIObjectItemView()) ->setUser($this->getUser()) @@ -94,6 +97,13 @@ final class ManiphestTaskListView extends ManiphestView { $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( $handles, array_reverse($task->getProjectPHIDs())); diff --git a/src/applications/maniphest/xaction/ManiphestTaskTransactionType.php b/src/applications/maniphest/xaction/ManiphestTaskTransactionType.php index 699ef11631..c59de163c6 100644 --- a/src/applications/maniphest/xaction/ManiphestTaskTransactionType.php +++ b/src/applications/maniphest/xaction/ManiphestTaskTransactionType.php @@ -3,14 +3,4 @@ abstract class ManiphestTaskTransactionType extends PhabricatorModularTransactionType { - public function renderSubtypeName($value) { - $object = $this->getObject(); - $map = $object->newEditEngineSubtypeMap(); - if (!isset($map[$value])) { - return $value; - } - - return $map[$value]->getName(); - } - } diff --git a/src/applications/project/view/ProjectBoardTaskCard.php b/src/applications/project/view/ProjectBoardTaskCard.php index 100fee20b3..1a6807ec45 100644 --- a/src/applications/project/view/ProjectBoardTaskCard.php +++ b/src/applications/project/view/ProjectBoardTaskCard.php @@ -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()) { $icon = ManiphestTaskStatus::getStatusIcon($task->getStatus()); $icon = id(new PHUIIconView()) diff --git a/src/applications/transactions/editengine/PhabricatorEditEngineSubtype.php b/src/applications/transactions/editengine/PhabricatorEditEngineSubtype.php index ff14ae239b..df367955af 100644 --- a/src/applications/transactions/editengine/PhabricatorEditEngineSubtype.php +++ b/src/applications/transactions/editengine/PhabricatorEditEngineSubtype.php @@ -8,6 +8,9 @@ final class PhabricatorEditEngineSubtype private $key; private $name; + private $icon; + private $tagText; + private $color; public function setKey($key) { $this->key = $key; @@ -27,8 +30,48 @@ final class PhabricatorEditEngineSubtype return $this->name; } + public function setIcon($icon) { + $this->icon = $icon; + return $this; + } + 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) { @@ -72,6 +115,9 @@ final class PhabricatorEditEngineSubtype array( 'key' => 'string', 'name' => 'string', + 'tag' => 'optional string', + 'color' => 'optional string', + 'icon' => 'optional string', )); $key = $value['key']; @@ -113,9 +159,27 @@ final class PhabricatorEditEngineSubtype $key = $entry['key']; $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) - ->setName($name); + ->setName($name) + ->setTagText($tag_text) + ->setIcon($icon); + + if ($color) { + $subtype->setColor($color); + } + + $map[$key] = $subtype; } return $map;