Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F15376149
D14699.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
16 KB
Referenced Files
None
Subscribers
None
D14699.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D14699: Support "template objects" generically in EditEngine
Attached
Detach File
Event Timeline
Log In to Comment