diff --git a/resources/sql/20230427.semistructured.3.objectinstance.customfield.sql b/resources/sql/20230427.semistructured.3.objectinstance.customfield.sql index 4d52db0..10019a6 100644 --- a/resources/sql/20230427.semistructured.3.objectinstance.customfield.sql +++ b/resources/sql/20230427.semistructured.3.objectinstance.customfield.sql @@ -1,11 +1,9 @@ ALTER TABLE {$NAMESPACE}_semistructured.semistructured_objecttype ADD customFieldsConfig LONGTEXT NOT NULL COLLATE {$COLLATE_TEXT}; CREATE TABLE {$NAMESPACE}_semistructured.semistructured_instanceconfiguredcustomfieldstorage LIKE {$NAMESPACE}_user.user_configuredcustomfieldstorage; CREATE TABLE {$NAMESPACE}_semistructured.semistructured_instancecustomfieldstringindex LIKE {$NAMESPACE}_user.user_customfieldstringindex; CREATE TABLE {$NAMESPACE}_semistructured.semistructured_instancecustomfieldnumericindex LIKE {$NAMESPACE}_user.user_customfieldnumericindex; - - diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index fedf120..6759730 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -1,139 +1,139 @@ 2, 'class' => array( 'SemiStructuredBaseController' => 'applications/semistruct/controller/SemiStructuredBaseController.php', 'SemiStructuredDAO' => 'applications/semistruct/storage/SemiStructuredDAO.php', 'SemiStructuredDataApplication' => 'applications/semistruct/application/SemiStructuredDataApplication.php', - 'SemiStructuredInstanceConfiguredCustomField' => 'applications/semistruct/customfield/SemiStructuredConfiguredCustomField.php', + 'SemiStructuredInstanceConfiguredCustomField' => 'applications/semistruct/customfield/SemiStructuredInstanceConfiguredCustomField.php', 'SemiStructuredInstanceConfiguredCustomFieldStorage' => 'applications/semistruct/storage/SemiStructuredInstanceConfiguredCustomFieldStorage.php', 'SemiStructuredInstanceCustomField' => 'applications/semistruct/customfield/SemiStructuredInstanceCustomField.php', 'SemiStructuredInstanceCustomFieldNumericIndex' => 'applications/semistruct/storage/SemiStructuredInstanceCustomFieldNumericIndex.php', 'SemiStructuredInstanceCustomFieldStringIndex' => 'applications/semistruct/storage/SemiStructuredInstanceCustomFieldStringIndex.php', 'SemiStructuredObjectInstance' => 'applications/semistruct/storage/SemiStructuredObjectInstance.php', 'SemiStructuredObjectInstanceClassTransaction' => 'applications/semistruct/xaction/instance/SemiStructuredObjectInstanceClassTransaction.php', 'SemiStructuredObjectInstanceController' => 'applications/semistruct/controller/instance/SemiStructuredObjectInstanceController.php', 'SemiStructuredObjectInstanceDescriptionTransaction' => 'applications/semistruct/xaction/instance/SemiStructuredObjectInstanceDescriptionTransaction.php', 'SemiStructuredObjectInstanceEditController' => 'applications/semistruct/controller/instance/SemiStructuredObjectInstanceEditController.php', 'SemiStructuredObjectInstanceEditEngine' => 'applications/semistruct/editor/SemiStructuredObjectInstanceEditEngine.php', 'SemiStructuredObjectInstanceListController' => 'applications/semistruct/controller/instance/SemiStructuredObjectInstanceListController.php', 'SemiStructuredObjectInstanceMailReceiver' => 'applications/semistruct/mail/SemiStructuredObjectInstanceMailReceiver.php', 'SemiStructuredObjectInstanceNameTransaction' => 'applications/semistruct/xaction/instance/SemiStructuredObjectInstanceNameTransaction.php', 'SemiStructuredObjectInstancePHIDType' => 'applications/semistruct/phid/SemiStructuredObjectInstancePHIDType.php', 'SemiStructuredObjectInstanceQuery' => 'applications/semistruct/query/SemiStructuredObjectInstanceQuery.php', 'SemiStructuredObjectInstanceRawDataTransaction' => 'applications/semistruct/xaction/instance/SemiStructuredObjectInstanceRawDataTransaction.php', 'SemiStructuredObjectInstanceReplyHandler' => 'applications/semistruct/mail/SemiStructuredObjectInstanceReplyHandler.php', 'SemiStructuredObjectInstanceSearchEngine' => 'applications/semistruct/query/SemiStructuredObjectInstanceSearchEngine.php', 'SemiStructuredObjectInstanceTransaction' => 'applications/semistruct/storage/SemiStructuredObjectInstanceTransaction.php', 'SemiStructuredObjectInstanceTransactionComment' => 'applications/semistruct/storage/SemiStructuredObjectInstanceTransactionComment.php', 'SemiStructuredObjectInstanceTransactionEditor' => 'applications/semistruct/editor/SemiStructuredObjectInstanceTransactionEditor.php', 'SemiStructuredObjectInstanceTransactionQuery' => 'applications/semistruct/query/SemiStructuredObjectInstanceTransactionQuery.php', 'SemiStructuredObjectInstanceTransactionType' => 'applications/semistruct/xaction/instance/SemiStructuredObjectInstanceTransactionType.php', 'SemiStructuredObjectInstanceViewController' => 'applications/semistruct/controller/instance/SemiStructuredObjectInstanceViewController.php', 'SemiStructuredObjectNewInstanceController' => 'applications/semistruct/controller/class/SemiStructuredObjectNewInstanceController.php', 'SemiStructuredObjectType' => 'applications/semistruct/storage/SemiStructuredObjectType.php', 'SemiStructuredObjectTypeArchiveController' => 'applications/semistruct/controller/class/SemiStructuredObjectTypeArchiveController.php', 'SemiStructuredObjectTypeController' => 'applications/semistruct/controller/class/SemiStructuredObjectTypeController.php', 'SemiStructuredObjectTypeCustomFieldsTransaction' => 'applications/semistruct/xaction/class/SemiStructuredObjectTypeCustomFieldsTransaction.php', 'SemiStructuredObjectTypeDescriptionTransaction' => 'applications/semistruct/xaction/class/SemiStructuredObjectTypeDescriptionTransaction.php', 'SemiStructuredObjectTypeEditController' => 'applications/semistruct/controller/class/SemiStructuredObjectTypeEditController.php', 'SemiStructuredObjectTypeEditEngine' => 'applications/semistruct/editor/SemiStructuredObjectTypeEditEngine.php', 'SemiStructuredObjectTypeFerretEngine' => 'applications/semistruct/engine/SemiStructuredObjectTypeFerretEngine.php', 'SemiStructuredObjectTypeListController' => 'applications/semistruct/controller/class/SemiStructuredObjectTypeListController.php', 'SemiStructuredObjectTypeMailReceiver' => 'applications/semistruct/mail/SemiStructuredObjectTypeMailReceiver.php', 'SemiStructuredObjectTypeNameTransaction' => 'applications/semistruct/xaction/class/SemiStructuredObjectTypeNameTransaction.php', 'SemiStructuredObjectTypePHIDType' => 'applications/semistruct/phid/SemiStructuredObjectTypePHIDType.php', 'SemiStructuredObjectTypeQuery' => 'applications/semistruct/query/SemiStructuredObjectTypeQuery.php', 'SemiStructuredObjectTypeReplyHandler' => 'applications/semistruct/mail/SemiStructuredObjectTypeReplyHandler.php', 'SemiStructuredObjectTypeSearchEngine' => 'applications/semistruct/query/SemiStructuredObjectTypeSearchEngine.php', 'SemiStructuredObjectTypeStatusTransaction' => 'applications/semistruct/xaction/class/SemiStructuredObjectTypeStatusTransaction.php', 'SemiStructuredObjectTypeTransaction' => 'applications/semistruct/storage/SemiStructuredObjectTypeTransaction.php', 'SemiStructuredObjectTypeTransactionComment' => 'applications/semistruct/storage/SemiStructuredObjectTypeTransactionComment.php', 'SemiStructuredObjectTypeTransactionEditor' => 'applications/semistruct/editor/SemiStructuredObjectTypeTransactionEditor.php', 'SemiStructuredObjectTypeTransactionQuery' => 'applications/semistruct/query/SemiStructuredObjectTypeTransactionQuery.php', 'SemiStructuredObjectTypeTransactionType' => 'applications/semistruct/xaction/class/SemiStructuredObjectTypeTransactionType.php', 'SemiStructuredObjectTypeViewController' => 'applications/semistruct/controller/class/SemiStructuredObjectTypeViewController.php', 'SemiStructuredPatchList' => 'applications/semistruct/storage/SemiStructuredPatchList.php', ), 'function' => array(), 'xmap' => array( 'SemiStructuredBaseController' => 'PhabricatorController', 'SemiStructuredDAO' => 'PhabricatorLiskDAO', 'SemiStructuredDataApplication' => 'PhabricatorApplication', 'SemiStructuredInstanceConfiguredCustomField' => array( 'SemiStructuredInstanceCustomField', 'PhabricatorStandardCustomFieldInterface', ), 'SemiStructuredInstanceConfiguredCustomFieldStorage' => 'PhabricatorCustomFieldStorage', 'SemiStructuredInstanceCustomField' => 'PhabricatorCustomField', 'SemiStructuredInstanceCustomFieldNumericIndex' => 'PhabricatorCustomFieldNumericIndexStorage', 'SemiStructuredInstanceCustomFieldStringIndex' => 'PhabricatorCustomFieldStringIndexStorage', 'SemiStructuredObjectInstance' => array( 'SemiStructuredDAO', 'PhabricatorPolicyInterface', 'PhabricatorApplicationTransactionInterface', 'PhabricatorSubscribableInterface', 'PhabricatorFlaggableInterface', 'PhabricatorCustomFieldInterface', 'PhabricatorDestructibleInterface', ), 'SemiStructuredObjectInstanceClassTransaction' => 'SemiStructuredObjectInstanceTransactionType', 'SemiStructuredObjectInstanceController' => 'SemiStructuredBaseController', 'SemiStructuredObjectInstanceDescriptionTransaction' => 'SemiStructuredObjectInstanceTransactionType', 'SemiStructuredObjectInstanceEditController' => 'SemiStructuredBaseController', 'SemiStructuredObjectInstanceEditEngine' => 'PhabricatorEditEngine', 'SemiStructuredObjectInstanceListController' => 'SemiStructuredObjectTypeController', 'SemiStructuredObjectInstanceMailReceiver' => 'PhabricatorObjectMailReceiver', 'SemiStructuredObjectInstanceNameTransaction' => 'SemiStructuredObjectInstanceTransactionType', 'SemiStructuredObjectInstancePHIDType' => 'PhabricatorPHIDType', 'SemiStructuredObjectInstanceQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'SemiStructuredObjectInstanceRawDataTransaction' => 'SemiStructuredObjectInstanceTransactionType', 'SemiStructuredObjectInstanceReplyHandler' => 'PhabricatorApplicationTransactionReplyHandler', 'SemiStructuredObjectInstanceSearchEngine' => 'PhabricatorApplicationSearchEngine', 'SemiStructuredObjectInstanceTransaction' => 'PhabricatorModularTransaction', 'SemiStructuredObjectInstanceTransactionComment' => 'PhabricatorApplicationTransactionComment', 'SemiStructuredObjectInstanceTransactionEditor' => 'PhabricatorApplicationTransactionEditor', 'SemiStructuredObjectInstanceTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'SemiStructuredObjectInstanceTransactionType' => 'PhabricatorModularTransactionType', 'SemiStructuredObjectInstanceViewController' => 'SemiStructuredObjectInstanceController', 'SemiStructuredObjectNewInstanceController' => 'SemiStructuredObjectTypeController', 'SemiStructuredObjectType' => array( 'SemiStructuredDAO', 'PhabricatorPolicyInterface', 'PhabricatorApplicationTransactionInterface', 'PhabricatorSubscribableInterface', 'PhabricatorFlaggableInterface', 'PhabricatorDestructibleInterface', 'PhabricatorFerretInterface', ), 'SemiStructuredObjectTypeArchiveController' => 'SemiStructuredBaseController', 'SemiStructuredObjectTypeController' => 'SemiStructuredBaseController', 'SemiStructuredObjectTypeCustomFieldsTransaction' => 'SemiStructuredObjectTypeTransactionType', 'SemiStructuredObjectTypeDescriptionTransaction' => 'SemiStructuredObjectTypeTransactionType', 'SemiStructuredObjectTypeEditController' => 'SemiStructuredBaseController', 'SemiStructuredObjectTypeEditEngine' => 'PhabricatorEditEngine', 'SemiStructuredObjectTypeFerretEngine' => 'PhabricatorFerretEngine', 'SemiStructuredObjectTypeListController' => 'SemiStructuredBaseController', 'SemiStructuredObjectTypeMailReceiver' => 'PhabricatorObjectMailReceiver', 'SemiStructuredObjectTypeNameTransaction' => 'SemiStructuredObjectTypeTransactionType', 'SemiStructuredObjectTypePHIDType' => 'PhabricatorPHIDType', 'SemiStructuredObjectTypeQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'SemiStructuredObjectTypeReplyHandler' => 'PhabricatorApplicationTransactionReplyHandler', 'SemiStructuredObjectTypeSearchEngine' => 'PhabricatorApplicationSearchEngine', 'SemiStructuredObjectTypeStatusTransaction' => 'SemiStructuredObjectTypeTransactionType', 'SemiStructuredObjectTypeTransaction' => 'PhabricatorModularTransaction', 'SemiStructuredObjectTypeTransactionComment' => 'PhabricatorApplicationTransactionComment', 'SemiStructuredObjectTypeTransactionEditor' => 'PhabricatorApplicationTransactionEditor', 'SemiStructuredObjectTypeTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'SemiStructuredObjectTypeTransactionType' => 'PhabricatorModularTransactionType', 'SemiStructuredObjectTypeViewController' => 'SemiStructuredObjectTypeController', 'SemiStructuredPatchList' => 'PhabricatorSQLPatchList', ), )); diff --git a/src/controller/instance/SemiStructuredObjectInstanceController.php b/src/controller/instance/SemiStructuredObjectInstanceController.php index 4630a25..785926f 100644 --- a/src/controller/instance/SemiStructuredObjectInstanceController.php +++ b/src/controller/instance/SemiStructuredObjectInstanceController.php @@ -1,88 +1,94 @@ object = $object; return $this; } public function getObject() { return $this->object; } // TODO ??? public function buildApplicationMenu() { return $this->buildSideNavView()->getMenu(); } protected function buildHeaderView() { $viewer = $this->getViewer(); $object = $this->getObject(); $object_type = $object->getClass(); if ($object_type->isArchived()) { $status_icon = 'fa-ban'; $status_color = 'dark'; } else { $status_icon = 'fa-check'; $status_color = 'bluegrey'; } $status_name = idx( SemiStructuredObjectType::getStatusNameMap(), $object_type->getStatus()); return id(new PHUIHeaderView()) - ->setHeader(pht('%s: %d %s', $object_type->getName(), $object->getID(), $object->getName())) + ->setHeader( + pht( + '%s: %d %s', + $object_type->getName(), + $object->getID(), + $object->getName())) ->setUser($viewer) ->setPolicyObject($object_type) ->setStatus($status_icon, $status_color, $status_name) ->setHeaderIcon('fa-trophy'); } protected function buildApplicationCrumbs() { $object = $this->getObject(); $object_type = $object->getClass(); $crumbs = parent::buildApplicationCrumbs(); $crumbs->addTextCrumb($object_type->getName(), $object_type->getURI()); - $crumbs->addTextCrumb(pht('%d %s', $object->getID(), $object->getName()), $object->getURI()); + $crumbs->addTextCrumb( + pht('%d %s', $object->getID(), $object->getName()), $object->getURI()); $crumbs->setBorder(true); return $crumbs; } protected function buildSideNavView($filter = null) { $viewer = $this->getViewer(); $object = $this->getObject(); $object_type = $object->getClass(); $id = $object->getID(); $nav = id(new AphrontSideNavFilterView()) ->setBaseURI(new PhutilURI($this->getApplicationURI())); $nav->addLabel(pht('Instance of %s', $object_type->getName())); // TODO figure out menu $nav->addFilter( 'view', pht('View Object Type'), $object_type->getURI(), 'fa-trophy'); $nav->addFilter( 'instances', pht('View Instances'), $this->getApplicationURI("/type/{$id}/items/"), 'fa-group'); $nav->selectFilter($filter); return $nav; } } diff --git a/src/customfield/SemiStructuredConfiguredCustomField.php b/src/customfield/SemiStructuredInstanceConfiguredCustomField.php similarity index 95% rename from src/customfield/SemiStructuredConfiguredCustomField.php rename to src/customfield/SemiStructuredInstanceConfiguredCustomField.php index 8b8e825..25602d9 100644 --- a/src/customfield/SemiStructuredConfiguredCustomField.php +++ b/src/customfield/SemiStructuredInstanceConfiguredCustomField.php @@ -1,37 +1,37 @@ hasAttachedClass()) { $class = $instance->getClass(); $config = $class->getCustomFieldsConfig(); } else { $config = array(); } return PhabricatorStandardCustomField::buildStandardFields($this, $config); } public function newStorageObject() { return new SemiStructuredInstanceConfiguredCustomFieldStorage(); } protected function newStringIndexStorage() { return new SemiStructuredInstanceCustomFieldStringIndex(); } protected function newNumericIndexStorage() { return new SemiStructuredInstanceCustomFieldNumericIndex(); } } diff --git a/src/editor/SemiStructuredObjectTypeEditEngine.php b/src/editor/SemiStructuredObjectTypeEditEngine.php index d59282f..1db2b99 100644 --- a/src/editor/SemiStructuredObjectTypeEditEngine.php +++ b/src/editor/SemiStructuredObjectTypeEditEngine.php @@ -1,121 +1,122 @@ getViewer(); return SemiStructuredObjectType::initializeNewObjectType($viewer); } protected function newObjectQuery() { return new SemiStructuredObjectTypeQuery(); } protected function getObjectCreateTitleText($object) { return pht('Create Object Type'); } protected function getObjectCreateButtonText($object) { return pht('Create Object Type'); } protected function getObjectCreateCancelURI($object) { return '/semistructured/'; } protected function getEditorURI() { return $this->getApplication()->getApplicationURI('editclass/'); } protected function getObjectEditTitleText($object) { return pht('Edit Object Type: %s', $object->getName()); } protected function getObjectEditShortText($object) { return pht('Edit Object Type'); } protected function getObjectCreateShortText() { return pht('Create Object Type'); } protected function getObjectName() { return pht('Object Type'); } protected function getObjectViewURI($object) { return $object->getURI(); } protected function buildCustomEditFields($object) { $custom_field_help = pht( 'See [[ %s | Custom Field Configuration ]] document '. 'for help with **%s**.', 'https://we.phorge.it/book/phorge/article/'. 'custom_fields/#custom-field-configuration', pht('Custom Fields Definition')); $fields = array( id(new PhabricatorTextEditField()) ->setKey('name') ->setLabel(pht('Name')) ->setDescription(pht('Name of the object type.')) ->setConduitDescription(pht('Rename the type.')) ->setConduitTypeDescription(pht('New type name.')) ->setTransactionType( SemiStructuredObjectTypeNameTransaction::TRANSACTIONTYPE) ->setIsRequired(true) ->setValue($object->getName()), id(new PhabricatorRemarkupEditField()) ->setKey('description') ->setLabel(pht('Description')) ->setDescription(pht('Object Type long description.')) ->setConduitTypeDescription(pht('New type description.')) ->setTransactionType( SemiStructuredObjectTypeDescriptionTransaction::TRANSACTIONTYPE) ->setValue($object->getDescription()), id(new PhabricatorInstructionsEditField()) ->setValue($custom_field_help), id(new PhabricatorTextAreaEditField()) ->setKey('customfieldsdef') ->setLabel(pht('Custom Fields Definition')) - ->setDescription(pht('Custom fields for the instances of this type(JSON).')) + ->setDescription( + pht('Custom fields for the instances of this type(JSON).')) ->setConduitTypeDescription(pht('Custom Fields Definition (JSON).')) ->setMonospaced(true) ->setIsRequired(false) ->setTransactionType( SemiStructuredObjectTypeCustomFieldsTransaction::TRANSACTIONTYPE) ->setValue( id(new PhutilJSON()) ->encodeFormatted($object->getCustomFieldsConfig())), ); return $fields; } } diff --git a/src/mail/SemiStructuredObjectInstanceReplyHandler.php b/src/mail/SemiStructuredObjectInstanceReplyHandler.php index de4a680..2dc40f7 100644 --- a/src/mail/SemiStructuredObjectInstanceReplyHandler.php +++ b/src/mail/SemiStructuredObjectInstanceReplyHandler.php @@ -1,16 +1,17 @@ objectType = $object_type; return $this; } public function getObjectType() { return $this->objectType; } public function getResultTypeDescription() { return pht('Object Instances'); } public function getApplicationClassName() { return 'SemiStructuredDataApplication'; } public function newQuery() { $query = id(new SemiStructuredObjectInstanceQuery()); if ($this->getObjectType()) { $query->withClassPhids(array($this->getObjectType()->getPHID())); } return $query; } protected function buildCustomSearchFields() { return array( // TODO object class ); } protected function getURI($path) { return '/semistruct/'.$path; } protected function getBuiltinQueryNames() { $names = array(); $names['all'] = pht('All object'); return $names; } public function buildSavedQueryFromBuiltin($query_key) { $query = $this->newSavedQuery(); $query->setQueryKey($query_key); $viewer = $this->requireViewer(); switch ($query_key) { case 'all': return $query; case 'open': return $query->setParameter( 'statuses', array( SemiStructuredObjectType::STATUS_ACTIVE, )); } return parent::buildSavedQueryFromBuiltin($query_key); } protected function buildQueryFromParameters(array $map) { $query = $this->newQuery(); // TODO type id/phid // if ($map['statuses']) { // $query->withStatuses($map['statuses']); // } // if ($map['editable'] !== null) { // $query->withCanEdit($map['editable']); // } return $query; } protected function getRequiredHandlePHIDsForResultList( array $objects, PhabricatorSavedQuery $query) { return array(); } public function renderResultsDirectly(array $items) { - return $this->renderResultList($items, new PhabricatorSavedQuery(), array()); + return $this->renderResultList( + $items, + new PhabricatorSavedQuery(), + array()); } protected function renderResultList( array $items, PhabricatorSavedQuery $query , array $handles) { $viewer = $this->requireViewer(); if ($items) { $edge_query = id(new PhabricatorEdgeQuery()) ->withSourcePHIDs(mpull($items, 'getPHID')) ->withEdgeTypes( array( PhabricatorProjectObjectHasProjectEdgeType::EDGECONST, )); $edge_query->execute(); } $list = id(new PHUIObjectItemListView()) ->setViewer($viewer); foreach ($items as $instance) { $item = id(new PHUIObjectItemView()) ->setViewer($viewer) ->setObjectName($instance->getName()) ->setHeader($instance->getName()) ->setHref($instance->getURI()) ->setObject($instance); $icon = id(new PHUIIconView()) ->setIcon($instance->getIcon()); $item->setImageIcon($icon); $item->setEpoch($instance->getDateModified()); $phid = $instance->getPHID(); $project_phids = $edge_query->getDestinationPHIDs(array($phid)); $project_handles = $viewer->loadHandles($project_phids); $item->addAttribute( id(new PHUIHandleTagListView()) ->setLimit(4) ->setNoDataString(pht('No Tags')) ->setSlim(true) ->setHandles($project_handles)); $list->addItem($item); } $result = new PhabricatorApplicationSearchResultView(); $result->setObjectList($list); $result->setNoDataString(pht('No objects found.')); return $result; } } diff --git a/src/xaction/class/SemiStructuredObjectTypeCustomFieldsTransaction.php b/src/xaction/class/SemiStructuredObjectTypeCustomFieldsTransaction.php index de54ad7..71eb5d8 100644 --- a/src/xaction/class/SemiStructuredObjectTypeCustomFieldsTransaction.php +++ b/src/xaction/class/SemiStructuredObjectTypeCustomFieldsTransaction.php @@ -1,87 +1,88 @@ encodeFormatted($object->getCustomFieldsConfig()); } public function applyInternalEffects($object, $value) { if ($value !== null && strlen($value)) { $value = phutil_json_decode($value); } $object->setCustomFieldsConfig($value); } public function getTitle() { return pht( '%s updated the custom fields definition of the object type.', $this->renderAuthor()); } public function getTitleForFeed() { return pht( '%s updated the custom fields definition for object type %s.', $this->renderAuthor(), $this->renderObject()); } public function getMailDiffSectionHeader() { return pht('CHANGES TO CUSTOM FIELDS DEFINITION OF OBJECT TYPE'); } public function hasChangeDetailView() { return true; } public function newChangeDetailView() { $viewer = $this->getViewer(); $old = $this->getOldValue(); $new = $this->getNewValue(); return id(new PhabricatorApplicationTransactionTextDiffDetailView()) ->setViewer($viewer) ->setOldText($old) ->setNewText($new); } public function validateTransactions($object, array $xactions) { $errors = array(); if (!$xactions) { return $errors; } $json_parser = new PhutilJSONParser(); - if ($this->isEmptyTextTransaction($object->getCustomFieldsConfig(), $xactions)) { + if ($this->isEmptyTextTransaction( + $object->getCustomFieldsConfig(), $xactions)) { // TODO custom fields are optional. // $errors[] = $this->newRequiredError( // pht('Object must have content.')); } foreach ($xactions as $xaction) { $new_value = $xaction->getNewValue(); try { if (strlen($new_value)) { phutil_json_decode($new_value); } } catch (PhutilJSONParserException $ex) { $errors[] = $this->newInvalidError( pht('Definition must be valid json!')); } } return $errors; } }