@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Provide a generic "Datasource" StandardCustomField

Summary:
Ref T9253. See discussion in D13843.

I want to let Drydock blueprints for Almanac services choose those services from a typeahead, but only list appropriate services in the typeahead. To do this:

- Provide a StandardCustomField for an arbitrary datasource.
- Adjust the AlmanacServiceDatasource to allow filtering by service class.

This implementation is substantially the same as the one in D13843, with some adjustments:

- I lifted most of the code in the `Users` standard custom field into a new `Tokenizer` standard custom field.
- The `Users` and `Datasource` custom fields now extend the `Tokenizer` custom field and can share most of the code it uses.
- I exposed this field fully as a configurable field. I don't think anyone will ever use it, but this generality costs us nearly nothing and improves consistency.
- The code in D13843 didn't actually pass the parameters over the wire, since the object that responds to the request is not the same object that renders the field. Use the "parameters" mechanism in datasources to get things passed over the wire.

Test Plan:
- Created a custom "users" field in Maniphest and made sure it still wokred.
- Created a custom "almanc services" field in Maniphest and selected some services for a task.
- With additional changes from D13843, selected an appropriate Almanac service in a new Drydock blueprint.

Reviewers: hach-que, chad

Reviewed By: hach-que, chad

Maniphest Tasks: T9253

Differential Revision: https://secure.phabricator.com/D14111

+96 -39
+5 -1
src/__phutil_library_map__.php
··· 2915 2915 'PhabricatorStandardCustomField' => 'infrastructure/customfield/standard/PhabricatorStandardCustomField.php', 2916 2916 'PhabricatorStandardCustomFieldBool' => 'infrastructure/customfield/standard/PhabricatorStandardCustomFieldBool.php', 2917 2917 'PhabricatorStandardCustomFieldCredential' => 'infrastructure/customfield/standard/PhabricatorStandardCustomFieldCredential.php', 2918 + 'PhabricatorStandardCustomFieldDatasource' => 'infrastructure/customfield/standard/PhabricatorStandardCustomFieldDatasource.php', 2918 2919 'PhabricatorStandardCustomFieldDate' => 'infrastructure/customfield/standard/PhabricatorStandardCustomFieldDate.php', 2919 2920 'PhabricatorStandardCustomFieldHeader' => 'infrastructure/customfield/standard/PhabricatorStandardCustomFieldHeader.php', 2920 2921 'PhabricatorStandardCustomFieldInt' => 'infrastructure/customfield/standard/PhabricatorStandardCustomFieldInt.php', ··· 2924 2925 'PhabricatorStandardCustomFieldRemarkup' => 'infrastructure/customfield/standard/PhabricatorStandardCustomFieldRemarkup.php', 2925 2926 'PhabricatorStandardCustomFieldSelect' => 'infrastructure/customfield/standard/PhabricatorStandardCustomFieldSelect.php', 2926 2927 'PhabricatorStandardCustomFieldText' => 'infrastructure/customfield/standard/PhabricatorStandardCustomFieldText.php', 2928 + 'PhabricatorStandardCustomFieldTokenizer' => 'infrastructure/customfield/standard/PhabricatorStandardCustomFieldTokenizer.php', 2927 2929 'PhabricatorStandardCustomFieldUsers' => 'infrastructure/customfield/standard/PhabricatorStandardCustomFieldUsers.php', 2928 2930 'PhabricatorStandardPageView' => 'view/page/PhabricatorStandardPageView.php', 2929 2931 'PhabricatorStandardSelectCustomFieldDatasource' => 'infrastructure/customfield/datasource/PhabricatorStandardSelectCustomFieldDatasource.php', ··· 7022 7024 'PhabricatorStandardCustomField' => 'PhabricatorCustomField', 7023 7025 'PhabricatorStandardCustomFieldBool' => 'PhabricatorStandardCustomField', 7024 7026 'PhabricatorStandardCustomFieldCredential' => 'PhabricatorStandardCustomField', 7027 + 'PhabricatorStandardCustomFieldDatasource' => 'PhabricatorStandardCustomFieldTokenizer', 7025 7028 'PhabricatorStandardCustomFieldDate' => 'PhabricatorStandardCustomField', 7026 7029 'PhabricatorStandardCustomFieldHeader' => 'PhabricatorStandardCustomField', 7027 7030 'PhabricatorStandardCustomFieldInt' => 'PhabricatorStandardCustomField', ··· 7030 7033 'PhabricatorStandardCustomFieldRemarkup' => 'PhabricatorStandardCustomField', 7031 7034 'PhabricatorStandardCustomFieldSelect' => 'PhabricatorStandardCustomField', 7032 7035 'PhabricatorStandardCustomFieldText' => 'PhabricatorStandardCustomField', 7033 - 'PhabricatorStandardCustomFieldUsers' => 'PhabricatorStandardCustomFieldPHIDs', 7036 + 'PhabricatorStandardCustomFieldTokenizer' => 'PhabricatorStandardCustomFieldPHIDs', 7037 + 'PhabricatorStandardCustomFieldUsers' => 'PhabricatorStandardCustomFieldTokenizer', 7034 7038 'PhabricatorStandardPageView' => 'PhabricatorBarePageView', 7035 7039 'PhabricatorStandardSelectCustomFieldDatasource' => 'PhabricatorTypeaheadDatasource', 7036 7040 'PhabricatorStatusController' => 'PhabricatorController',
+10
src/applications/almanac/typeahead/AlmanacServiceDatasource.php
··· 23 23 ->withNamePrefix($raw_query) 24 24 ->setOrder('name'); 25 25 26 + // TODO: When service classes are restricted, it might be nice to customize 27 + // the title and placeholder text to show which service types can be 28 + // selected, or show all services but mark the invalid ones disabled and 29 + // prevent their selection. 30 + 31 + $service_classes = $this->getParameter('serviceClasses'); 32 + if ($service_classes) { 33 + $services->withServiceClasses($service_classes); 34 + } 35 + 26 36 $services = $this->executeQuery($services); 27 37 28 38 if ($services) {
+3
src/docs/user/configuration/custom_fields.diviner
··· 144 144 - **Credentials**: Controls with type `credential` allow selection of a 145 145 Passphrase credential which provides `credential.provides`, and creation 146 146 of credentials of `credential.type`. 147 + - **Datasource**: Controls with type `datasource` allow selection of tokens 148 + from an arbitrary datasource, controlled with `datasource.class` and 149 + `datasource.parameters`. 147 150 148 151 = Advanced Custom Fields = 149 152
+28
src/infrastructure/customfield/standard/PhabricatorStandardCustomFieldDatasource.php
··· 1 + <?php 2 + 3 + final class PhabricatorStandardCustomFieldDatasource 4 + extends PhabricatorStandardCustomFieldTokenizer { 5 + 6 + public function getFieldType() { 7 + return 'datasource'; 8 + } 9 + 10 + public function getDatasource() { 11 + $parameters = $this->getFieldConfigValue('datasource.parameters', array()); 12 + 13 + $class = $this->getFieldConfigValue('datasource.class'); 14 + $parent = 'PhabricatorTypeaheadDatasource'; 15 + if (!is_subclass_of($class, $parent)) { 16 + throw new Exception( 17 + pht( 18 + 'Configured datasource class "%s" must be a valid subclass of '. 19 + '"%s".', 20 + $class, 21 + $parent)); 22 + } 23 + 24 + return newv($class, array()) 25 + ->setParameters($parameters); 26 + } 27 + 28 + }
+47
src/infrastructure/customfield/standard/PhabricatorStandardCustomFieldTokenizer.php
··· 1 + <?php 2 + 3 + abstract class PhabricatorStandardCustomFieldTokenizer 4 + extends PhabricatorStandardCustomFieldPHIDs { 5 + 6 + abstract public function getDatasource(); 7 + 8 + public function renderEditControl(array $handles) { 9 + $value = $this->getFieldValue(); 10 + 11 + $control = id(new AphrontFormTokenizerControl()) 12 + ->setUser($this->getViewer()) 13 + ->setLabel($this->getFieldName()) 14 + ->setName($this->getFieldKey()) 15 + ->setDatasource($this->getDatasource()) 16 + ->setCaption($this->getCaption()) 17 + ->setValue(nonempty($value, array())); 18 + 19 + $limit = $this->getFieldConfigValue('limit'); 20 + if ($limit) { 21 + $control->setLimit($limit); 22 + } 23 + 24 + return $control; 25 + } 26 + 27 + public function appendToApplicationSearchForm( 28 + PhabricatorApplicationSearchEngine $engine, 29 + AphrontFormView $form, 30 + $value) { 31 + 32 + $control = id(new AphrontFormTokenizerControl()) 33 + ->setLabel($this->getFieldName()) 34 + ->setName($this->getFieldKey()) 35 + ->setDatasource($this->getDatasource()) 36 + ->setValue(nonempty($value, array())); 37 + 38 + $form->appendControl($control); 39 + } 40 + 41 + public function getHeraldFieldValueType($condition) { 42 + return id(new HeraldTokenizerFieldValue()) 43 + ->setKey('custom.'.$this->getFieldKey()) 44 + ->setDatasource($this->getDatasource()); 45 + } 46 + 47 + }
+3 -38
src/infrastructure/customfield/standard/PhabricatorStandardCustomFieldUsers.php
··· 1 1 <?php 2 2 3 3 final class PhabricatorStandardCustomFieldUsers 4 - extends PhabricatorStandardCustomFieldPHIDs { 4 + extends PhabricatorStandardCustomFieldTokenizer { 5 5 6 6 public function getFieldType() { 7 7 return 'users'; 8 8 } 9 9 10 - public function renderEditControl(array $handles) { 11 - $value = $this->getFieldValue(); 12 - 13 - $control = id(new AphrontFormTokenizerControl()) 14 - ->setUser($this->getViewer()) 15 - ->setLabel($this->getFieldName()) 16 - ->setName($this->getFieldKey()) 17 - ->setDatasource(new PhabricatorPeopleDatasource()) 18 - ->setCaption($this->getCaption()) 19 - ->setValue(nonempty($value, array())); 20 - 21 - $limit = $this->getFieldConfigValue('limit'); 22 - if ($limit) { 23 - $control->setLimit($limit); 24 - } 25 - 26 - return $control; 27 - } 28 - 29 - public function appendToApplicationSearchForm( 30 - PhabricatorApplicationSearchEngine $engine, 31 - AphrontFormView $form, 32 - $value) { 33 - 34 - $control = id(new AphrontFormTokenizerControl()) 35 - ->setLabel($this->getFieldName()) 36 - ->setName($this->getFieldKey()) 37 - ->setDatasource(new PhabricatorPeopleDatasource()) 38 - ->setValue(nonempty($value, array())); 39 - 40 - $form->appendControl($control); 41 - } 42 - 43 - public function getHeraldFieldValueType($condition) { 44 - return id(new HeraldTokenizerFieldValue()) 45 - ->setKey('custom.'.$this->getFieldKey()) 46 - ->setDatasource(new PhabricatorPeopleDatasource()); 10 + public function getDatasource() { 11 + return new PhabricatorPeopleDatasource(); 47 12 } 48 13 49 14 }