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

Make Settings modular and allow them to be EditEngine'd

Summary: Ref T4103. This starts breaking out settings in a modern way to prepare for global defaults.

Test Plan:
- Edited diff settings.
- Saw them take effect in primary settings pane.
- Set stuff to new automatic defaults.
- Tried to edit another user's settings.
- Edited a bot's settings as an administrator.

{F1669077}

Reviewers: chad

Reviewed By: chad

Maniphest Tasks: T4103

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

+566 -4
+16
src/__phutil_library_map__.php
··· 2822 2822 'PhabricatorObjectSelectorDialog' => 'view/control/PhabricatorObjectSelectorDialog.php', 2823 2823 'PhabricatorOffsetPagedQuery' => 'infrastructure/query/PhabricatorOffsetPagedQuery.php', 2824 2824 'PhabricatorOldWorldContentSource' => 'infrastructure/contentsource/PhabricatorOldWorldContentSource.php', 2825 + 'PhabricatorOlderInlinesSetting' => 'applications/settings/setting/PhabricatorOlderInlinesSetting.php', 2825 2826 'PhabricatorOneTimeTriggerClock' => 'infrastructure/daemon/workers/clock/PhabricatorOneTimeTriggerClock.php', 2826 2827 'PhabricatorOpcodeCacheSpec' => 'applications/cache/spec/PhabricatorOpcodeCacheSpec.php', 2827 2828 'PhabricatorOwnerPathQuery' => 'applications/owners/query/PhabricatorOwnerPathQuery.php', ··· 3348 3349 'PhabricatorSecurityConfigOptions' => 'applications/config/option/PhabricatorSecurityConfigOptions.php', 3349 3350 'PhabricatorSecuritySetupCheck' => 'applications/config/check/PhabricatorSecuritySetupCheck.php', 3350 3351 'PhabricatorSelectEditField' => 'applications/transactions/editfield/PhabricatorSelectEditField.php', 3352 + 'PhabricatorSelectSetting' => 'applications/settings/setting/PhabricatorSelectSetting.php', 3351 3353 'PhabricatorSendGridConfigOptions' => 'applications/config/option/PhabricatorSendGridConfigOptions.php', 3352 3354 'PhabricatorSessionsSettingsPanel' => 'applications/settings/panel/PhabricatorSessionsSettingsPanel.php', 3355 + 'PhabricatorSetting' => 'applications/settings/setting/PhabricatorSetting.php', 3353 3356 'PhabricatorSettingsAddEmailAction' => 'applications/settings/action/PhabricatorSettingsAddEmailAction.php', 3354 3357 'PhabricatorSettingsAdjustController' => 'applications/settings/controller/PhabricatorSettingsAdjustController.php', 3355 3358 'PhabricatorSettingsApplication' => 'applications/settings/application/PhabricatorSettingsApplication.php', 3359 + 'PhabricatorSettingsEditController' => 'applications/settings/controller/PhabricatorSettingsEditController.php', 3360 + 'PhabricatorSettingsEditEngine' => 'applications/settings/editor/PhabricatorSettingsEditEngine.php', 3356 3361 'PhabricatorSettingsMainController' => 'applications/settings/controller/PhabricatorSettingsMainController.php', 3357 3362 'PhabricatorSettingsMainMenuBarExtension' => 'applications/settings/extension/PhabricatorSettingsMainMenuBarExtension.php', 3358 3363 'PhabricatorSettingsPanel' => 'applications/settings/panel/PhabricatorSettingsPanel.php', ··· 3363 3368 'PhabricatorSetupIssueUIExample' => 'applications/uiexample/examples/PhabricatorSetupIssueUIExample.php', 3364 3369 'PhabricatorSetupIssueView' => 'applications/config/view/PhabricatorSetupIssueView.php', 3365 3370 'PhabricatorShortSite' => 'aphront/site/PhabricatorShortSite.php', 3371 + 'PhabricatorShowFiletreeSetting' => 'applications/settings/setting/PhabricatorShowFiletreeSetting.php', 3366 3372 'PhabricatorSimpleEditType' => 'applications/transactions/edittype/PhabricatorSimpleEditType.php', 3367 3373 'PhabricatorSite' => 'aphront/site/PhabricatorSite.php', 3368 3374 'PhabricatorSlowvoteApplication' => 'applications/slowvote/application/PhabricatorSlowvoteApplication.php', ··· 3568 3574 'PhabricatorUIExampleRenderController' => 'applications/uiexample/controller/PhabricatorUIExampleRenderController.php', 3569 3575 'PhabricatorUIExamplesApplication' => 'applications/uiexample/application/PhabricatorUIExamplesApplication.php', 3570 3576 'PhabricatorUSEnglishTranslation' => 'infrastructure/internationalization/translation/PhabricatorUSEnglishTranslation.php', 3577 + 'PhabricatorUnifiedDiffsSetting' => 'applications/settings/setting/PhabricatorUnifiedDiffsSetting.php', 3571 3578 'PhabricatorUnitTestContentSource' => 'infrastructure/contentsource/PhabricatorUnitTestContentSource.php', 3572 3579 'PhabricatorUnitsTestCase' => 'view/__tests__/PhabricatorUnitsTestCase.php', 3573 3580 'PhabricatorUnknownContentSource' => 'infrastructure/contentsource/PhabricatorUnknownContentSource.php', ··· 3592 3599 'PhabricatorUserLogView' => 'applications/people/view/PhabricatorUserLogView.php', 3593 3600 'PhabricatorUserPHIDResolver' => 'applications/phid/resolver/PhabricatorUserPHIDResolver.php', 3594 3601 'PhabricatorUserPreferences' => 'applications/settings/storage/PhabricatorUserPreferences.php', 3602 + 'PhabricatorUserPreferencesEditor' => 'applications/settings/editor/PhabricatorUserPreferencesEditor.php', 3595 3603 'PhabricatorUserPreferencesPHIDType' => 'applications/settings/phid/PhabricatorUserPreferencesPHIDType.php', 3596 3604 'PhabricatorUserPreferencesQuery' => 'applications/settings/query/PhabricatorUserPreferencesQuery.php', 3597 3605 'PhabricatorUserPreferencesTransaction' => 'applications/settings/storage/PhabricatorUserPreferencesTransaction.php', ··· 7413 7421 'PhabricatorObjectSelectorDialog' => 'Phobject', 7414 7422 'PhabricatorOffsetPagedQuery' => 'PhabricatorQuery', 7415 7423 'PhabricatorOldWorldContentSource' => 'PhabricatorContentSource', 7424 + 'PhabricatorOlderInlinesSetting' => 'PhabricatorSelectSetting', 7416 7425 'PhabricatorOneTimeTriggerClock' => 'PhabricatorTriggerClock', 7417 7426 'PhabricatorOpcodeCacheSpec' => 'PhabricatorCacheSpec', 7418 7427 'PhabricatorOwnerPathQuery' => 'Phobject', ··· 8064 8073 'PhabricatorSecurityConfigOptions' => 'PhabricatorApplicationConfigOptions', 8065 8074 'PhabricatorSecuritySetupCheck' => 'PhabricatorSetupCheck', 8066 8075 'PhabricatorSelectEditField' => 'PhabricatorEditField', 8076 + 'PhabricatorSelectSetting' => 'PhabricatorSetting', 8067 8077 'PhabricatorSendGridConfigOptions' => 'PhabricatorApplicationConfigOptions', 8068 8078 'PhabricatorSessionsSettingsPanel' => 'PhabricatorSettingsPanel', 8079 + 'PhabricatorSetting' => 'Phobject', 8069 8080 'PhabricatorSettingsAddEmailAction' => 'PhabricatorSystemAction', 8070 8081 'PhabricatorSettingsAdjustController' => 'PhabricatorController', 8071 8082 'PhabricatorSettingsApplication' => 'PhabricatorApplication', 8083 + 'PhabricatorSettingsEditController' => 'PhabricatorController', 8084 + 'PhabricatorSettingsEditEngine' => 'PhabricatorEditEngine', 8072 8085 'PhabricatorSettingsMainController' => 'PhabricatorController', 8073 8086 'PhabricatorSettingsMainMenuBarExtension' => 'PhabricatorMainMenuBarExtension', 8074 8087 'PhabricatorSettingsPanel' => 'Phobject', ··· 8079 8092 'PhabricatorSetupIssueUIExample' => 'PhabricatorUIExample', 8080 8093 'PhabricatorSetupIssueView' => 'AphrontView', 8081 8094 'PhabricatorShortSite' => 'PhabricatorSite', 8095 + 'PhabricatorShowFiletreeSetting' => 'PhabricatorSelectSetting', 8082 8096 'PhabricatorSimpleEditType' => 'PhabricatorEditType', 8083 8097 'PhabricatorSite' => 'AphrontSite', 8084 8098 'PhabricatorSlowvoteApplication' => 'PhabricatorApplication', ··· 8305 8319 'PhabricatorUIExampleRenderController' => 'PhabricatorController', 8306 8320 'PhabricatorUIExamplesApplication' => 'PhabricatorApplication', 8307 8321 'PhabricatorUSEnglishTranslation' => 'PhutilTranslation', 8322 + 'PhabricatorUnifiedDiffsSetting' => 'PhabricatorSelectSetting', 8308 8323 'PhabricatorUnitTestContentSource' => 'PhabricatorContentSource', 8309 8324 'PhabricatorUnitsTestCase' => 'PhabricatorTestCase', 8310 8325 'PhabricatorUnknownContentSource' => 'PhabricatorContentSource', ··· 8351 8366 'PhabricatorDestructibleInterface', 8352 8367 'PhabricatorApplicationTransactionInterface', 8353 8368 ), 8369 + 'PhabricatorUserPreferencesEditor' => 'AlmanacEditor', 8354 8370 'PhabricatorUserPreferencesPHIDType' => 'PhabricatorPHIDType', 8355 8371 'PhabricatorUserPreferencesQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 8356 8372 'PhabricatorUserPreferencesTransaction' => 'PhabricatorApplicationTransaction',
+1
src/applications/people/storage/PhabricatorUser.php
··· 503 503 if (!$preferences) { 504 504 $preferences = new PhabricatorUserPreferences(); 505 505 $preferences->setUserPHID($this->getPHID()); 506 + $preferences->attachUser($this); 506 507 507 508 $default_dict = array( 508 509 PhabricatorUserPreferences::PREFERENCE_TITLES => 'glyph',
+2
src/applications/settings/application/PhabricatorSettingsApplication.php
··· 34 34 'adjust/' => 'PhabricatorSettingsAdjustController', 35 35 'timezone/(?P<offset>[^/]+)/' 36 36 => 'PhabricatorSettingsTimezoneController', 37 + '(?P<type>user)/(?P<username>[^/]+)/(?:panel/(?P<key>[^/]+)/)?' 38 + => 'PhabricatorSettingsEditController', 37 39 ), 38 40 ); 39 41 }
+35
src/applications/settings/controller/PhabricatorSettingsEditController.php
··· 1 + <?php 2 + 3 + final class PhabricatorSettingsEditController 4 + extends PhabricatorController { 5 + 6 + public function handleRequest(AphrontRequest $request) { 7 + $viewer = $this->getViewer(); 8 + 9 + $engine = id(new PhabricatorSettingsEditEngine()) 10 + ->setController($this); 11 + 12 + switch ($request->getURIData('type')) { 13 + case 'user': 14 + $user = id(new PhabricatorPeopleQuery()) 15 + ->setViewer($viewer) 16 + ->withUsernames(array($request->getURIData('username'))) 17 + ->executeOne(); 18 + 19 + $preferences = $user->loadPreferences(); 20 + 21 + PhabricatorPolicyFilter::requireCapability( 22 + $viewer, 23 + $preferences, 24 + PhabricatorPolicyCapability::CAN_EDIT); 25 + 26 + $engine->setTargetObject($preferences); 27 + break; 28 + default: 29 + return new Aphront404Response(); 30 + } 31 + 32 + return $engine->buildResponse(); 33 + } 34 + 35 + }
+91
src/applications/settings/editor/PhabricatorSettingsEditEngine.php
··· 1 + <?php 2 + 3 + final class PhabricatorSettingsEditEngine 4 + extends PhabricatorEditEngine { 5 + 6 + const ENGINECONST = 'settings.settings'; 7 + 8 + public function isEngineConfigurable() { 9 + return false; 10 + } 11 + 12 + public function getEngineName() { 13 + return pht('Settings'); 14 + } 15 + 16 + public function getSummaryHeader() { 17 + return pht('Edit Settings Configurations'); 18 + } 19 + 20 + public function getSummaryText() { 21 + return pht('This engine is used to edit settings.'); 22 + } 23 + 24 + public function getEngineApplicationClass() { 25 + return 'PhabricatorSettingsApplication'; 26 + } 27 + 28 + protected function newEditableObject() { 29 + return new PhabricatorUserPreferences(); 30 + } 31 + 32 + protected function newObjectQuery() { 33 + return new PhabricatorUserPreferencesQuery(); 34 + } 35 + 36 + protected function getObjectCreateTitleText($object) { 37 + return pht('Create Settings'); 38 + } 39 + 40 + protected function getObjectCreateButtonText($object) { 41 + return pht('Create Settings'); 42 + } 43 + 44 + protected function getObjectEditTitleText($object) { 45 + return pht('Edit Settings'); 46 + } 47 + 48 + protected function getObjectEditShortText($object) { 49 + return pht('Edit Settings'); 50 + } 51 + 52 + protected function getObjectCreateShortText() { 53 + return pht('Create Settings'); 54 + } 55 + 56 + protected function getObjectName() { 57 + return pht('Settings'); 58 + } 59 + 60 + protected function getEditorURI() { 61 + return '/settings/edit/'; 62 + } 63 + 64 + protected function getObjectCreateCancelURI($object) { 65 + return '/settings/'; 66 + } 67 + 68 + protected function getObjectViewURI($object) { 69 + // TODO: This isn't correct... 70 + return '/settings/user/'.$this->getViewer()->getUsername().'/'; 71 + } 72 + 73 + protected function getCreateNewObjectPolicy() { 74 + return PhabricatorPolicies::POLICY_ADMIN; 75 + } 76 + 77 + protected function buildCustomEditFields($object) { 78 + $viewer = $this->getViewer(); 79 + $settings = PhabricatorSetting::getAllEnabledSettings($viewer); 80 + 81 + $fields = array(); 82 + foreach ($settings as $setting) { 83 + foreach ($setting->newCustomEditFields($object) as $field) { 84 + $fields[] = $field; 85 + } 86 + } 87 + 88 + return $fields; 89 + } 90 + 91 + }
+132
src/applications/settings/editor/PhabricatorUserPreferencesEditor.php
··· 1 + <?php 2 + 3 + final class PhabricatorUserPreferencesEditor 4 + extends AlmanacEditor { 5 + 6 + public function getEditorObjectsDescription() { 7 + return pht('Settings'); 8 + } 9 + 10 + public function getTransactionTypes() { 11 + $types = parent::getTransactionTypes(); 12 + 13 + $types[] = PhabricatorUserPreferencesTransaction::TYPE_SETTING; 14 + 15 + return $types; 16 + } 17 + 18 + protected function getCustomTransactionOldValue( 19 + PhabricatorLiskDAO $object, 20 + PhabricatorApplicationTransaction $xaction) { 21 + 22 + $setting_key = $xaction->getMetadataValue( 23 + PhabricatorUserPreferencesTransaction::PROPERTY_SETTING); 24 + 25 + switch ($xaction->getTransactionType()) { 26 + case PhabricatorUserPreferencesTransaction::TYPE_SETTING: 27 + return $object->getPreference($setting_key); 28 + } 29 + 30 + return parent::getCustomTransactionOldValue($object, $xaction); 31 + } 32 + 33 + protected function getCustomTransactionNewValue( 34 + PhabricatorLiskDAO $object, 35 + PhabricatorApplicationTransaction $xaction) { 36 + 37 + $actor = $this->getActor(); 38 + 39 + $setting_key = $xaction->getMetadataValue( 40 + PhabricatorUserPreferencesTransaction::PROPERTY_SETTING); 41 + 42 + $settings = PhabricatorSetting::getAllEnabledSettings($actor); 43 + $setting = $settings[$setting_key]; 44 + 45 + switch ($xaction->getTransactionType()) { 46 + case PhabricatorUserPreferencesTransaction::TYPE_SETTING: 47 + $value = $xaction->getNewValue(); 48 + $value = $setting->getTransactionNewValue($value); 49 + return $value; 50 + } 51 + 52 + return parent::getCustomTransactionNewValue($object, $xaction); 53 + } 54 + 55 + protected function applyCustomInternalTransaction( 56 + PhabricatorLiskDAO $object, 57 + PhabricatorApplicationTransaction $xaction) { 58 + 59 + $setting_key = $xaction->getMetadataValue( 60 + PhabricatorUserPreferencesTransaction::PROPERTY_SETTING); 61 + 62 + switch ($xaction->getTransactionType()) { 63 + case PhabricatorUserPreferencesTransaction::TYPE_SETTING: 64 + $new_value = $xaction->getNewValue(); 65 + if ($new_value === null) { 66 + $object->unsetPreference($setting_key); 67 + } else { 68 + $object->setPreference($setting_key, $new_value); 69 + } 70 + return; 71 + } 72 + 73 + return parent::applyCustomInternalTransaction($object, $xaction); 74 + } 75 + 76 + protected function applyCustomExternalTransaction( 77 + PhabricatorLiskDAO $object, 78 + PhabricatorApplicationTransaction $xaction) { 79 + 80 + switch ($xaction->getTransactionType()) { 81 + case PhabricatorUserPreferencesTransaction::TYPE_SETTING: 82 + return; 83 + } 84 + 85 + return parent::applyCustomExternalTransaction($object, $xaction); 86 + } 87 + 88 + protected function validateTransaction( 89 + PhabricatorLiskDAO $object, 90 + $type, 91 + array $xactions) { 92 + 93 + $errors = parent::validateTransaction($object, $type, $xactions); 94 + 95 + $actor = $this->getActor(); 96 + $settings = PhabricatorSetting::getAllEnabledSettings($actor); 97 + 98 + switch ($type) { 99 + case PhabricatorUserPreferencesTransaction::TYPE_SETTING: 100 + foreach ($xactions as $xaction) { 101 + $setting_key = $xaction->getMetadataValue( 102 + PhabricatorUserPreferencesTransaction::PROPERTY_SETTING); 103 + 104 + $setting = idx($settings, $setting_key); 105 + if (!$setting) { 106 + $errors[] = new PhabricatorApplicationTransactionValidationError( 107 + $type, 108 + pht('Invalid'), 109 + pht( 110 + 'There is no known application setting with key "%s".', 111 + $setting_key), 112 + $xaction); 113 + continue; 114 + } 115 + 116 + try { 117 + $setting->validateTransactionValue($xaction->getNewValue()); 118 + } catch (Exception $ex) { 119 + $errors[] = new PhabricatorApplicationTransactionValidationError( 120 + $type, 121 + pht('Invalid'), 122 + $ex->getMessage(), 123 + $xaction); 124 + } 125 + } 126 + break; 127 + } 128 + 129 + return $errors; 130 + } 131 + 132 + }
-1
src/applications/settings/phid/PhabricatorUserPreferencesPHIDType.php
··· 32 32 $viewer = $query->getViewer(); 33 33 foreach ($handles as $phid => $handle) { 34 34 $preferences = $objects[$phid]; 35 - 36 35 $handle->setName(pht('Settings %d', $preferences->getID())); 37 36 } 38 37 }
+35
src/applications/settings/setting/PhabricatorOlderInlinesSetting.php
··· 1 + <?php 2 + 3 + final class PhabricatorOlderInlinesSetting 4 + extends PhabricatorSelectSetting { 5 + 6 + const SETTINGKEY = 'diff-ghosts'; 7 + 8 + const VALUE_GHOST_INLINES_ENABLED = 'default'; 9 + const VALUE_GHOST_INLINES_DISABLED = 'disabled'; 10 + 11 + public function getSettingName() { 12 + return pht('Show Older Inlines'); 13 + } 14 + 15 + protected function getControlInstructions() { 16 + return pht( 17 + 'When a revision is updated, Phabricator attempts to bring inline '. 18 + 'comments on the older version forward to the new changes. You can '. 19 + 'disable this behavior if you prefer comments stay anchored in one '. 20 + 'place.'); 21 + } 22 + 23 + public function getSettingDefaultValue() { 24 + return self::VALUE_GHOST_INLINES_ENABLED; 25 + } 26 + 27 + protected function getSelectOptions() { 28 + return array( 29 + self::VALUE_GHOST_INLINES_ENABLED => pht('Enabled'), 30 + self::VALUE_GHOST_INLINES_DISABLED => pht('Disabled'), 31 + ); 32 + } 33 + 34 + 35 + }
+55
src/applications/settings/setting/PhabricatorSelectSetting.php
··· 1 + <?php 2 + 3 + abstract class PhabricatorSelectSetting 4 + extends PhabricatorSetting { 5 + 6 + abstract protected function getSelectOptions(); 7 + 8 + final protected function newCustomEditField($object) { 9 + $setting_key = $this->getSettingKey(); 10 + $default_value = $object->getDefaultValue($setting_key); 11 + 12 + $options = $this->getSelectOptions(); 13 + 14 + if (isset($options[$default_value])) { 15 + $default_label = pht('Default (%s)', $options[$default_value]); 16 + } else { 17 + $default_label = pht('Default (Unknown, "%s")', $default_value); 18 + } 19 + 20 + $options = array( 21 + '' => $default_label, 22 + ) + $options; 23 + 24 + return $this->newEditField($object, new PhabricatorSelectEditField()) 25 + ->setOptions($options); 26 + } 27 + 28 + final public function validateTransactionValue($value) { 29 + if (!strlen($value)) { 30 + return; 31 + } 32 + 33 + $options = $this->getSelectOptions(); 34 + 35 + if (!isset($options[$value])) { 36 + throw new Exception( 37 + pht( 38 + 'Value "%s" is not valid for setting "%s": valid values are %s.', 39 + $value, 40 + $this->getSettingName(), 41 + implode(', ', array_keys($options)))); 42 + } 43 + 44 + return; 45 + } 46 + 47 + public function getTransactionNewValue($value) { 48 + if (!strlen($value)) { 49 + return null; 50 + } 51 + 52 + return (string)$value; 53 + } 54 + 55 + }
+96
src/applications/settings/setting/PhabricatorSetting.php
··· 1 + <?php 2 + 3 + abstract class PhabricatorSetting extends Phobject { 4 + 5 + private $viewer; 6 + 7 + public function setViewer(PhabricatorUser $viewer) { 8 + $this->viewer = $viewer; 9 + return $this; 10 + } 11 + 12 + public function getViewer() { 13 + return $this->viewer; 14 + } 15 + 16 + abstract public function getSettingName(); 17 + 18 + protected function getControlInstructions() { 19 + return null; 20 + } 21 + 22 + protected function isEnabledForViewer(PhabricatorUser $viewer) { 23 + return true; 24 + } 25 + 26 + public function getSettingDefaultValue() { 27 + return null; 28 + } 29 + 30 + final public function getSettingKey() { 31 + return $this->getPhobjectClassConstant('SETTINGKEY'); 32 + } 33 + 34 + public static function getAllSettings() { 35 + return id(new PhutilClassMapQuery()) 36 + ->setAncestorClass(__CLASS__) 37 + ->setUniqueMethod('getSettingKey') 38 + ->execute(); 39 + } 40 + 41 + public static function getAllEnabledSettings(PhabricatorUser $viewer) { 42 + $settings = self::getAllSettings(); 43 + foreach ($settings as $key => $setting) { 44 + if (!$setting->isEnabledForViewer($viewer)) { 45 + unset($settings[$key]); 46 + } 47 + } 48 + return $settings; 49 + } 50 + 51 + final public function newCustomEditFields($object) { 52 + $fields = array(); 53 + 54 + $field = $this->newCustomEditField($object); 55 + if ($field) { 56 + $fields[] = $field; 57 + } 58 + 59 + return $fields; 60 + } 61 + 62 + protected function newCustomEditField($object) { 63 + return null; 64 + } 65 + 66 + protected function newEditField($object, PhabricatorEditField $template) { 67 + $setting_property = PhabricatorUserPreferencesTransaction::PROPERTY_SETTING; 68 + $setting_key = $this->getSettingKey(); 69 + $value = $object->getPreference($setting_key); 70 + $xaction_type = PhabricatorUserPreferencesTransaction::TYPE_SETTING; 71 + $label = $this->getSettingName(); 72 + 73 + $template 74 + ->setKey($setting_key) 75 + ->setLabel($label) 76 + ->setValue($value) 77 + ->setTransactionType($xaction_type) 78 + ->setMetadataValue($setting_property, $setting_key); 79 + 80 + $instructions = $this->getControlInstructions(); 81 + if (strlen($instructions)) { 82 + $template->setControlInstructions($instructions); 83 + } 84 + 85 + return $template; 86 + } 87 + 88 + public function validateTransactionValue($value) { 89 + return; 90 + } 91 + 92 + public function getTransactionNewValue($value) { 93 + return $value; 94 + } 95 + 96 + }
+34
src/applications/settings/setting/PhabricatorShowFiletreeSetting.php
··· 1 + <?php 2 + 3 + final class PhabricatorShowFiletreeSetting 4 + extends PhabricatorSelectSetting { 5 + 6 + const SETTINGKEY = 'diff-filetree'; 7 + 8 + const VALUE_DISABLE_FILETREE = 0; 9 + const VALUE_ENABLE_FILETREE = 1; 10 + 11 + public function getSettingName() { 12 + return pht('Show Filetree'); 13 + } 14 + 15 + protected function getControlInstructions() { 16 + return pht( 17 + 'When viewing a revision or commit, you can enable a sidebar showing '. 18 + 'affected files. When this option is enabled, press {nav %s} to show '. 19 + 'or hide the sidebar.', 20 + 'f'); 21 + } 22 + 23 + public function getSettingDefaultValue() { 24 + return self::VALUE_DISABLE_FILETREE; 25 + } 26 + 27 + protected function getSelectOptions() { 28 + return array( 29 + self::VALUE_DISABLE_FILETREE => pht('Disable Filetree'), 30 + self::VALUE_ENABLE_FILETREE => pht('Enable Filetree'), 31 + ); 32 + } 33 + 34 + }
+35
src/applications/settings/setting/PhabricatorUnifiedDiffsSetting.php
··· 1 + <?php 2 + 3 + final class PhabricatorUnifiedDiffsSetting 4 + extends PhabricatorSelectSetting { 5 + 6 + const SETTINGKEY = 'diff-unified'; 7 + 8 + const VALUE_ON_SMALL_SCREENS = 'default'; 9 + const VALUE_ALWAYS_UNIFIED = 'unified'; 10 + 11 + public function getSettingName() { 12 + return pht('Show Unified Diffs'); 13 + } 14 + 15 + protected function getControlInstructions() { 16 + return pht( 17 + 'Phabricator normally shows diffs in a side-by-side layout on large '. 18 + 'screens and automatically switches to a unified view on small '. 19 + 'screens (like mobile phones). If you prefer unified diffs even on '. 20 + 'large screens, you can select them for use on all displays.'); 21 + } 22 + 23 + public function getSettingDefaultValue() { 24 + return self::VALUE_ON_SMALL_SCREENS; 25 + } 26 + 27 + protected function getSelectOptions() { 28 + return array( 29 + self::VALUE_ON_SMALL_SCREENS => pht('On Small Screens'), 30 + self::VALUE_ALWAYS_UNIFIED => pht('Always'), 31 + ); 32 + } 33 + 34 + 35 + }
+16 -2
src/applications/settings/storage/PhabricatorUserPreferences.php
··· 92 92 return $this; 93 93 } 94 94 95 + public function getDefaultValue($key) { 96 + $setting = self::getSettingObject($key); 97 + 98 + if (!$setting) { 99 + return null; 100 + } 101 + 102 + return $setting->getSettingDefaultValue(); 103 + } 104 + 105 + private static function getSettingObject($key) { 106 + $settings = PhabricatorSetting::getAllSettings(); 107 + return idx($settings, $key); 108 + } 109 + 95 110 public function getPinnedApplications(array $apps, PhabricatorUser $viewer) { 96 111 $pref_pinned = self::PREFERENCE_APP_PINNED; 97 112 $pinned = $this->getPreference($pref_pinned); ··· 212 227 213 228 214 229 public function getApplicationTransactionEditor() { 215 - // TODO: Implement. 216 - throw new PhutilMethodNotImplementedException(); 230 + return new PhabricatorUserPreferencesEditor(); 217 231 } 218 232 219 233 public function getApplicationTransactionObject() {
+4
src/applications/settings/storage/PhabricatorUserPreferencesTransaction.php
··· 3 3 final class PhabricatorUserPreferencesTransaction 4 4 extends PhabricatorApplicationTransaction { 5 5 6 + const TYPE_SETTING = 'setting'; 7 + 8 + const PROPERTY_SETTING = 'setting.key'; 9 + 6 10 public function getApplicationName() { 7 11 return 'user'; 8 12 }
+14 -1
src/view/form/control/AphrontFormSelectControl.php
··· 56 56 $disabled = array_fuse($disabled); 57 57 58 58 $tags = array(); 59 + $already_selected = false; 59 60 foreach ($options as $value => $thing) { 60 61 if (is_array($thing)) { 61 62 $tags[] = phutil_tag( ··· 65 66 ), 66 67 self::renderOptions($selected, $thing)); 67 68 } else { 69 + // When there are a list of options including similar values like 70 + // "0" and "" (the empty string), only select the first matching 71 + // value. Ideally this should be more precise about matching, but we 72 + // have 2,000 of these controls at this point so hold that for a 73 + // broader rewrite. 74 + if (!$already_selected && ($value == $selected)) { 75 + $is_selected = 'selected'; 76 + $already_selected = true; 77 + } else { 78 + $is_selected = null; 79 + } 80 + 68 81 $tags[] = phutil_tag( 69 82 'option', 70 83 array( 71 - 'selected' => ($value == $selected) ? 'selected' : null, 84 + 'selected' => $is_selected, 72 85 'value' => $value, 73 86 'disabled' => isset($disabled[$value]) ? 'disabled' : null, 74 87 ),