Page MenuHomePhabricator

D14699.diff
No OneTemporary

D14699.diff

diff --git a/src/applications/maniphest/editor/ManiphestEditEngine.php b/src/applications/maniphest/editor/ManiphestEditEngine.php
--- a/src/applications/maniphest/editor/ManiphestEditEngine.php
+++ b/src/applications/maniphest/editor/ManiphestEditEngine.php
@@ -81,6 +81,7 @@
->setLabel(pht('Status'))
->setDescription(pht('Status of the task.'))
->setTransactionType(ManiphestTransaction::TYPE_STATUS)
+ ->setIsCopyable(true)
->setValue($object->getStatus())
->setOptions($status_map)
->setCommentActionLabel(pht('Change Status'))
@@ -91,6 +92,7 @@
->setLabel(pht('Assigned To'))
->setDescription(pht('User who is responsible for the task.'))
->setTransactionType(ManiphestTransaction::TYPE_OWNER)
+ ->setIsCopyable(true)
->setSingleValue($object->getOwnerPHID())
->setCommentActionLabel(pht('Assign / Claim'))
->setCommentActionDefaultValue($owner_value),
@@ -99,6 +101,7 @@
->setLabel(pht('Priority'))
->setDescription(pht('Priority of the task.'))
->setTransactionType(ManiphestTransaction::TYPE_PRIORITY)
+ ->setIsCopyable(true)
->setValue($object->getPriority())
->setOptions($priority_map)
->setCommentActionLabel($priority_label),
diff --git a/src/applications/owners/editor/PhabricatorOwnersPackageEditEngine.php b/src/applications/owners/editor/PhabricatorOwnersPackageEditEngine.php
--- a/src/applications/owners/editor/PhabricatorOwnersPackageEditEngine.php
+++ b/src/applications/owners/editor/PhabricatorOwnersPackageEditEngine.php
@@ -58,6 +58,7 @@
->setDescription(pht('Users and projects which own the package.'))
->setTransactionType(PhabricatorOwnersPackageTransaction::TYPE_OWNERS)
->setDatasource(new PhabricatorProjectOrUserDatasource())
+ ->setIsCopyable(true)
->setValue($object->getOwnerPHIDs()),
id(new PhabricatorSelectEditField())
->setKey('status')
@@ -74,6 +75,7 @@
'Automatically trigger audits for commits affecting files in '.
'this package.'))
->setTransactionType(PhabricatorOwnersPackageTransaction::TYPE_AUDITING)
+ ->setIsCopyable(true)
->setValue($object->getAuditingEnabled())
->setOptions(
array(
diff --git a/src/applications/paste/editor/PhabricatorPasteEditEngine.php b/src/applications/paste/editor/PhabricatorPasteEditEngine.php
--- a/src/applications/paste/editor/PhabricatorPasteEditEngine.php
+++ b/src/applications/paste/editor/PhabricatorPasteEditEngine.php
@@ -73,6 +73,7 @@
'title.'))
->setAliases(array('lang'))
->setTransactionType(PhabricatorPasteTransaction::TYPE_LANGUAGE)
+ ->setIsCopyable(true)
->setValue($object->getLanguage())
->setOptions($langs),
id(new PhabricatorSelectEditField())
diff --git a/src/applications/policy/editor/PhabricatorPolicyEditEngineExtension.php b/src/applications/policy/editor/PhabricatorPolicyEditEngineExtension.php
--- a/src/applications/policy/editor/PhabricatorPolicyEditEngineExtension.php
+++ b/src/applications/policy/editor/PhabricatorPolicyEditEngineExtension.php
@@ -83,6 +83,7 @@
->setLabel($label)
->setDescription($description)
->setAliases($aliases)
+ ->setIsCopyable(true)
->setCapability($capability)
->setPolicies($policies)
->setTransactionType($type)
@@ -100,6 +101,7 @@
->setEditTypeKey('space')
->setDescription(
pht('Shifts the object in the Spaces application.'))
+ ->setIsCopyable(true)
->setIsReorderable(false)
->setAliases(array('space', 'policy.space'))
->setTransactionType($type_space)
diff --git a/src/applications/project/editor/PhabricatorProjectsEditEngineExtension.php b/src/applications/project/editor/PhabricatorProjectsEditEngineExtension.php
--- a/src/applications/project/editor/PhabricatorProjectsEditEngineExtension.php
+++ b/src/applications/project/editor/PhabricatorProjectsEditEngineExtension.php
@@ -48,6 +48,7 @@
->setEditTypeKey('projects')
->setDescription(pht('Add or remove associated projects.'))
->setAliases(array('project', 'projects'))
+ ->setIsCopyable(true)
->setUseEdgeTransactions(true)
->setEdgeTransactionDescriptions(
pht('Add projects.'),
diff --git a/src/applications/subscriptions/editor/PhabricatorSubscriptionsEditEngineExtension.php b/src/applications/subscriptions/editor/PhabricatorSubscriptionsEditEngineExtension.php
--- a/src/applications/subscriptions/editor/PhabricatorSubscriptionsEditEngineExtension.php
+++ b/src/applications/subscriptions/editor/PhabricatorSubscriptionsEditEngineExtension.php
@@ -45,6 +45,7 @@
->setEditTypeKey('subscribers')
->setDescription(pht('Manage subscribers.'))
->setAliases(array('subscriber', 'subscribers'))
+ ->setIsCopyable(true)
->setUseEdgeTransactions(true)
->setEdgeTransactionDescriptions(
pht('Add subscribers.'),
diff --git a/src/applications/transactions/editengine/PhabricatorEditEngine.php b/src/applications/transactions/editengine/PhabricatorEditEngine.php
--- a/src/applications/transactions/editengine/PhabricatorEditEngine.php
+++ b/src/applications/transactions/editengine/PhabricatorEditEngine.php
@@ -95,7 +95,7 @@
}
$config = $this->getEditEngineConfiguration();
- $fields = $config->applyConfigurationToFields($this, $fields);
+ $fields = $config->applyConfigurationToFields($this, $object, $fields);
foreach ($fields as $field) {
$field
@@ -443,12 +443,16 @@
* to make Conduit a little easier to use.
*
* @param wild ID, PHID, or monogram.
+ * @param list<const> List of required capability constants, or omit for
+ * defaults.
* @return object Corresponding editable object.
* @task load
*/
- private function newObjectFromIdentifier($identifier) {
+ private function newObjectFromIdentifier(
+ $identifier,
+ array $capabilities = array()) {
if (is_int($identifier) || ctype_digit($identifier)) {
- $object = $this->newObjectFromID($identifier);
+ $object = $this->newObjectFromID($identifier, $capabilities);
if (!$object) {
throw new Exception(
@@ -462,7 +466,7 @@
$type_unknown = PhabricatorPHIDConstants::PHID_TYPE_UNKNOWN;
if (phid_get_type($identifier) != $type_unknown) {
- $object = $this->newObjectFromPHID($identifier);
+ $object = $this->newObjectFromPHID($identifier, $capabilities);
if (!$object) {
throw new Exception(
@@ -503,7 +507,7 @@
// sure it's really valid, goes through standard policy check logic, and
// picks up any `need...()` clauses we want it to load with.
- $object = $this->newObjectFromPHID($target->getPHID());
+ $object = $this->newObjectFromPHID($target->getPHID(), $capabilities);
if (!$object) {
throw new Exception(
pht(
@@ -536,14 +540,16 @@
* Load an object by PHID.
*
* @param phid Object PHID.
+ * @param list<const> List of required capability constants, or omit for
+ * defaults.
* @return object|null Object, or null if no such object exists.
* @task load
*/
- private function newObjectFromPHID($phid) {
+ private function newObjectFromPHID($phid, array $capabilities = array()) {
$query = $this->newObjectQuery()
->withPHIDs(array($phid));
- return $this->newObjectFromQuery($query);
+ return $this->newObjectFromQuery($query, $capabilities);
}
@@ -629,6 +635,9 @@
);
$use_default = true;
break;
+ case 'parameters':
+ $use_default = true;
+ break;
default:
break;
}
@@ -769,11 +778,43 @@
}
} else {
if ($this->getIsCreate()) {
+ $template = $request->getStr('template');
+
+ if (strlen($template)) {
+ $template_object = $this->newObjectFromIdentifier(
+ $template,
+ array(
+ PhabricatorPolicyCapability::CAN_VIEW,
+ ));
+ if (!$template_object) {
+ return new Aphront404Response();
+ }
+ } else {
+ $template_object = null;
+ }
+
+ if ($template_object) {
+ $copy_fields = $this->buildEditFields($template_object);
+ $copy_fields = mpull($copy_fields, null, 'getKey');
+ foreach ($copy_fields as $copy_key => $copy_field) {
+ if (!$copy_field->getIsCopyable()) {
+ unset($copy_fields[$copy_key]);
+ }
+ }
+ } else {
+ $copy_fields = array();
+ }
+
foreach ($fields as $field) {
if ($field->getIsLocked() || $field->getIsHidden()) {
continue;
}
+ $field_key = $field->getKey();
+ if (isset($copy_fields[$field_key])) {
+ $field->readValueFromField($copy_fields[$field_key]);
+ }
+
$field->readValueFromRequest($request);
}
}
diff --git a/src/applications/transactions/editfield/PhabricatorEditField.php b/src/applications/transactions/editfield/PhabricatorEditField.php
--- a/src/applications/transactions/editfield/PhabricatorEditField.php
+++ b/src/applications/transactions/editfield/PhabricatorEditField.php
@@ -28,6 +28,7 @@
private $isReorderable = true;
private $isDefaultable = true;
private $isLockable = true;
+ private $isCopyable = false;
public function setKey($key) {
$this->key = $key;
@@ -146,6 +147,15 @@
return $this->isHidden;
}
+ public function setIsCopyable($is_copyable) {
+ $this->isCopyable = $is_copyable;
+ return $this;
+ }
+
+ public function getIsCopyable() {
+ return $this->isCopyable;
+ }
+
public function setIsSubmittedForm($is_submitted) {
$this->isSubmittedForm = $is_submitted;
return $this;
@@ -366,6 +376,15 @@
return $this->getHTTPParameterValue($request, $key);
}
+ public function readValueFromField(PhabricatorEditField $other) {
+ $this->value = $this->getValueFromField($other);
+ return $this;
+ }
+
+ protected function getValueFromField(PhabricatorEditField $other) {
+ return $other->getValue();
+ }
+
/**
* Read and return the value the object had when the user first loaded the
diff --git a/src/applications/transactions/storage/PhabricatorEditEngineConfiguration.php b/src/applications/transactions/storage/PhabricatorEditEngineConfiguration.php
--- a/src/applications/transactions/storage/PhabricatorEditEngineConfiguration.php
+++ b/src/applications/transactions/storage/PhabricatorEditEngineConfiguration.php
@@ -89,12 +89,15 @@
public function applyConfigurationToFields(
PhabricatorEditEngine $engine,
+ $object,
array $fields) {
$fields = mpull($fields, null, 'getKey');
+ $is_new = !$object->getID();
+
$values = $this->getProperty('defaults', array());
foreach ($fields as $key => $field) {
- if ($engine->getIsCreate()) {
+ if ($is_new) {
if (array_key_exists($key, $values)) {
$field->readDefaultValueFromConfiguration($values[$key]);
}
diff --git a/src/applications/transactions/view/PhabricatorApplicationEditHTTPParameterHelpView.php b/src/applications/transactions/view/PhabricatorApplicationEditHTTPParameterHelpView.php
--- a/src/applications/transactions/view/PhabricatorApplicationEditHTTPParameterHelpView.php
+++ b/src/applications/transactions/view/PhabricatorApplicationEditHTTPParameterHelpView.php
@@ -176,6 +176,59 @@
'wide',
));
+ $template_text = pht(<<<EOTEXT
+Template Objects
+----------------
+
+Instead of specifying each field value individually, you can specify another
+object to use as a template. Some of the initial fields will be copied from the
+template object.
+
+Specify a template object with the `template` parameter. You can use an ID,
+PHID, or monogram (for objects which have monograms). For example, you might
+use URIs like these:
+
+```
+%s?template=123
+%s?template=PHID-WXYZ-abcdef...
+%s?template=T123
+```
+
+You can combine the `template` parameter with HTTP parameters: the template
+object will be copied first, then any HTTP parameters will be read.
+
+When using `template`, these fields will be copied:
+EOTEXT
+ ,
+ $uri,
+ $uri,
+ $uri);
+
+ $yes = id(new PHUIIconView())->setIconFont('fa-check-circle green');
+ $no = id(new PHUIIconView())->setIconFont('fa-times grey');
+
+ $rows = array();
+ foreach ($fields as $field) {
+ $rows[] = array(
+ $field->getLabel(),
+ $field->getIsCopyable() ? $yes : $no,
+ );
+ }
+
+ $template_table = id(new AphrontTableView($rows))
+ ->setNoDataString(
+ pht('None of the fields on this object support templating.'))
+ ->setHeaders(
+ array(
+ pht('Field'),
+ pht('Will Copy'),
+ ))
+ ->setColumnClasses(
+ array(
+ 'pri',
+ 'wide',
+ ));
+
$select_text = pht(<<<EOTEXT
Select Fields
-------------
@@ -243,6 +296,8 @@
$main_table,
$this->renderInstructions($aliases_text),
$alias_table,
+ $this->renderInstructions($template_text),
+ $template_table,
$this->renderInstructions($select_text),
$select_table,
$this->renderInstructions($types_text),
diff --git a/src/docs/user/configuration/custom_fields.diviner b/src/docs/user/configuration/custom_fields.diviner
--- a/src/docs/user/configuration/custom_fields.diviner
+++ b/src/docs/user/configuration/custom_fields.diviner
@@ -119,6 +119,8 @@
above the control when rendered on the edit view.
- **placeholder**: A placeholder text that appears on text boxes. Only
supported in text, int and remarkup fields (optional).
+ - **copy**: If true, this field's value will be copied when an object is
+ created using another object as a template.
The `strings` value supports different strings per control type. They are:
@@ -128,15 +130,6 @@
- **search.default** Text for the search interface, defaults to "(Any)".
- **search.require** Text for the search interface, defaults to "Require".
-Some applications have specific options which only work in that application.
-
-In **Maniphest**:
-
- - **copy**: When a user creates a task, the UI gives them an option to
- "Create Another Similar Task". Some fields from the original task are copied
- into the new task, while others are not; by default, fields are not copied.
- If you want this field to be copied, specify `true` for the `copy` property.
-
Internally, Phabricator implements some additional custom field types and
options. These are not intended for general use and are subject to abrupt
change, but are documented here for completeness:
diff --git a/src/infrastructure/customfield/editor/PhabricatorCustomFieldEditEngineExtension.php b/src/infrastructure/customfield/editor/PhabricatorCustomFieldEditEngineExtension.php
--- a/src/infrastructure/customfield/editor/PhabricatorCustomFieldEditEngineExtension.php
+++ b/src/infrastructure/customfield/editor/PhabricatorCustomFieldEditEngineExtension.php
@@ -35,7 +35,7 @@
$field_list->setViewer($viewer);
- if (!$engine->getIsCreate()) {
+ if ($object->getID()) {
$field_list->readFieldsFromStorage($object);
}
diff --git a/src/infrastructure/customfield/standard/PhabricatorStandardCustomField.php b/src/infrastructure/customfield/standard/PhabricatorStandardCustomField.php
--- a/src/infrastructure/customfield/standard/PhabricatorStandardCustomField.php
+++ b/src/infrastructure/customfield/standard/PhabricatorStandardCustomField.php
@@ -15,6 +15,7 @@
private $fieldError;
private $required;
private $default;
+ private $isCopyable;
abstract public function getFieldType();
@@ -115,6 +116,9 @@
case 'default':
$this->setFieldValue($value);
break;
+ case 'copy':
+ $this->setIsCopyable($value);
+ break;
case 'type':
// We set this earlier on.
break;
@@ -185,6 +189,15 @@
return idx($this->strings, $key, $default);
}
+ public function setIsCopyable($is_copyable) {
+ $this->isCopyable = $is_copyable;
+ return $this;
+ }
+
+ public function getIsCopyable() {
+ return $this->isCopyable;
+ }
+
public function shouldUseStorage() {
try {
$object = $this->newStorageObject();
@@ -430,7 +443,8 @@
$short = 'custom.'.$this->getRawStandardFieldKey();
return parent::newStandardEditField()
- ->setEditTypeKey($short);
+ ->setEditTypeKey($short)
+ ->setIsCopyable($this->getIsCopyable());
}
public function shouldAppearInConduitTransactions() {

File Metadata

Mime Type
text/plain
Expires
Mar 14 2025, 2:06 AM (4 w, 2 d ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
7223477
Default Alt Text
D14699.diff (16 KB)

Event Timeline