Page MenuHomePhabricator

D20040.diff
No OneTemporary

D20040.diff

diff --git a/resources/sql/autopatches/20190127.project.01.subtype.sql b/resources/sql/autopatches/20190127.project.01.subtype.sql
new file mode 100644
--- /dev/null
+++ b/resources/sql/autopatches/20190127.project.01.subtype.sql
@@ -0,0 +1,2 @@
+ALTER TABLE {$NAMESPACE}_project.project
+ ADD subtype VARCHAR(64) COLLATE {$COLLATE_TEXT} NOT NULL;
diff --git a/resources/sql/autopatches/20190127.project.02.default.sql b/resources/sql/autopatches/20190127.project.02.default.sql
new file mode 100644
--- /dev/null
+++ b/resources/sql/autopatches/20190127.project.02.default.sql
@@ -0,0 +1,2 @@
+UPDATE {$NAMESPACE}_project.project
+ SET subtype = 'default' WHERE subtype = '';
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
@@ -4114,6 +4114,8 @@
'PhabricatorProjectSubprojectWarningController' => 'applications/project/controller/PhabricatorProjectSubprojectWarningController.php',
'PhabricatorProjectSubprojectsController' => 'applications/project/controller/PhabricatorProjectSubprojectsController.php',
'PhabricatorProjectSubprojectsProfileMenuItem' => 'applications/project/menuitem/PhabricatorProjectSubprojectsProfileMenuItem.php',
+ 'PhabricatorProjectSubtypeDatasource' => 'applications/project/typeahead/PhabricatorProjectSubtypeDatasource.php',
+ 'PhabricatorProjectSubtypesConfigType' => 'applications/project/config/PhabricatorProjectSubtypesConfigType.php',
'PhabricatorProjectTestDataGenerator' => 'applications/project/lipsum/PhabricatorProjectTestDataGenerator.php',
'PhabricatorProjectTransaction' => 'applications/project/storage/PhabricatorProjectTransaction.php',
'PhabricatorProjectTransactionEditor' => 'applications/project/editor/PhabricatorProjectTransactionEditor.php',
@@ -10029,6 +10031,7 @@
'PhabricatorConduitResultInterface',
'PhabricatorColumnProxyInterface',
'PhabricatorSpacesInterface',
+ 'PhabricatorEditEngineSubtypeInterface',
),
'PhabricatorProjectAddHeraldAction' => 'PhabricatorProjectHeraldAction',
'PhabricatorProjectApplication' => 'PhabricatorApplication',
@@ -10156,6 +10159,8 @@
'PhabricatorProjectSubprojectWarningController' => 'PhabricatorProjectController',
'PhabricatorProjectSubprojectsController' => 'PhabricatorProjectController',
'PhabricatorProjectSubprojectsProfileMenuItem' => 'PhabricatorProfileMenuItem',
+ 'PhabricatorProjectSubtypeDatasource' => 'PhabricatorTypeaheadDatasource',
+ 'PhabricatorProjectSubtypesConfigType' => 'PhabricatorJSONConfigType',
'PhabricatorProjectTestDataGenerator' => 'PhabricatorTestDataGenerator',
'PhabricatorProjectTransaction' => 'PhabricatorModularTransaction',
'PhabricatorProjectTransactionEditor' => 'PhabricatorApplicationTransactionEditor',
diff --git a/src/applications/project/config/PhabricatorProjectConfigOptions.php b/src/applications/project/config/PhabricatorProjectConfigOptions.php
--- a/src/applications/project/config/PhabricatorProjectConfigOptions.php
+++ b/src/applications/project/config/PhabricatorProjectConfigOptions.php
@@ -83,6 +83,34 @@
$custom_field_type = 'custom:PhabricatorCustomFieldConfigOptionType';
+
+ $subtype_type = 'projects.subtypes';
+ $subtype_default_key = PhabricatorEditEngineSubtype::SUBTYPE_DEFAULT;
+ $subtype_example = array(
+ array(
+ 'key' => $subtype_default_key,
+ 'name' => pht('Project'),
+ ),
+ array(
+ 'key' => 'team',
+ 'name' => pht('Team'),
+ ),
+ );
+ $subtype_example = id(new PhutilJSON())->encodeAsList($subtype_example);
+
+ $subtype_default = array(
+ array(
+ 'key' => $subtype_default_key,
+ 'name' => pht('Project'),
+ ),
+ );
+
+ $subtype_description = $this->deformat(pht(<<<EOTEXT
+Allows you to define project subtypes. For a more detailed description of
+subtype configuration, see @{config:maniphest.subtypes}.
+EOTEXT
+ ));
+
return array(
$this->newOption('projects.custom-field-definitions', 'wild', array())
->setSummary(pht('Custom Projects fields.'))
@@ -102,6 +130,11 @@
$this->newOption('projects.colors', $colors_type, $default_colors)
->setSummary(pht('Adjust project colors.'))
->setDescription($colors_description),
+ $this->newOption('projects.subtypes', $subtype_type, $subtype_default)
+ ->setSummary(pht('Define project subtypes.'))
+ ->setDescription($subtype_description)
+ ->addExample($subtype_example, pht('Simple Subtypes')),
+
);
}
diff --git a/src/applications/project/config/PhabricatorProjectSubtypesConfigType.php b/src/applications/project/config/PhabricatorProjectSubtypesConfigType.php
new file mode 100644
--- /dev/null
+++ b/src/applications/project/config/PhabricatorProjectSubtypesConfigType.php
@@ -0,0 +1,14 @@
+<?php
+
+final class PhabricatorProjectSubtypesConfigType
+ extends PhabricatorJSONConfigType {
+
+ const TYPEKEY = 'projects.subtypes';
+
+ public function validateStoredValue(
+ PhabricatorConfigOption $option,
+ $value) {
+ PhabricatorEditEngineSubtype::validateConfiguration($value);
+ }
+
+}
diff --git a/src/applications/project/controller/PhabricatorProjectProfileController.php b/src/applications/project/controller/PhabricatorProjectProfileController.php
--- a/src/applications/project/controller/PhabricatorProjectProfileController.php
+++ b/src/applications/project/controller/PhabricatorProjectProfileController.php
@@ -51,6 +51,12 @@
$watch_action = $this->renderWatchAction($project);
$header->addActionLink($watch_action);
+ $subtype = $project->newSubtypeObject();
+ if ($subtype && $subtype->hasTagView()) {
+ $subtype_tag = $subtype->newTagView();
+ $header->addTag($subtype_tag);
+ }
+
$milestone_list = $this->buildMilestoneList($project);
$subproject_list = $this->buildSubprojectList($project);
diff --git a/src/applications/project/query/PhabricatorProjectQuery.php b/src/applications/project/query/PhabricatorProjectQuery.php
--- a/src/applications/project/query/PhabricatorProjectQuery.php
+++ b/src/applications/project/query/PhabricatorProjectQuery.php
@@ -24,6 +24,7 @@
private $maxDepth;
private $minMilestoneNumber;
private $maxMilestoneNumber;
+ private $subtypes;
private $status = 'status-any';
const STATUS_ANY = 'status-any';
@@ -131,6 +132,11 @@
return $this;
}
+ public function withSubtypes(array $subtypes) {
+ $this->subtypes = $subtypes;
+ return $this;
+ }
+
public function needMembers($need_members) {
$this->needMembers = $need_members;
return $this;
@@ -618,6 +624,13 @@
$this->maxMilestoneNumber);
}
+ if ($this->subtypes !== null) {
+ $where[] = qsprintf(
+ $conn,
+ 'subtype IN (%Ls)',
+ $this->subtypes);
+ }
+
return $where;
}
diff --git a/src/applications/project/query/PhabricatorProjectSearchEngine.php b/src/applications/project/query/PhabricatorProjectSearchEngine.php
--- a/src/applications/project/query/PhabricatorProjectSearchEngine.php
+++ b/src/applications/project/query/PhabricatorProjectSearchEngine.php
@@ -19,6 +19,9 @@
}
protected function buildCustomSearchFields() {
+ $subtype_map = id(new PhabricatorProject())->newEditEngineSubtypeMap();
+ $hide_subtypes = ($subtype_map->getCount() == 1);
+
return array(
id(new PhabricatorSearchTextField())
->setLabel(pht('Name'))
@@ -62,6 +65,14 @@
pht(
'Pass true to find only milestones, or false to omit '.
'milestones.')),
+ id(new PhabricatorSearchDatasourceField())
+ ->setLabel(pht('Subtypes'))
+ ->setKey('subtypes')
+ ->setAliases(array('subtype'))
+ ->setDescription(
+ pht('Search for projects with given subtypes.'))
+ ->setDatasource(new PhabricatorProjectSubtypeDatasource())
+ ->setIsHidden($hide_subtypes),
id(new PhabricatorSearchCheckboxesField())
->setLabel(pht('Icons'))
->setKey('icons')
@@ -134,6 +145,10 @@
$query->withAncestorProjectPHIDs($map['ancestorPHIDs']);
}
+ if ($map['subtypes']) {
+ $query->withSubtypes($map['subtypes']);
+ }
+
return $query;
}
diff --git a/src/applications/project/storage/PhabricatorProject.php b/src/applications/project/storage/PhabricatorProject.php
--- a/src/applications/project/storage/PhabricatorProject.php
+++ b/src/applications/project/storage/PhabricatorProject.php
@@ -12,7 +12,8 @@
PhabricatorFerretInterface,
PhabricatorConduitResultInterface,
PhabricatorColumnProxyInterface,
- PhabricatorSpacesInterface {
+ PhabricatorSpacesInterface,
+ PhabricatorEditEngineSubtypeInterface {
protected $name;
protected $status = PhabricatorProjectStatus::STATUS_ACTIVE;
@@ -40,6 +41,7 @@
protected $properties = array();
protected $spacePHID;
+ protected $subtype;
private $memberPHIDs = self::ATTACHABLE;
private $watcherPHIDs = self::ATTACHABLE;
@@ -102,6 +104,7 @@
->setHasWorkboard(0)
->setHasMilestones(0)
->setHasSubprojects(0)
+ ->setSubtype(PhabricatorEditEngineSubtype::SUBTYPE_DEFAULT)
->attachParentProject(null);
}
@@ -237,6 +240,7 @@
'projectPath' => 'hashpath64',
'projectDepth' => 'uint32',
'projectPathKey' => 'bytes4',
+ 'subtype' => 'text64',
),
self::CONFIG_KEY_SCHEMA => array(
'key_icon' => array(
@@ -765,6 +769,10 @@
->setKey('slug')
->setType('string')
->setDescription(pht('Primary slug/hashtag.')),
+ id(new PhabricatorConduitSearchFieldSpecification())
+ ->setKey('subtype')
+ ->setType('string')
+ ->setDescription(pht('Subtype of the project.')),
id(new PhabricatorConduitSearchFieldSpecification())
->setKey('milestone')
->setType('int?')
@@ -814,6 +822,7 @@
return array(
'name' => $this->getName(),
'slug' => $this->getPrimarySlug(),
+ 'subtype' => $this->getSubtype(),
'milestone' => $milestone,
'depth' => (int)$this->getProjectDepth(),
'parent' => $parent_ref,
@@ -873,4 +882,26 @@
}
+/* -( PhabricatorEditEngineSubtypeInterface )------------------------------ */
+
+
+ public function getEditEngineSubtype() {
+ return $this->getSubtype();
+ }
+
+ public function setEditEngineSubtype($value) {
+ return $this->setSubtype($value);
+ }
+
+ public function newEditEngineSubtypeMap() {
+ $config = PhabricatorEnv::getEnvConfig('projects.subtypes');
+ return PhabricatorEditEngineSubtype::newSubtypeMap($config);
+ }
+
+ public function newSubtypeObject() {
+ $subtype_key = $this->getEditEngineSubtype();
+ $subtype_map = $this->newEditEngineSubtypeMap();
+ return $subtype_map->getSubtype($subtype_key);
+ }
+
}
diff --git a/src/applications/project/typeahead/PhabricatorProjectSubtypeDatasource.php b/src/applications/project/typeahead/PhabricatorProjectSubtypeDatasource.php
new file mode 100644
--- /dev/null
+++ b/src/applications/project/typeahead/PhabricatorProjectSubtypeDatasource.php
@@ -0,0 +1,45 @@
+<?php
+
+final class PhabricatorProjectSubtypeDatasource
+ extends PhabricatorTypeaheadDatasource {
+
+ public function getBrowseTitle() {
+ return pht('Browse Subtypes');
+ }
+
+ public function getPlaceholderText() {
+ return pht('Type a project subtype name...');
+ }
+
+ public function getDatasourceApplicationClass() {
+ return 'PhabricatorProjectApplication';
+ }
+
+ public function loadResults() {
+ $results = $this->buildResults();
+ return $this->filterResultsAgainstTokens($results);
+ }
+
+ protected function renderSpecialTokens(array $values) {
+ return $this->renderTokensFromResults($this->buildResults(), $values);
+ }
+
+ private function buildResults() {
+ $results = array();
+
+ $subtype_map = id(new PhabricatorProject())->newEditEngineSubtypeMap();
+ foreach ($subtype_map->getSubtypes() as $key => $subtype) {
+
+ $result = id(new PhabricatorTypeaheadResult())
+ ->setIcon($subtype->getIcon())
+ ->setColor($subtype->getColor())
+ ->setPHID($key)
+ ->setName($subtype->getName());
+
+ $results[$key] = $result;
+ }
+
+ return $results;
+ }
+
+}
diff --git a/src/applications/project/view/PhabricatorProjectListView.php b/src/applications/project/view/PhabricatorProjectListView.php
--- a/src/applications/project/view/PhabricatorProjectListView.php
+++ b/src/applications/project/view/PhabricatorProjectListView.php
@@ -87,6 +87,13 @@
}
}
+ $subtype = $project->newSubtypeObject();
+ if ($subtype && $subtype->hasTagView()) {
+ $subtype_tag = $subtype->newTagView()
+ ->setSlimShady(true);
+ $item->addAttribute($subtype_tag);
+ }
+
$list->addItem($item);
}

File Metadata

Mime Type
text/plain
Expires
Tue, Feb 11, 8:56 PM (10 h, 58 m)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
7123213
Default Alt Text
D20040.diff (12 KB)

Event Timeline