diff --git a/src/applications/owners/editor/PhabricatorOwnersPackageEditEngine.php b/src/applications/owners/editor/PhabricatorOwnersPackageEditEngine.php index 2cab68d7e6..65dc42062e 100644 --- a/src/applications/owners/editor/PhabricatorOwnersPackageEditEngine.php +++ b/src/applications/owners/editor/PhabricatorOwnersPackageEditEngine.php @@ -1,102 +1,132 @@ getViewer()); } protected function newObjectQuery() { return id(new PhabricatorOwnersPackageQuery()) ->needPaths(true); } protected function getObjectCreateTitleText($object) { return pht('Create New Package'); } protected function getObjectEditTitleText($object) { return pht('Edit Package %s', $object->getName()); } protected function getObjectEditShortText($object) { return pht('Package %d', $object->getID()); } protected function getObjectCreateShortText() { return pht('Create Package'); } protected function getObjectViewURI($object) { $id = $object->getID(); return "/owners/package/{$id}/"; } protected function buildCustomEditFields($object) { + + $paths_help = pht(<<setKey('name') ->setLabel(pht('Name')) ->setDescription(pht('Name of the package.')) ->setTransactionType(PhabricatorOwnersPackageTransaction::TYPE_NAME) ->setIsRequired(true) ->setValue($object->getName()), id(new PhabricatorDatasourceEditField()) ->setKey('owners') ->setLabel(pht('Owners')) ->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('auditing') ->setLabel(pht('Auditing')) ->setDescription( pht( 'Automatically trigger audits for commits affecting files in '. 'this package.')) ->setTransactionType(PhabricatorOwnersPackageTransaction::TYPE_AUDITING) ->setIsCopyable(true) ->setValue($object->getAuditingEnabled()) ->setOptions( array( '' => pht('Disabled'), '1' => pht('Enabled'), )), id(new PhabricatorRemarkupEditField()) ->setKey('description') ->setLabel(pht('Description')) ->setDescription(pht('Human-readable description of the package.')) ->setTransactionType( PhabricatorOwnersPackageTransaction::TYPE_DESCRIPTION) ->setValue($object->getDescription()), id(new PhabricatorSelectEditField()) ->setKey('status') ->setLabel(pht('Status')) ->setDescription(pht('Archive or enable the package.')) ->setTransactionType(PhabricatorOwnersPackageTransaction::TYPE_STATUS) ->setIsConduitOnly(true) ->setValue($object->getStatus()) ->setOptions($object->getStatusNameMap()), id(new PhabricatorConduitEditField()) ->setKey('paths.set') ->setLabel(pht('Paths')) ->setDescription(pht('Set paths for this package.')) ->setIsConduitOnly(true) - ->setTransactionType(PhabricatorOwnersPackageTransaction::TYPE_PATHS), + ->setTransactionType(PhabricatorOwnersPackageTransaction::TYPE_PATHS) + ->setConduitDocumentation($paths_help), ); } } diff --git a/src/applications/transactions/editengine/PhabricatorEditEngineAPIMethod.php b/src/applications/transactions/editengine/PhabricatorEditEngineAPIMethod.php index 344f22b3c4..b5146e6eb3 100644 --- a/src/applications/transactions/editengine/PhabricatorEditEngineAPIMethod.php +++ b/src/applications/transactions/editengine/PhabricatorEditEngineAPIMethod.php @@ -1,201 +1,207 @@ newEditEngine(); $class = $engine->getEngineApplicationClass(); return PhabricatorApplication::getByClass($class); } public function getMethodStatus() { return self::METHOD_STATUS_UNSTABLE; } public function getMethodStatusDescription() { return pht('ApplicationEditor methods are highly unstable.'); } final protected function defineParamTypes() { return array( 'transactions' => 'list>', 'objectIdentifier' => 'optional id|phid|string', ); } final protected function defineReturnType() { return 'map'; } final protected function execute(ConduitAPIRequest $request) { $engine = $this->newEditEngine() ->setViewer($request->getUser()); return $engine->buildConduitResponse($request); } final public function getMethodDescription() { $viewer = $this->getViewer(); $engine = $this->newEditEngine() ->setViewer($viewer); $types = $engine->getConduitEditTypes(); $out = array(); $out[] = pht(<<getEditType(); $edit_summary = $type->getSummary(); $table[] = "| `{$edit_type}` | {$edit_summary} |"; } $out[] = implode("\n", $table); foreach ($types as $type) { $section = array(); $section[] = pht('Edit Type: %s', $type->getEditType()); $section[] = '---------'; $section[] = null; $section[] = $type->getDescription(); $section[] = null; $section[] = pht( 'This edit generates transactions of type `%s` internally.', $type->getTransactionType()); $section[] = null; + $type_documentation = $type->getConduitDocumentation(); + if ($type_documentation) { + $section[] = $type_documentation; + $section[] = null; + } + $type_description = pht( 'Use `%s` to select this edit type.', $type->getEditType()); $value_type = $type->getValueType(); if (!strlen($value_type)) { $value_type = '?'; } $value_description = $type->getValueDescription(); $table = array(); $table[] = "| {$key} | {$head_type} | {$description} |"; $table[] = '|--------|--------------|----------------|'; $table[] = "| `type` | `const` | {$type_description} |"; $table[] = "| `value` | `{$value_type}` | {$value_description} |"; $section[] = implode("\n", $table); $out[] = implode("\n", $section); } $out = implode("\n\n", $out); return $out; } } diff --git a/src/applications/transactions/editfield/PhabricatorEditField.php b/src/applications/transactions/editfield/PhabricatorEditField.php index 77a90f2d03..db69e493a3 100644 --- a/src/applications/transactions/editfield/PhabricatorEditField.php +++ b/src/applications/transactions/editfield/PhabricatorEditField.php @@ -1,680 +1,691 @@ key = $key; return $this; } public function getKey() { return $this->key; } public function setLabel($label) { $this->label = $label; return $this; } public function getLabel() { return $this->label; } public function setViewer(PhabricatorUser $viewer) { $this->viewer = $viewer; return $this; } public function getViewer() { return $this->viewer; } public function setAliases(array $aliases) { $this->aliases = $aliases; return $this; } public function getAliases() { return $this->aliases; } public function setObject($object) { $this->object = $object; return $this; } public function getObject() { return $this->object; } public function setDescription($description) { $this->description = $description; return $this; } public function getDescription() { return $this->description; } public function setIsLocked($is_locked) { $this->isLocked = $is_locked; return $this; } public function getIsLocked() { return $this->isLocked; } public function setIsPreview($preview) { $this->isPreview = $preview; return $this; } public function getIsPreview() { return $this->isPreview; } public function setIsReorderable($is_reorderable) { $this->isReorderable = $is_reorderable; return $this; } public function getIsReorderable() { return $this->isReorderable; } public function setIsConduitOnly($is_conduit_only) { $this->isConduitOnly = $is_conduit_only; return $this; } public function getIsConduitOnly() { return $this->isConduitOnly; } public function setIsEditDefaults($is_edit_defaults) { $this->isEditDefaults = $is_edit_defaults; return $this; } public function getIsEditDefaults() { return $this->isEditDefaults; } public function setIsDefaultable($is_defaultable) { $this->isDefaultable = $is_defaultable; return $this; } public function getIsDefaultable() { return $this->isDefaultable; } public function setIsLockable($is_lockable) { $this->isLockable = $is_lockable; return $this; } public function getIsLockable() { return $this->isLockable; } public function setIsHidden($is_hidden) { $this->isHidden = $is_hidden; return $this; } public function getIsHidden() { 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; } public function getIsSubmittedForm() { return $this->isSubmittedForm; } public function setIsRequired($is_required) { $this->isRequired = $is_required; return $this; } public function getIsRequired() { return $this->isRequired; } public function setControlError($control_error) { $this->controlError = $control_error; return $this; } public function getControlError() { return $this->controlError; } public function setCommentActionLabel($label) { $this->commentActionLabel = $label; return $this; } public function getCommentActionLabel() { return $this->commentActionLabel; } public function setCommentActionValue($comment_action_value) { $this->hasCommentActionValue = true; $this->commentActionValue = $comment_action_value; return $this; } public function getCommentActionValue() { return $this->commentActionValue; } protected function newControl() { throw new PhutilMethodNotImplementedException(); } protected function buildControl() { if ($this->getIsConduitOnly()) { return null; } $control = $this->newControl(); if ($control === null) { return null; } $control ->setValue($this->getValueForControl()) ->setName($this->getKey()); if (!$control->getLabel()) { $control->setLabel($this->getLabel()); } if ($this->getIsSubmittedForm()) { $error = $this->getControlError(); if ($error !== null) { $control->setError($error); } } else if ($this->getIsRequired()) { $control->setError(true); } return $control; } protected function renderControl() { $control = $this->buildControl(); if ($control === null) { return null; } if ($this->getIsPreview()) { $disabled = true; $hidden = false; } else if ($this->getIsEditDefaults()) { $disabled = false; $hidden = false; } else { $disabled = $this->getIsLocked(); $hidden = $this->getIsHidden(); } if ($hidden) { return null; } $control->setDisabled($disabled); return $control; } public function appendToForm(AphrontFormView $form) { $control = $this->renderControl(); if ($control !== null) { if ($this->getIsPreview()) { if ($this->getIsHidden()) { $control ->addClass('aphront-form-preview-hidden') ->setError(pht('Hidden')); } else if ($this->getIsLocked()) { $control ->setError(pht('Locked')); } } $form->appendControl($control); } return $this; } protected function getValueForControl() { return $this->getValue(); } public function getValueForDefaults() { $value = $this->getValue(); // By default, just treat the empty string like `null` since they're // equivalent for almost all fields and this reduces the number of // meaningless transactions we generate when adjusting defaults. if ($value === '') { return null; } return $value; } protected function getValue() { return $this->value; } public function setValue($value) { $this->hasValue = true; $this->initialValue = $value; $this->value = $value; return $this; } public function setMetadataValue($key, $value) { $this->metadata[$key] = $value; return $this; } public function getMetadata() { return $this->metadata; } public function getValueForTransaction() { return $this->getValue(); } public function getTransactionType() { return $this->transactionType; } public function setTransactionType($type) { $this->transactionType = $type; return $this; } public function readValueFromRequest(AphrontRequest $request) { $check = $this->getAllReadValueFromRequestKeys(); foreach ($check as $key) { if (!$this->getValueExistsInRequest($request, $key)) { continue; } $this->value = $this->getValueFromRequest($request, $key); break; } return $this; } public function readValueFromComment($value) { $this->value = $this->getValueFromComment($value); return $this; } protected function getValueFromComment($value) { return $value; } public function getAllReadValueFromRequestKeys() { $keys = array(); $keys[] = $this->getKey(); foreach ($this->getAliases() as $alias) { $keys[] = $alias; } return $keys; } public function readDefaultValueFromConfiguration($value) { $this->value = $this->getDefaultValueFromConfiguration($value); return $this; } protected function getDefaultValueFromConfiguration($value) { return $value; } protected function getValueFromObject($object) { if ($this->hasValue) { return $this->value; } else { return $this->getDefaultValue(); } } protected function getValueExistsInRequest(AphrontRequest $request, $key) { return $this->getHTTPParameterValueExists($request, $key); } protected function getValueFromRequest(AphrontRequest $request, $key) { 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 * form. * * This is the initial value from the user's point of view when they started * the edit process, and used primarily to prevent race conditions for fields * like "Projects" and "Subscribers" that use tokenizers and support edge * transactions. * * Most fields do not need to store these values or deal with initial value * handling. * * @param AphrontRequest Request to read from. * @param string Key to read. * @return wild Value read from request. */ protected function getInitialValueFromSubmit(AphrontRequest $request, $key) { return null; } public function getInitialValue() { return $this->initialValue; } public function setInitialValue($initial_value) { $this->initialValue = $initial_value; return $this; } public function readValueFromSubmit(AphrontRequest $request) { $key = $this->getKey(); if ($this->getValueExistsInSubmit($request, $key)) { $value = $this->getValueFromSubmit($request, $key); } else { $value = $this->getDefaultValue(); } $this->value = $value; $initial_value = $this->getInitialValueFromSubmit($request, $key); $this->initialValue = $initial_value; return $this; } protected function getValueExistsInSubmit(AphrontRequest $request, $key) { return $this->getHTTPParameterValueExists($request, $key); } protected function getValueFromSubmit(AphrontRequest $request, $key) { return $this->getHTTPParameterValue($request, $key); } protected function getHTTPParameterValueExists( AphrontRequest $request, $key) { $type = $this->getHTTPParameterType(); if ($type) { return $type->getExists($request, $key); } return false; } protected function getHTTPParameterValue($request, $key) { $type = $this->getHTTPParameterType(); if ($type) { return $type->getValue($request, $key); } return null; } protected function getDefaultValue() { $type = $this->getHTTPParameterType(); if ($type) { return $type->getDefaultValue(); } return null; } final public function getHTTPParameterType() { if ($this->getIsConduitOnly()) { return null; } $type = $this->newHTTPParameterType(); if ($type) { $type->setViewer($this->getViewer()); } return $type; } protected function newHTTPParameterType() { return new AphrontStringHTTPParameterType(); } public function setEditTypeKey($edit_type_key) { $this->editTypeKey = $edit_type_key; return $this; } public function getEditTypeKey() { if ($this->editTypeKey === null) { return $this->getKey(); } return $this->editTypeKey; } protected function newEditType() { // TODO: This could be a little cleaner. $http_type = $this->getHTTPParameterType(); if ($http_type) { $value_type = $http_type->getTypeName(); } else { $value_type = 'wild'; } return id(new PhabricatorSimpleEditType()) ->setValueType($value_type); } protected function getEditType() { $transaction_type = $this->getTransactionType(); if ($transaction_type === null) { return null; } $type_key = $this->getEditTypeKey(); return $this->newEditType() ->setEditType($type_key) ->setTransactionType($transaction_type) ->setDescription($this->getDescription()) - ->setMetadata($this->getMetadata()); + ->setMetadata($this->getMetadata()) + ->setConduitDocumentation($this->getConduitDocumentation()); } public function getConduitEditTypes() { $edit_type = $this->getEditType(); if ($edit_type === null) { return array(); } return array($edit_type); } public function getCommentAction() { $label = $this->getCommentActionLabel(); if ($label === null) { return null; } $action = $this->newCommentAction(); if ($action === null) { return null; } if ($this->hasCommentActionValue) { $value = $this->getCommentActionValue(); } else { $value = $this->getValue(); } $action ->setKey($this->getKey()) ->setLabel($label) ->setValue($this->getValueForCommentAction($value)); return $action; } protected function newCommentAction() { return null; } protected function getValueForCommentAction($value) { return $value; } public function shouldGenerateTransactionsFromSubmit() { if ($this->getIsConduitOnly()) { return false; } $edit_type = $this->getEditType(); if (!$edit_type) { return false; } return true; } public function shouldReadValueFromRequest() { if ($this->getIsConduitOnly()) { return false; } if ($this->getIsLocked()) { return false; } if ($this->getIsHidden()) { return false; } return true; } public function shouldReadValueFromSubmit() { if ($this->getIsConduitOnly()) { return false; } if ($this->getIsLocked()) { return false; } if ($this->getIsHidden()) { return false; } return true; } public function shouldGenerateTransactionsFromComment() { if ($this->getIsConduitOnly()) { return false; } if ($this->getIsLocked()) { return false; } if ($this->getIsHidden()) { return false; } return true; } public function generateTransactions( PhabricatorApplicationTransaction $template, array $spec) { $edit_type = $this->getEditType(); if (!$edit_type) { throw new Exception( pht( 'EditField (with key "%s", of class "%s") is generating '. 'transactions, but has no EditType.', $this->getKey(), get_class($this))); } return $edit_type->generateTransactions($template, $spec); } + public function setConduitDocumentation($conduit_documentation) { + $this->conduitDocumentation = $conduit_documentation; + return $this; + } + + public function getConduitDocumentation() { + return $this->conduitDocumentation; + } + } diff --git a/src/applications/transactions/edittype/PhabricatorEditType.php b/src/applications/transactions/edittype/PhabricatorEditType.php index c376046374..b6940f4601 100644 --- a/src/applications/transactions/edittype/PhabricatorEditType.php +++ b/src/applications/transactions/edittype/PhabricatorEditType.php @@ -1,99 +1,109 @@ description = $description; return $this; } public function getDescription() { return $this->description; } public function setSummary($summary) { $this->summary = $summary; return $this; } public function getSummary() { if ($this->summary === null) { return $this->getDescription(); } return $this->summary; } public function setLabel($label) { $this->label = $label; return $this; } public function getLabel() { return $this->label; } public function setField(PhabricatorEditField $field) { $this->field = $field; return $this; } public function getField() { return $this->field; } public function setEditType($edit_type) { $this->editType = $edit_type; return $this; } public function getEditType() { return $this->editType; } + public function setConduitDocumentation($conduit_documentation) { + $this->conduitDocumentation = $conduit_documentation; + return $this; + } + + public function getConduitDocumentation() { + return $this->conduitDocumentation; + } + public function setMetadata($metadata) { $this->metadata = $metadata; return $this; } public function getMetadata() { return $this->metadata; } public function setTransactionType($transaction_type) { $this->transactionType = $transaction_type; return $this; } public function getTransactionType() { return $this->transactionType; } abstract public function generateTransactions( PhabricatorApplicationTransaction $template, array $spec); abstract public function getValueType(); abstract public function getValueDescription(); protected function newTransaction( PhabricatorApplicationTransaction $template) { $xaction = id(clone $template) ->setTransactionType($this->getTransactionType()); foreach ($this->getMetadata() as $key => $value) { $xaction->setMetadataValue($key, $value); } return $xaction; } }