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

Begin modularizing Herald field values

Summary:
Ref T8726. I'm primarily trying to modularize tokenizer values so we don't have to update JS to add a new one.

This is ultimately the blocker for "select" custom fields working in Herald.

This inches us toward that. I'm //not// modularizing conditions or control types in this round, but hope to end up with hard-coded conditions (which are highly general and very rarely change), hard-coded control types (which are also highly general and very rarely change) and completely modular fields and values (which have mid-to-low generality and change frequently).

Test Plan: Used UI to interact with "none", "text", and new-style "select" controls. No actual support for tokenizers yet.

Reviewers: btrahan

Reviewed By: btrahan

Subscribers: epriestley

Maniphest Tasks: T8726

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

+204 -33
+11 -11
resources/celerity/map.php
··· 382 382 'rsrc/js/application/doorkeeper/behavior-doorkeeper-tag.js' => 'e5822781', 383 383 'rsrc/js/application/files/behavior-icon-composer.js' => '8ef9ab58', 384 384 'rsrc/js/application/files/behavior-launch-icon-composer.js' => '48086888', 385 - 'rsrc/js/application/herald/HeraldRuleEditor.js' => 'b2cae298', 385 + 'rsrc/js/application/herald/HeraldRuleEditor.js' => '0f85bdfd', 386 386 'rsrc/js/application/herald/PathTypeahead.js' => 'f7fc67ec', 387 387 'rsrc/js/application/herald/herald-rule-editor.js' => '7ebaeed3', 388 388 'rsrc/js/application/maniphest/behavior-batch-editor.js' => '782ab6e7', ··· 538 538 'global-drag-and-drop-css' => '697324ad', 539 539 'harbormaster-css' => '49d64eb4', 540 540 'herald-css' => '826075fa', 541 - 'herald-rule-editor' => 'b2cae298', 541 + 'herald-rule-editor' => '0f85bdfd', 542 542 'herald-test-css' => '778b008e', 543 543 'inline-comment-summary-css' => '51efda3a', 544 544 'javelin-aphlict' => '5359e785', ··· 917 917 '0f764c35' => array( 918 918 'javelin-install', 919 919 'javelin-util', 920 + ), 921 + '0f85bdfd' => array( 922 + 'multirow-row-manager', 923 + 'javelin-install', 924 + 'javelin-util', 925 + 'javelin-dom', 926 + 'javelin-stratcom', 927 + 'javelin-json', 928 + 'phabricator-prefab', 920 929 ), 921 930 '13c739ea' => array( 922 931 'javelin-behavior', ··· 1675 1684 'javelin-dom', 1676 1685 'javelin-uri', 1677 1686 'javelin-request', 1678 - ), 1679 - 'b2cae298' => array( 1680 - 'multirow-row-manager', 1681 - 'javelin-install', 1682 - 'javelin-util', 1683 - 'javelin-dom', 1684 - 'javelin-stratcom', 1685 - 'javelin-json', 1686 - 'phabricator-prefab', 1687 1687 ), 1688 1688 'b3a4b884' => array( 1689 1689 'javelin-behavior',
+8
src/__phutil_library_map__.php
··· 1018 1018 'HeraldDifferentialRevisionAdapter' => 'applications/differential/herald/HeraldDifferentialRevisionAdapter.php', 1019 1019 'HeraldDisableController' => 'applications/herald/controller/HeraldDisableController.php', 1020 1020 'HeraldEffect' => 'applications/herald/engine/HeraldEffect.php', 1021 + 'HeraldEmptyFieldValue' => 'applications/herald/value/HeraldEmptyFieldValue.php', 1021 1022 'HeraldEngine' => 'applications/herald/engine/HeraldEngine.php', 1022 1023 'HeraldField' => 'applications/herald/field/HeraldField.php', 1023 1024 'HeraldFieldTestCase' => 'applications/herald/field/__tests__/HeraldFieldTestCase.php', 1025 + 'HeraldFieldValue' => 'applications/herald/value/HeraldFieldValue.php', 1024 1026 'HeraldInvalidActionException' => 'applications/herald/engine/exception/HeraldInvalidActionException.php', 1025 1027 'HeraldInvalidConditionException' => 'applications/herald/engine/exception/HeraldInvalidConditionException.php', 1026 1028 'HeraldManageGlobalRulesCapability' => 'applications/herald/capability/HeraldManageGlobalRulesCapability.php', ··· 1050 1052 'HeraldRuleTypeConfig' => 'applications/herald/config/HeraldRuleTypeConfig.php', 1051 1053 'HeraldRuleViewController' => 'applications/herald/controller/HeraldRuleViewController.php', 1052 1054 'HeraldSchemaSpec' => 'applications/herald/storage/HeraldSchemaSpec.php', 1055 + 'HeraldSelectFieldValue' => 'applications/herald/value/HeraldSelectFieldValue.php', 1053 1056 'HeraldSpaceField' => 'applications/spaces/herald/HeraldSpaceField.php', 1054 1057 'HeraldSubscribersField' => 'applications/subscriptions/herald/HeraldSubscribersField.php', 1055 1058 'HeraldTestConsoleController' => 'applications/herald/controller/HeraldTestConsoleController.php', 1059 + 'HeraldTextFieldValue' => 'applications/herald/value/HeraldTextFieldValue.php', 1056 1060 'HeraldTransactionQuery' => 'applications/herald/query/HeraldTransactionQuery.php', 1057 1061 'HeraldTranscript' => 'applications/herald/storage/transcript/HeraldTranscript.php', 1058 1062 'HeraldTranscriptController' => 'applications/herald/controller/HeraldTranscriptController.php', ··· 4615 4619 'HeraldDifferentialRevisionAdapter' => 'HeraldDifferentialAdapter', 4616 4620 'HeraldDisableController' => 'HeraldController', 4617 4621 'HeraldEffect' => 'Phobject', 4622 + 'HeraldEmptyFieldValue' => 'HeraldFieldValue', 4618 4623 'HeraldEngine' => 'Phobject', 4619 4624 'HeraldField' => 'Phobject', 4620 4625 'HeraldFieldTestCase' => 'PhutilTestCase', 4626 + 'HeraldFieldValue' => 'Phobject', 4621 4627 'HeraldInvalidActionException' => 'Exception', 4622 4628 'HeraldInvalidConditionException' => 'Exception', 4623 4629 'HeraldManageGlobalRulesCapability' => 'PhabricatorPolicyCapability', ··· 4653 4659 'HeraldRuleTypeConfig' => 'Phobject', 4654 4660 'HeraldRuleViewController' => 'HeraldController', 4655 4661 'HeraldSchemaSpec' => 'PhabricatorConfigSchemaSpec', 4662 + 'HeraldSelectFieldValue' => 'HeraldFieldValue', 4656 4663 'HeraldSpaceField' => 'HeraldField', 4657 4664 'HeraldSubscribersField' => 'HeraldField', 4658 4665 'HeraldTestConsoleController' => 'HeraldController', 4666 + 'HeraldTextFieldValue' => 'HeraldFieldValue', 4659 4667 'HeraldTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 4660 4668 'HeraldTranscript' => array( 4661 4669 'HeraldDAO',
+10 -10
src/applications/herald/controller/HeraldRuleController.php
··· 440 440 $config_info['fields'] = $field_map; 441 441 $config_info['conditions'] = $all_conditions; 442 442 $config_info['actions'] = $action_map; 443 + $config_info['valueMap'] = array(); 443 444 444 445 foreach ($config_info['fields'] as $field => $name) { 445 446 try { ··· 452 453 453 454 foreach ($config_info['fields'] as $field => $fname) { 454 455 foreach ($config_info['conditionMap'][$field] as $condition) { 455 - $value_type = $adapter->getValueTypeForFieldAndCondition( 456 + $value_key = $adapter->getValueTypeForFieldAndCondition( 456 457 $field, 457 458 $condition); 458 - $config_info['values'][$field][$condition] = $value_type; 459 + 460 + if ($value_key instanceof HeraldFieldValue) { 461 + $spec = $value_key->getControlSpecificationDictionary(); 462 + $value_key = $value_key->getFieldValueKey(); 463 + $config_info['valueMap'][$value_key] = $spec; 464 + } 465 + 466 + $config_info['values'][$field][$condition] = $value_key; 459 467 } 460 468 } 461 469 ··· 482 490 'conditions' => (object)$serial_conditions, 483 491 'actions' => (object)$serial_actions, 484 492 'select' => array( 485 - HeraldAdapter::VALUE_CONTENT_SOURCE => array( 486 - 'options' => PhabricatorContentSource::getSourceNameMap(), 487 - 'default' => PhabricatorContentSource::SOURCE_WEB, 488 - ), 489 493 HeraldAdapter::VALUE_FLAG_COLOR => array( 490 494 'options' => PhabricatorFlagColor::getColorNameMap(), 491 495 'default' => PhabricatorFlagColor::COLOR_BLUE, ··· 508 512 ), 509 513 'template' => $this->buildTokenizerTemplates($handles) + array( 510 514 'rules' => $all_rules, 511 - ), 512 - 'author' => array( 513 - $rule->getAuthorPHID() => 514 - $handles[$rule->getAuthorPHID()]->getName(), 515 515 ), 516 516 'info' => $config_info, 517 517 ));
+7 -1
src/applications/herald/field/HeraldContentSourceField.php
··· 20 20 } 21 21 22 22 public function getHeraldFieldValueType($condition) { 23 - return HeraldAdapter::VALUE_CONTENT_SOURCE; 23 + $map = PhabricatorContentSource::getSourceNameMap(); 24 + asort($map); 25 + 26 + return id(new HeraldSelectFieldValue()) 27 + ->setKey(self::FIELDCONST) 28 + ->setDefault(PhabricatorContentSource::SOURCE_WEB) 29 + ->setOptions($map); 24 30 } 25 31 26 32 public function supportsObject($object) {
+2 -2
src/applications/herald/field/HeraldField.php
··· 86 86 switch ($standard_type) { 87 87 case self::STANDARD_BOOL: 88 88 case self::STANDARD_PHID_BOOL: 89 - return HeraldAdapter::VALUE_NONE; 89 + return new HeraldEmptyFieldValue(); 90 90 case self::STANDARD_TEXT: 91 91 case self::STANDARD_TEXT_LIST: 92 92 case self::STANDARD_TEXT_MAP: 93 - return HeraldAdapter::VALUE_TEXT; 93 + return new HeraldTextFieldValue(); 94 94 } 95 95 96 96 throw new Exception(
+14
src/applications/herald/value/HeraldEmptyFieldValue.php
··· 1 + <?php 2 + 3 + final class HeraldEmptyFieldValue 4 + extends HeraldFieldValue { 5 + 6 + public function getFieldValueKey() { 7 + return 'none'; 8 + } 9 + 10 + public function getControlType() { 11 + return self::CONTROL_NONE; 12 + } 13 + 14 + }
+24
src/applications/herald/value/HeraldFieldValue.php
··· 1 + <?php 2 + 3 + abstract class HeraldFieldValue extends Phobject { 4 + 5 + const CONTROL_NONE = 'herald.control.none'; 6 + const CONTROL_TEXT = 'herald.control.text'; 7 + const CONTROL_SELECT = 'herald.control.select'; 8 + const CONTROL_TOKENIZER = 'herald.control.tokenizer'; 9 + 10 + abstract public function getFieldValueKey(); 11 + abstract public function getControlType(); 12 + 13 + final public function getControlSpecificationDictionary() { 14 + return array( 15 + 'control' => $this->getControlType(), 16 + 'template' => $this->getControlTemplate(), 17 + ); 18 + } 19 + 20 + protected function getControlTemplate() { 21 + return array(); 22 + } 23 + 24 + }
+59
src/applications/herald/value/HeraldSelectFieldValue.php
··· 1 + <?php 2 + 3 + final class HeraldSelectFieldValue 4 + extends HeraldFieldValue { 5 + 6 + private $key; 7 + private $options; 8 + private $default; 9 + 10 + public function setKey($key) { 11 + $this->key = $key; 12 + return $this; 13 + } 14 + 15 + public function getKey() { 16 + return $this->key; 17 + } 18 + 19 + public function setOptions(array $options) { 20 + $this->options = $options; 21 + return $this; 22 + } 23 + 24 + public function getOptions() { 25 + return $this->options; 26 + } 27 + 28 + public function setDefault($default) { 29 + $this->default = $default; 30 + return $this; 31 + } 32 + 33 + public function getDefault() { 34 + return $this->default; 35 + } 36 + 37 + public function getFieldValueKey() { 38 + if ($this->getKey() === null) { 39 + throw new PhutilInvalidStateException('setKey'); 40 + } 41 + return 'select.'.$this->getKey(); 42 + } 43 + 44 + public function getControlType() { 45 + return self::CONTROL_SELECT; 46 + } 47 + 48 + protected function getControlTemplate() { 49 + if ($this->getOptions() === null) { 50 + throw new PhutilInvalidStateException('setOptions'); 51 + } 52 + 53 + return array( 54 + 'options' => $this->getOptions(), 55 + 'default' => $this->getDefault(), 56 + ); 57 + } 58 + 59 + }
+14
src/applications/herald/value/HeraldTextFieldValue.php
··· 1 + <?php 2 + 3 + final class HeraldTextFieldValue 4 + extends HeraldFieldValue { 5 + 6 + public function getFieldValueKey() { 7 + return 'text'; 8 + } 9 + 10 + public function getControlType() { 11 + return self::CONTROL_TEXT; 12 + } 13 + 14 + }
+55 -9
webroot/rsrc/js/application/herald/HeraldRuleEditor.js
··· 200 200 return node; 201 201 }, 202 202 203 + _buildStandardInput: function(spec) { 204 + var input; 205 + var get_fn; 206 + var set_fn; 207 + switch (spec.control) { 208 + case 'herald.control.none': 209 + input = null; 210 + get_fn = JX.bag; 211 + set_fn = JX.bag; 212 + break; 213 + case 'herald.control.text': 214 + input = JX.$N('input', {type: 'text'}); 215 + get_fn = function() { return input.value; }; 216 + set_fn = function(v) { input.value = v; }; 217 + break; 218 + case 'herald.control.select': 219 + input = this._renderSelect(spec.template.options); 220 + get_fn = function() { return input.value; }; 221 + set_fn = function(v) { input.value = v; }; 222 + if (spec.template.default) { 223 + set_fn(spec.template.default); 224 + } 225 + break; 226 + case 'herald.control.tokenizer': 227 + var tokenizer = this._newTokenizer(spec.template.tokenizer, true); 228 + input = tokenizer[0]; 229 + get_fn = tokenizer[1]; 230 + set_fn = tokenizer[2]; 231 + break; 232 + default: 233 + JX.$E('No rules to build control "' + spec.control + '".'); 234 + break; 235 + } 236 + 237 + return [input, get_fn, set_fn]; 238 + }, 239 + 203 240 _buildInput : function(type) { 241 + if (this._config.info.valueMap[type]) { 242 + return this._buildStandardInput(this._config.info.valueMap[type]); 243 + } 244 + 204 245 var input; 205 246 var get_fn; 206 247 var set_fn; ··· 233 274 get_fn = JX.bag; 234 275 set_fn = JX.bag; 235 276 break; 236 - case 'contentsource': 237 277 case 'flagcolor': 238 278 case 'value-ref-type': 239 279 case 'value-ref-change': ··· 276 316 return node; 277 317 }, 278 318 279 - _newTokenizer : function(type) { 280 - var tokenizerConfig = { 281 - src : this._config.template.source[type].uri, 282 - placeholder: this._config.template.source[type].placeholder, 283 - browseURI: this._config.template.source[type].browseURI, 284 - icons : this._config.template.icons, 285 - username : this._config.username 286 - }; 319 + _newTokenizer : function(type, is_config) { 320 + var tokenizerConfig; 321 + 322 + if (is_config) { 323 + tokenizerConfig = type; 324 + } else { 325 + tokenizerConfig = { 326 + src : this._config.template.source[type].uri, 327 + placeholder: this._config.template.source[type].placeholder, 328 + browseURI: this._config.template.source[type].browseURI, 329 + icons : this._config.template.icons, 330 + username : this._config.username 331 + }; 332 + } 287 333 288 334 var build = JX.Prefab.newTokenizerFromTemplate( 289 335 this._config.template.markup,