From 635e9c6075273fd3479a8903f8082db1b0bd72b7 Mon Sep 17 00:00:00 2001 From: epriestley Date: Mon, 21 Sep 2015 04:41:52 -0700 Subject: [PATCH] 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 --- src/__phutil_library_map__.php | 6 ++- .../typeahead/AlmanacServiceDatasource.php | 10 ++++ .../user/configuration/custom_fields.diviner | 3 ++ ...abricatorStandardCustomFieldDatasource.php | 28 +++++++++++ ...habricatorStandardCustomFieldTokenizer.php | 47 +++++++++++++++++++ .../PhabricatorStandardCustomFieldUsers.php | 41 ++-------------- 6 files changed, 96 insertions(+), 39 deletions(-) create mode 100644 src/infrastructure/customfield/standard/PhabricatorStandardCustomFieldDatasource.php create mode 100644 src/infrastructure/customfield/standard/PhabricatorStandardCustomFieldTokenizer.php diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index cd5c6c5b65..15395094dd 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -2915,6 +2915,7 @@ phutil_register_library_map(array( 'PhabricatorStandardCustomField' => 'infrastructure/customfield/standard/PhabricatorStandardCustomField.php', 'PhabricatorStandardCustomFieldBool' => 'infrastructure/customfield/standard/PhabricatorStandardCustomFieldBool.php', 'PhabricatorStandardCustomFieldCredential' => 'infrastructure/customfield/standard/PhabricatorStandardCustomFieldCredential.php', + 'PhabricatorStandardCustomFieldDatasource' => 'infrastructure/customfield/standard/PhabricatorStandardCustomFieldDatasource.php', 'PhabricatorStandardCustomFieldDate' => 'infrastructure/customfield/standard/PhabricatorStandardCustomFieldDate.php', 'PhabricatorStandardCustomFieldHeader' => 'infrastructure/customfield/standard/PhabricatorStandardCustomFieldHeader.php', 'PhabricatorStandardCustomFieldInt' => 'infrastructure/customfield/standard/PhabricatorStandardCustomFieldInt.php', @@ -2924,6 +2925,7 @@ phutil_register_library_map(array( 'PhabricatorStandardCustomFieldRemarkup' => 'infrastructure/customfield/standard/PhabricatorStandardCustomFieldRemarkup.php', 'PhabricatorStandardCustomFieldSelect' => 'infrastructure/customfield/standard/PhabricatorStandardCustomFieldSelect.php', 'PhabricatorStandardCustomFieldText' => 'infrastructure/customfield/standard/PhabricatorStandardCustomFieldText.php', + 'PhabricatorStandardCustomFieldTokenizer' => 'infrastructure/customfield/standard/PhabricatorStandardCustomFieldTokenizer.php', 'PhabricatorStandardCustomFieldUsers' => 'infrastructure/customfield/standard/PhabricatorStandardCustomFieldUsers.php', 'PhabricatorStandardPageView' => 'view/page/PhabricatorStandardPageView.php', 'PhabricatorStandardSelectCustomFieldDatasource' => 'infrastructure/customfield/datasource/PhabricatorStandardSelectCustomFieldDatasource.php', @@ -7022,6 +7024,7 @@ phutil_register_library_map(array( 'PhabricatorStandardCustomField' => 'PhabricatorCustomField', 'PhabricatorStandardCustomFieldBool' => 'PhabricatorStandardCustomField', 'PhabricatorStandardCustomFieldCredential' => 'PhabricatorStandardCustomField', + 'PhabricatorStandardCustomFieldDatasource' => 'PhabricatorStandardCustomFieldTokenizer', 'PhabricatorStandardCustomFieldDate' => 'PhabricatorStandardCustomField', 'PhabricatorStandardCustomFieldHeader' => 'PhabricatorStandardCustomField', 'PhabricatorStandardCustomFieldInt' => 'PhabricatorStandardCustomField', @@ -7030,7 +7033,8 @@ phutil_register_library_map(array( 'PhabricatorStandardCustomFieldRemarkup' => 'PhabricatorStandardCustomField', 'PhabricatorStandardCustomFieldSelect' => 'PhabricatorStandardCustomField', 'PhabricatorStandardCustomFieldText' => 'PhabricatorStandardCustomField', - 'PhabricatorStandardCustomFieldUsers' => 'PhabricatorStandardCustomFieldPHIDs', + 'PhabricatorStandardCustomFieldTokenizer' => 'PhabricatorStandardCustomFieldPHIDs', + 'PhabricatorStandardCustomFieldUsers' => 'PhabricatorStandardCustomFieldTokenizer', 'PhabricatorStandardPageView' => 'PhabricatorBarePageView', 'PhabricatorStandardSelectCustomFieldDatasource' => 'PhabricatorTypeaheadDatasource', 'PhabricatorStatusController' => 'PhabricatorController', diff --git a/src/applications/almanac/typeahead/AlmanacServiceDatasource.php b/src/applications/almanac/typeahead/AlmanacServiceDatasource.php index e5728e1c26..621b0408ae 100644 --- a/src/applications/almanac/typeahead/AlmanacServiceDatasource.php +++ b/src/applications/almanac/typeahead/AlmanacServiceDatasource.php @@ -23,6 +23,16 @@ final class AlmanacServiceDatasource ->withNamePrefix($raw_query) ->setOrder('name'); + // TODO: When service classes are restricted, it might be nice to customize + // the title and placeholder text to show which service types can be + // selected, or show all services but mark the invalid ones disabled and + // prevent their selection. + + $service_classes = $this->getParameter('serviceClasses'); + if ($service_classes) { + $services->withServiceClasses($service_classes); + } + $services = $this->executeQuery($services); if ($services) { diff --git a/src/docs/user/configuration/custom_fields.diviner b/src/docs/user/configuration/custom_fields.diviner index 6643a0518f..9ada0efa06 100644 --- a/src/docs/user/configuration/custom_fields.diviner +++ b/src/docs/user/configuration/custom_fields.diviner @@ -144,6 +144,9 @@ change, but are documented here for completeness: - **Credentials**: Controls with type `credential` allow selection of a Passphrase credential which provides `credential.provides`, and creation of credentials of `credential.type`. + - **Datasource**: Controls with type `datasource` allow selection of tokens + from an arbitrary datasource, controlled with `datasource.class` and + `datasource.parameters`. = Advanced Custom Fields = diff --git a/src/infrastructure/customfield/standard/PhabricatorStandardCustomFieldDatasource.php b/src/infrastructure/customfield/standard/PhabricatorStandardCustomFieldDatasource.php new file mode 100644 index 0000000000..49b9ab2cb5 --- /dev/null +++ b/src/infrastructure/customfield/standard/PhabricatorStandardCustomFieldDatasource.php @@ -0,0 +1,28 @@ +getFieldConfigValue('datasource.parameters', array()); + + $class = $this->getFieldConfigValue('datasource.class'); + $parent = 'PhabricatorTypeaheadDatasource'; + if (!is_subclass_of($class, $parent)) { + throw new Exception( + pht( + 'Configured datasource class "%s" must be a valid subclass of '. + '"%s".', + $class, + $parent)); + } + + return newv($class, array()) + ->setParameters($parameters); + } + +} diff --git a/src/infrastructure/customfield/standard/PhabricatorStandardCustomFieldTokenizer.php b/src/infrastructure/customfield/standard/PhabricatorStandardCustomFieldTokenizer.php new file mode 100644 index 0000000000..f6a542ec7f --- /dev/null +++ b/src/infrastructure/customfield/standard/PhabricatorStandardCustomFieldTokenizer.php @@ -0,0 +1,47 @@ +getFieldValue(); + + $control = id(new AphrontFormTokenizerControl()) + ->setUser($this->getViewer()) + ->setLabel($this->getFieldName()) + ->setName($this->getFieldKey()) + ->setDatasource($this->getDatasource()) + ->setCaption($this->getCaption()) + ->setValue(nonempty($value, array())); + + $limit = $this->getFieldConfigValue('limit'); + if ($limit) { + $control->setLimit($limit); + } + + return $control; + } + + public function appendToApplicationSearchForm( + PhabricatorApplicationSearchEngine $engine, + AphrontFormView $form, + $value) { + + $control = id(new AphrontFormTokenizerControl()) + ->setLabel($this->getFieldName()) + ->setName($this->getFieldKey()) + ->setDatasource($this->getDatasource()) + ->setValue(nonempty($value, array())); + + $form->appendControl($control); + } + + public function getHeraldFieldValueType($condition) { + return id(new HeraldTokenizerFieldValue()) + ->setKey('custom.'.$this->getFieldKey()) + ->setDatasource($this->getDatasource()); + } + +} diff --git a/src/infrastructure/customfield/standard/PhabricatorStandardCustomFieldUsers.php b/src/infrastructure/customfield/standard/PhabricatorStandardCustomFieldUsers.php index 7efe873a1d..2f1e6db53a 100644 --- a/src/infrastructure/customfield/standard/PhabricatorStandardCustomFieldUsers.php +++ b/src/infrastructure/customfield/standard/PhabricatorStandardCustomFieldUsers.php @@ -1,49 +1,14 @@ getFieldValue(); - - $control = id(new AphrontFormTokenizerControl()) - ->setUser($this->getViewer()) - ->setLabel($this->getFieldName()) - ->setName($this->getFieldKey()) - ->setDatasource(new PhabricatorPeopleDatasource()) - ->setCaption($this->getCaption()) - ->setValue(nonempty($value, array())); - - $limit = $this->getFieldConfigValue('limit'); - if ($limit) { - $control->setLimit($limit); - } - - return $control; - } - - public function appendToApplicationSearchForm( - PhabricatorApplicationSearchEngine $engine, - AphrontFormView $form, - $value) { - - $control = id(new AphrontFormTokenizerControl()) - ->setLabel($this->getFieldName()) - ->setName($this->getFieldKey()) - ->setDatasource(new PhabricatorPeopleDatasource()) - ->setValue(nonempty($value, array())); - - $form->appendControl($control); - } - - public function getHeraldFieldValueType($condition) { - return id(new HeraldTokenizerFieldValue()) - ->setKey('custom.'.$this->getFieldKey()) - ->setDatasource(new PhabricatorPeopleDatasource()); + public function getDatasource() { + return new PhabricatorPeopleDatasource(); } }