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

Allow custom fields to be reordered and disabled from Config

Summary: Ref T1703. Put a more reasonable UI than "blob of JSON" on top of this.

Test Plan:
Reordered, enabled and disabled user profile fields.

{F49317}

Reviewers: btrahan, chad

Reviewed By: chad

CC: aran

Maniphest Tasks: T1703

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

+202 -1
+14
src/__celerity_resource_map__.php
··· 1343 1343 ), 1344 1344 'disk' => '/rsrc/js/application/phortune/behavior-balanced-payment-form.js', 1345 1345 ), 1346 + 'javelin-behavior-config-reorder-fields' => 1347 + array( 1348 + 'uri' => '/res/691c5c8c/rsrc/js/application/config/behavior-reorder-fields.js', 1349 + 'type' => 'js', 1350 + 'requires' => 1351 + array( 1352 + 0 => 'javelin-behavior', 1353 + 1 => 'javelin-stratcom', 1354 + 2 => 'javelin-dom', 1355 + 3 => 'javelin-json', 1356 + 4 => 'phabricator-draggable-list', 1357 + ), 1358 + 'disk' => '/rsrc/js/application/config/behavior-reorder-fields.js', 1359 + ), 1346 1360 'javelin-behavior-conpherence-menu' => 1347 1361 array( 1348 1362 'uri' => '/res/f27205d4/rsrc/js/application/conpherence/behavior-menu.js',
+5 -1
src/applications/people/customfield/PhabricatorUserBlurbField.php
··· 14 14 } 15 15 16 16 public function getFieldDescription() { 17 - return pht('Short user summary.'); 17 + return pht('Short blurb about the user.'); 18 + } 19 + 20 + public function canDisableField() { 21 + return true; 18 22 } 19 23 20 24 protected function didSetObject(PhabricatorCustomFieldInterface $object) {
+125
src/infrastructure/customfield/config/PhabricatorCustomFieldConfigOptionType.php
··· 3 3 final class PhabricatorCustomFieldConfigOptionType 4 4 extends PhabricatorConfigOptionType { 5 5 6 + public function readRequest( 7 + PhabricatorConfigOption $option, 8 + AphrontRequest $request) { 9 + 10 + $e_value = null; 11 + $errors = array(); 12 + $storage_value = $request->getStr('value'); 13 + 14 + $in_value = json_decode($storage_value, true); 15 + if (!is_array($in_value)) { 16 + $in_value = array(); 17 + } 18 + 19 + // When we submit from JS, we submit a list (since maps are not guaranteed 20 + // to retain order). Convert it into a map for storage (since it's far more 21 + // convenient for us elsewhere). 22 + $storage_value = ipull($in_value, null, 'key'); 23 + $display_value = $storage_value; 24 + 25 + return array($e_value, $errors, $storage_value, $display_value); 26 + } 27 + 28 + public function renderControl( 29 + PhabricatorConfigOption $option, 30 + $display_value, 31 + $e_value) { 32 + 33 + $field_base_class = $option->getCustomData(); 34 + 35 + $field_spec = $display_value; 36 + if (!is_array($field_spec)) { 37 + $field_spec = PhabricatorEnv::getEnvConfig($option->getKey()); 38 + } 39 + 40 + // Get all of the fields (including disabled fields) by querying for them 41 + // with a faux spec where no fields are disabled. 42 + $faux_spec = $field_spec; 43 + foreach ($faux_spec as $key => $spec) { 44 + unset($faux_spec[$key]['disabled']); 45 + } 46 + $fields = PhabricatorCustomField::buildFieldList( 47 + $field_base_class, 48 + $faux_spec); 49 + 50 + $list_id = celerity_generate_unique_node_id(); 51 + $input_id = celerity_generate_unique_node_id(); 52 + 53 + $list = id(new PhabricatorObjectItemListView()) 54 + ->setFlush(true) 55 + ->setID($list_id); 56 + foreach ($fields as $key => $field) { 57 + $item = id(new PhabricatorObjectItemView()) 58 + ->addSigil('field-spec') 59 + ->setMetadata(array('fieldKey' => $key)) 60 + ->setGrippable(true) 61 + ->addAttribute($field->getFieldDescription()) 62 + ->setHeader($field->getFieldName()); 63 + 64 + $is_disabled = !empty($field_spec[$key]['disabled']); 65 + 66 + $disabled_item = clone $item; 67 + $enabled_item = clone $item; 68 + 69 + if ($is_disabled) { 70 + $list->addItem($disabled_item); 71 + } else { 72 + $list->addItem($enabled_item); 73 + } 74 + 75 + $disabled_item->addIcon('none', pht('Disabled')); 76 + $disabled_item->addAction( 77 + id(new PHUIListItemView()) 78 + ->setHref('#') 79 + ->addSigil('field-spec-toggle') 80 + ->setIcon('new')); 81 + 82 + $enabled_item->setBarColor('green'); 83 + 84 + if (!$field->canDisableField()) { 85 + $enabled_item->addAction( 86 + id(new PHUIListItemView()) 87 + ->setIcon('lock-grey')); 88 + $enabled_item->addIcon('none', pht('Permanent Field')); 89 + } else { 90 + $enabled_item->addAction( 91 + id(new PHUIListItemView()) 92 + ->setHref('#') 93 + ->addSigil('field-spec-toggle') 94 + ->setIcon('delete')); 95 + } 96 + 97 + $fields[$key] = array( 98 + 'disabled' => $is_disabled, 99 + 'disabledMarkup' => $disabled_item->render(), 100 + 'enabledMarkup' => $enabled_item->render(), 101 + ); 102 + } 103 + 104 + $input = phutil_tag( 105 + 'input', 106 + array( 107 + 'id' => $input_id, 108 + 'type' => 'hidden', 109 + 'name' => 'value', 110 + 'value' => json_encode($display_value), 111 + )); 112 + 113 + Javelin::initBehavior( 114 + 'config-reorder-fields', 115 + array( 116 + 'listID' => $list_id, 117 + 'inputID' => $input_id, 118 + 'fields' => $fields, 119 + )); 120 + 121 + return id(new AphrontFormMarkupControl()) 122 + ->setLabel(pht('Value')) 123 + ->setError($e_value) 124 + ->setValue( 125 + array( 126 + $list, 127 + $input, 128 + )); 129 + } 130 + 6 131 }
+58
webroot/rsrc/js/application/config/behavior-reorder-fields.js
··· 1 + /** 2 + * @provides javelin-behavior-config-reorder-fields 3 + * @requires javelin-behavior 4 + * javelin-stratcom 5 + * javelin-dom 6 + * javelin-json 7 + * phabricator-draggable-list 8 + */ 9 + 10 + JX.behavior('config-reorder-fields', function(config) { 11 + 12 + var fields = config.fields; 13 + var root = JX.$(config.listID); 14 + 15 + var list = new JX.DraggableList('field-spec', root) 16 + .setFindItemsHandler(function() { 17 + return JX.DOM.scry(root, 'li', 'field-spec'); 18 + }); 19 + 20 + list.listen('didDrop', function(node, after) { 21 + write_state_to_form(); 22 + }); 23 + 24 + JX.DOM.listen(root, 'click', 'field-spec-toggle', function(e) { 25 + e.kill(); 26 + 27 + var key = e.getNodeData('field-spec').fieldKey; 28 + fields[key].disabled = !fields[key].disabled; 29 + 30 + JX.DOM.replace( 31 + e.getNode('field-spec'), 32 + JX.$H( 33 + fields[key].disabled ? 34 + fields[key].disabledMarkup : 35 + fields[key].enabledMarkup)); 36 + 37 + write_state_to_form(); 38 + }); 39 + 40 + var write_state_to_form = function() { 41 + var nodes = list.findItems(); 42 + var order = []; 43 + var key; 44 + for (var ii = 0; ii < nodes.length; ii++) { 45 + key = JX.Stratcom.getData(nodes[ii]).fieldKey; 46 + if (key) { 47 + order.push({ 48 + key: key, 49 + disabled: fields[key].disabled 50 + }); 51 + } 52 + } 53 + 54 + JX.$(config.inputID).value = JX.JSON.stringify(order); 55 + }; 56 + 57 + }); 58 +