diff --git a/src/__celerity_resource_map__.php b/src/__celerity_resource_map__.php index 71d4547559..bbf1688cf3 100644 --- a/src/__celerity_resource_map__.php +++ b/src/__celerity_resource_map__.php @@ -72,7 +72,7 @@ celerity_register_resource_map(array( ), 'aphront-form-view-css' => array( - 'uri' => '/res/16af59d8/rsrc/css/aphront/form-view.css', + 'uri' => '/res/4d1d9d08/rsrc/css/aphront/form-view.css', 'type' => 'css', 'requires' => array( @@ -1682,6 +1682,30 @@ celerity_register_resource_map(array( 'uri' => '/res/pkg/4e7acf1a/core.pkg.js', 'type' => 'js', ), + '831e959b' => + array( + 'name' => 'core.pkg.css', + 'symbols' => + array( + 0 => 'phabricator-core-css', + 1 => 'phabricator-core-buttons-css', + 2 => 'phabricator-standard-page-view', + 3 => 'aphront-dialog-view-css', + 4 => 'aphront-form-view-css', + 5 => 'aphront-panel-view-css', + 6 => 'aphront-side-nav-view-css', + 7 => 'aphront-table-view-css', + 8 => 'aphront-crumbs-view-css', + 9 => 'aphront-tokenizer-control-css', + 10 => 'aphront-typeahead-control-css', + 11 => 'aphront-list-filter-view-css', + 12 => 'phabricator-directory-css', + 13 => 'phabricator-remarkup-css', + 14 => 'syntax-highlighting-css', + ), + 'uri' => '/res/pkg/831e959b/core.pkg.css', + 'type' => 'css', + ), '8710f5ac' => array( 'name' => 'differential.pkg.js', @@ -1741,30 +1765,6 @@ celerity_register_resource_map(array( 'uri' => '/res/pkg/bbe7e6f7/typeahead.pkg.js', 'type' => 'js', ), - 'e1e8a800' => - array( - 'name' => 'core.pkg.css', - 'symbols' => - array( - 0 => 'phabricator-core-css', - 1 => 'phabricator-core-buttons-css', - 2 => 'phabricator-standard-page-view', - 3 => 'aphront-dialog-view-css', - 4 => 'aphront-form-view-css', - 5 => 'aphront-panel-view-css', - 6 => 'aphront-side-nav-view-css', - 7 => 'aphront-table-view-css', - 8 => 'aphront-crumbs-view-css', - 9 => 'aphront-tokenizer-control-css', - 10 => 'aphront-typeahead-control-css', - 11 => 'aphront-list-filter-view-css', - 12 => 'phabricator-directory-css', - 13 => 'phabricator-remarkup-css', - 14 => 'syntax-highlighting-css', - ), - 'uri' => '/res/pkg/e1e8a800/core.pkg.css', - 'type' => 'css', - ), 'e4f8b52c' => array( 'name' => 'differential.pkg.css', @@ -1789,16 +1789,16 @@ celerity_register_resource_map(array( ), 'reverse' => array( - 'aphront-crumbs-view-css' => 'e1e8a800', - 'aphront-dialog-view-css' => 'e1e8a800', - 'aphront-form-view-css' => 'e1e8a800', + 'aphront-crumbs-view-css' => '831e959b', + 'aphront-dialog-view-css' => '831e959b', + 'aphront-form-view-css' => '831e959b', 'aphront-headsup-action-list-view-css' => 'e4f8b52c', - 'aphront-list-filter-view-css' => 'e1e8a800', - 'aphront-panel-view-css' => 'e1e8a800', - 'aphront-side-nav-view-css' => 'e1e8a800', - 'aphront-table-view-css' => 'e1e8a800', - 'aphront-tokenizer-control-css' => 'e1e8a800', - 'aphront-typeahead-control-css' => 'e1e8a800', + 'aphront-list-filter-view-css' => '831e959b', + 'aphront-panel-view-css' => '831e959b', + 'aphront-side-nav-view-css' => '831e959b', + 'aphront-table-view-css' => '831e959b', + 'aphront-tokenizer-control-css' => '831e959b', + 'aphront-typeahead-control-css' => '831e959b', 'differential-changeset-view-css' => 'e4f8b52c', 'differential-core-view-css' => 'e4f8b52c', 'differential-inline-comment-editor' => '8710f5ac', @@ -1847,16 +1847,16 @@ celerity_register_resource_map(array( 'javelin-vector' => 'b164acea', 'javelin-workflow' => '4e7acf1a', 'phabricator-content-source-view-css' => 'e4f8b52c', - 'phabricator-core-buttons-css' => 'e1e8a800', - 'phabricator-core-css' => 'e1e8a800', - 'phabricator-directory-css' => 'e1e8a800', + 'phabricator-core-buttons-css' => '831e959b', + 'phabricator-core-css' => '831e959b', + 'phabricator-directory-css' => '831e959b', 'phabricator-drag-and-drop-file-upload' => '8710f5ac', 'phabricator-keyboard-shortcut' => '4e7acf1a', 'phabricator-keyboard-shortcut-manager' => '4e7acf1a', 'phabricator-object-selector-css' => 'e4f8b52c', - 'phabricator-remarkup-css' => 'e1e8a800', + 'phabricator-remarkup-css' => '831e959b', 'phabricator-shaped-request' => '8710f5ac', - 'phabricator-standard-page-view' => 'e1e8a800', - 'syntax-highlighting-css' => 'e1e8a800', + 'phabricator-standard-page-view' => '831e959b', + 'syntax-highlighting-css' => '831e959b', ), )); diff --git a/src/applications/maniphest/auxiliaryfield/default/ManiphestAuxiliaryFieldDefaultSpecification.php b/src/applications/maniphest/auxiliaryfield/default/ManiphestAuxiliaryFieldDefaultSpecification.php index d6bbfc7022..3bed2b83be 100644 --- a/src/applications/maniphest/auxiliaryfield/default/ManiphestAuxiliaryFieldDefaultSpecification.php +++ b/src/applications/maniphest/auxiliaryfield/default/ManiphestAuxiliaryFieldDefaultSpecification.php @@ -26,11 +26,14 @@ class ManiphestAuxiliaryFieldDefaultSpecification private $fieldType; private $selectOptions; + private $checkboxLabel; + private $checkboxValue; private $error; const TYPE_SELECT = 'select'; const TYPE_STRING = 'string'; const TYPE_INT = 'int'; + const TYPE_BOOL = 'bool'; public function getFieldType() { return $this->fieldType; @@ -68,35 +71,62 @@ class ManiphestAuxiliaryFieldDefaultSpecification return $this->required; } + public function setCheckboxLabel($checkbox_label) { + $this->checkboxLabel = $checkbox_label; + return $this; + } + + public function getCheckboxLabel() { + return $this->checkboxLabel; + } + + public function setCheckboxValue($checkbox_value) { + $this->checkboxValue = $checkbox_value; + return $this; + } + + public function getCheckboxValue() { + return $this->checkboxValue; + } + public function renderControl() { $control = null; - switch ($this->getFieldType()) { + $type = $this->getFieldType(); + switch ($type) { case self::TYPE_INT: - $control = new AphrontFormTextControl(); break; - case self::TYPE_STRING: $control = new AphrontFormTextControl(); break; - case self::TYPE_SELECT: $control = new AphrontFormSelectControl(); $control->setOptions($this->getSelectOptions()); break; - + case self::TYPE_BOOL: + $control = new AphrontFormCheckboxControl(); + break; default: + $label = $this->getLabel(); throw new ManiphestAuxiliaryFieldTypeException( - $this->getFieldType().' is not a valid type for '.$this->getLabel() - ); + "Field type '{$type}' is not a valid type (for field '{$label}')."); break; } - $control->setValue($this->getValue()); + if ($type == self::TYPE_BOOL) { + $control->addCheckbox( + 'auxiliary['.$this->getAuxiliaryKey().']', + 1, + $this->getCheckboxLabel(), + (bool)$this->getValue()); + } else { + $control->setValue($this->getValue()); + $control->setName('auxiliary['.$this->getAuxiliaryKey().']'); + } + $control->setLabel($this->getLabel()); $control->setCaption($this->getCaption()); - $control->setName('auxiliary['.$this->getAuxiliaryKey().']'); $control->setError($this->getError()); return $control; @@ -104,7 +134,7 @@ class ManiphestAuxiliaryFieldDefaultSpecification public function setValueFromRequest($request) { $aux_post_values = $request->getArr('auxiliary'); - $this->setValue(idx($aux_post_values, $this->getAuxiliaryKey())); + $this->setValue(idx($aux_post_values, $this->getAuxiliaryKey(), '')); } public function getValueForStorage() { @@ -123,17 +153,29 @@ class ManiphestAuxiliaryFieldDefaultSpecification $this->getLabel().' must be an integer value.' ); } - break; - + case self::TYPE_BOOL: + return true; case self::TYPE_STRING: return true; - break; - case self::TYPE_SELECT: return true; - break; } } + public function renderForDetailView() { + switch ($this->getFieldType()) { + case self::TYPE_BOOL: + if ($this->getValue()) { + return phutil_escape_html($this->getCheckboxValue()); + } else { + return null; + } + case self::TYPE_SELECT: + $display = idx($this->getSelectOptions(), $this->getValue()); + return phutil_escape_html($display); + } + return parent::renderForDetailView(); + } + } diff --git a/src/applications/maniphest/auxiliaryfield/default/__init__.php b/src/applications/maniphest/auxiliaryfield/default/__init__.php index 950c3a4495..d2dc5ac92e 100644 --- a/src/applications/maniphest/auxiliaryfield/default/__init__.php +++ b/src/applications/maniphest/auxiliaryfield/default/__init__.php @@ -9,9 +9,11 @@ phutil_require_module('phabricator', 'applications/maniphest/auxiliaryfield/base'); phutil_require_module('phabricator', 'applications/maniphest/auxiliaryfield/typeexception'); phutil_require_module('phabricator', 'applications/maniphest/auxiliaryfield/validationexception'); +phutil_require_module('phabricator', 'view/form/control/checkbox'); phutil_require_module('phabricator', 'view/form/control/select'); phutil_require_module('phabricator', 'view/form/control/text'); +phutil_require_module('phutil', 'markup'); phutil_require_module('phutil', 'utils'); diff --git a/src/applications/maniphest/extensions/task/ManiphestDefaultTaskExtensions.php b/src/applications/maniphest/extensions/task/ManiphestDefaultTaskExtensions.php index 2793f83520..1ee4d049b9 100644 --- a/src/applications/maniphest/extensions/task/ManiphestDefaultTaskExtensions.php +++ b/src/applications/maniphest/extensions/task/ManiphestDefaultTaskExtensions.php @@ -33,6 +33,9 @@ final class ManiphestDefaultTaskExtensions $spec->setFieldType(idx($info, 'type')); $spec->setRequired(idx($info, 'required')); + $spec->setCheckboxLabel(idx($info, 'checkbox-label')); + $spec->setCheckboxValue(idx($info, 'checkbox-value', 1)); + if ($spec->getFieldType() == ManiphestAuxiliaryFieldDefaultSpecification::TYPE_SELECT) { $spec->setSelectOptions(idx($info, 'options')); diff --git a/src/docs/userguide/maniphest_custom.diviner b/src/docs/userguide/maniphest_custom.diviner index c7f74fe64e..2f433a2e9a 100644 --- a/src/docs/userguide/maniphest_custom.diviner +++ b/src/docs/userguide/maniphest_custom.diviner @@ -44,11 +44,15 @@ Each array key must be unique, and is used to organize the internal storage of the field. These options are available: - **label**: Display label for the field on the edit and detail interfaces. - - **type**: Field type, one of **int**, **string** or **select**. + - **type**: Field type, one of **int**, **string**, **bool** or **select**. - **caption**: A caption to display underneath the field (optional). - **required**: True if the user should be required to provide a value. - **options**: If type is set to **select**, provide options for the dropdown as a dictionary. + - **checkbox-label**: If type is set to **bool**, an optional string to + show next to the checkbox. + - **checkbox-value**: If type is set to **bool**, the value to show on + the detail view when the checkbox is selected. = Advanced Field Customization = diff --git a/webroot/rsrc/css/aphront/form-view.css b/webroot/rsrc/css/aphront/form-view.css index f05e957d3f..40279e5c71 100644 --- a/webroot/rsrc/css/aphront/form-view.css +++ b/webroot/rsrc/css/aphront/form-view.css @@ -116,9 +116,11 @@ table.aphront-form-control-checkbox-layout { table.aphront-form-control-checkbox-layout th { padding-top: 2px; padding-left: 0.35em; + padding-bottom: 4px; } .aphront-form-control-checkbox-layout td input { + margin-top: 4px; width: auto; }