diff --git a/src/application/SemiStructuredDataApplication.php b/src/application/SemiStructuredDataApplication.php index 1838298..52884e7 100644 --- a/src/application/SemiStructuredDataApplication.php +++ b/src/application/SemiStructuredDataApplication.php @@ -1,58 +1,65 @@ array( '(?:query/(?P[^/]+)/)?' => 'SemiStructuredObjectTypeListController', $this->getEditRoutePattern('editclass/') => 'SemiStructuredObjectTypeEditController', 'type/(?:(?P\d+)/)?' => array( '' => 'SemiStructuredObjectTypeViewController', 'items/' => 'SemiStructuredObjectInstanceListController', '(?:query/(?P[^/]+)/)?' => 'SemiStructuredObjectInstanceListController', 'archive/' => 'SemiStructuredObjectTypeArchiveController', ), // If the ID field is called `id`, the EditEngine thinks this is // editing an existing object. 'type/(?:(?P\d+)/)?' => array( 'new/' => 'SemiStructuredObjectNewInstanceController', ), $this->getEditRoutePattern('editinstance/') => 'SemiStructuredObjectInstanceEditController', 'instance/(?:(?P\d+)/)?' => 'SemiStructuredObjectInstanceViewController', ), ); } } diff --git a/src/controller/class/SemiStructuredObjectTypeController.php b/src/controller/class/SemiStructuredObjectTypeController.php index c997967..8b206cf 100644 --- a/src/controller/class/SemiStructuredObjectTypeController.php +++ b/src/controller/class/SemiStructuredObjectTypeController.php @@ -1,89 +1,89 @@ objectType = $object_type; return $this; } public function getObjectType() { return $this->objectType; } // TODO ??? public function buildApplicationMenu() { return $this->buildSideNavView()->getMenu(); } protected function buildHeaderView() { $viewer = $this->getViewer(); $object_type = $this->getObjectType(); 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($object_type->getName()) ->setUser($viewer) ->setPolicyObject($object_type) ->setStatus($status_icon, $status_color, $status_name) - ->setHeaderIcon('fa-trophy'); + ->setHeaderIcon(SemiStructuredDataApplication::ICON_OBJECT_TYPE); } protected function buildApplicationCrumbs() { $object_type = $this->getObjectType(); $uri = $object_type->getURI(); $crumbs = parent::buildApplicationCrumbs(); $crumbs->addTextCrumb($object_type->getName(), $uri); $crumbs->setBorder(true); return $crumbs; } protected function buildSideNavView($filter = null) { $viewer = $this->getViewer(); $object_type = $this->getObjectType(); $id = $object_type->getID(); $can_edit = PhabricatorPolicyFilter::hasCapability( $viewer, $object_type, PhabricatorPolicyCapability::CAN_EDIT); $nav = id(new AphrontSideNavFilterView()) ->setBaseURI(new PhutilURI($this->getApplicationURI())); $nav->addLabel(pht('Object Type')); $nav->addFilter( 'view', pht('View Object Type'), $object_type->getURI(), - 'fa-trophy'); + SemiStructuredDataApplication::ICON_OBJECT_TYPE); $nav->addFilter( 'instances', pht('View Instances'), $this->getApplicationURI("/type/{$id}/items/"), 'fa-group'); $nav->selectFilter($filter); return $nav; } } diff --git a/src/controller/class/SemiStructuredObjectTypeViewController.php b/src/controller/class/SemiStructuredObjectTypeViewController.php index 105322b..35bc88f 100644 --- a/src/controller/class/SemiStructuredObjectTypeViewController.php +++ b/src/controller/class/SemiStructuredObjectTypeViewController.php @@ -1,174 +1,185 @@ getViewer(); $id = $request->getURIData('id'); $object_type = id(new SemiStructuredObjectTypeQuery()) ->setViewer($viewer) ->withIDs(array($id)) ->executeOne(); if (!$object_type) { return new Aphront404Response(); } $this->setObjectType($object_type); $crumbs = $this->buildApplicationCrumbs(); $title = $object_type->getName(); $header = $this->buildHeaderView(); $curtain = $this->buildCurtain(); $details = $this->buildDetailsView(); $timeline = $this->buildTransactionTimeline( $object_type, new SemiStructuredObjectTypeTransactionQuery()); $comment_view = id(new SemiStructuredObjectTypeEditEngine()) ->setViewer($viewer) ->buildEditEngineCommentView($object_type); - $instances_view = $this->buildInstancesView(); + list($instances_header, $instances_view) = $this->buildInstancesView(); $view = id(new PHUITwoColumnView()) ->setHeader($header) ->setCurtain($curtain) ->setMainColumn(array( - $instances_view, $timeline, $comment_view, - )) - ->addPropertySection(pht('Description'), $details); + )) + ->addPropertySection(pht('Description'), $details) + ->addPropertySection($instances_header, $instances_view); $navigation = $this->buildSideNavView('view'); return $this->newPage() ->setTitle($title) ->setCrumbs($crumbs) ->setPageObjectPHIDs(array($object_type->getPHID())) ->setNavigation($navigation) ->appendChild($view); } private function buildDetailsView() { $viewer = $this->getViewer(); $object_type = $this->getObjectType(); $view = id(new PHUIPropertyListView()) ->setUser($viewer); $description = $object_type->getDescription(); if (strlen($description)) { $view->addTextContent( new PHUIRemarkupView($viewer, $description)); } $custom_fields_def = $object_type->getCustomFieldsConfig(); $custom_fields_def = id(new PhutilJSON()) ->encodeFormatted($custom_fields_def); $view->addProperty( pht('Custom Fields'), phutil_tag('pre', array(), $custom_fields_def)); return $view; } private function buildCurtain() { $viewer = $this->getViewer(); $object_type = $this->getObjectType(); $can_edit = PhabricatorPolicyFilter::hasCapability( $viewer, $object_type, PhabricatorPolicyCapability::CAN_EDIT); $can_create_instance = true; $id = $object_type->getID(); $edit_uri = $this->getApplicationURI("/editclass/{$id}/"); $create_uri = $this->getApplicationURI("/type/{$id}/new/"); $archive_uri = $this->getApplicationURI("/type/{$id}/archive/"); $curtain = $this->newCurtainView($object_type); $curtain->addAction( id(new PhabricatorActionView()) ->setName(pht('Edit Object Type')) ->setIcon('fa-pencil') ->setDisabled(!$can_edit) ->setHref($edit_uri)); $curtain->addAction( id(new PhabricatorActionView()) ->setName(pht('Create New Instance')) ->setIcon('fa-plus') ->setDisabled(!$can_create_instance) ->setHref($create_uri)); if ($object_type->isArchived()) { $curtain->addAction( id(new PhabricatorActionView()) ->setName(pht('Activate Object Type')) ->setIcon('fa-check') ->setDisabled(!$can_edit) ->setWorkflow($can_edit) ->setHref($archive_uri)); } else { $curtain->addAction( id(new PhabricatorActionView()) ->setName(pht('Archive Object Type')) ->setIcon('fa-ban') ->setDisabled(!$can_edit) ->setWorkflow($can_edit) ->setHref($archive_uri)); } return $curtain; } private function buildInstancesView() { $viewer = $this->getViewer(); $object_type = $this->getObjectType(); $instances = id(new SemiStructuredObjectInstanceQuery()) ->setViewer($viewer) ->setLimit(10) ->withClassPHIDs(array($object_type->getPHID())) ->execute(); $content = id(new SemiStructuredObjectInstanceSearchEngine()) ->setViewer($viewer) ->renderResultsDirectly($instances); // $content is PhabricatorApplicationSearchResultView $box = new PHUIObjectBoxView(); - $interface = 'PhabricatorApplicationSearchResultView'; if ($content->getObjectList()) { $box->setObjectList($content->getObjectList()); } if ($content->getTable()) { $box->setTable($content->getTable()); } if ($content->getContent()) { $box->appendChild($content->getContent()); } - $box - ->setHeader(pht('Instances of this type')); - - return $box; + $header = pht('Instances of this type'); + $header = (new PHUIHeaderView()) + ->setHeader($header) + ->addActionLink((new PHUIButtonView()) + ->setText(pht("All Instances")) + ->setIcon(SemiStructuredDataApplication::ICON_OBJECT_INSTANCE_MANY) + ->setHref("./items/") + ->setTag('a') + ->setButtonType(PHUIButtonView::BUTTONTYPE_SIMPLE)) + ->addActionLink((new PHUIButtonView()) + ->setText(pht("Create New")) + ->setIcon('fa-plus') + ->setHref("./new/") + ->setTag('a') + ->setButtonType(PHUIButtonView::BUTTONTYPE_SIMPLE)); + return array($header, $box); } } diff --git a/src/controller/instance/SemiStructuredObjectInstanceController.php b/src/controller/instance/SemiStructuredObjectInstanceController.php index 785926f..69b14ff 100644 --- a/src/controller/instance/SemiStructuredObjectInstanceController.php +++ b/src/controller/instance/SemiStructuredObjectInstanceController.php @@ -1,94 +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())) ->setUser($viewer) ->setPolicyObject($object_type) ->setStatus($status_icon, $status_color, $status_name) - ->setHeaderIcon('fa-trophy'); + ->setHeaderIcon(SemiStructuredDataApplication::ICON_OBJECT_TYPE); } 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->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'); + SemiStructuredDataApplication::ICON_OBJECT_TYPE); $nav->addFilter( 'instances', pht('View Instances'), $this->getApplicationURI("/type/{$id}/items/"), 'fa-group'); $nav->selectFilter($filter); return $nav; } } diff --git a/src/storage/SemiStructuredObjectInstance.php b/src/storage/SemiStructuredObjectInstance.php index ddb3920..9fdb9f7 100644 --- a/src/storage/SemiStructuredObjectInstance.php +++ b/src/storage/SemiStructuredObjectInstance.php @@ -1,180 +1,180 @@ setViewPolicy(PhabricatorPolicies::getMostOpenPolicy()) // TODO take policies from class? // ->setEditPolicy($actor->getPHID()) ->setStatus(self::STATUS_ACTIVE); if ($object_class !== null) { $object ->setClassPHID($object_class->getPHID()) ->attachClass($object_class); } return $object; } public function attachClass( SemiStructuredObjectType $object_class = null) { $this->class = $object_class; return $this; } public function getClass() { return $this->assertAttached($this->class); } public function hasAttachedClass() { return $this->class !== self::ATTACHABLE; } public function getURI() { return urisprintf('/semistruct/instance/%d/', $this->getID()); } public function getIcon() { // TODO customize in Type - return 'fa-dribbble'; + return SemiStructuredDataApplication::ICON_OBJECT_INSTANCE; } public static function getStatusNameMap() { return array( // TODO remove this self::STATUS_ACTIVE => pht('Active'), self::STATUS_ARCHIVED => pht('Archived'), ); } protected function getConfiguration() { return array( self::CONFIG_AUX_PHID => true, self::CONFIG_SERIALIZATION => array( 'rawData' => self::SERIALIZATION_JSON, ), self::CONFIG_COLUMN_SCHEMA => array( 'name' => 'sort255', 'description' => 'text', 'status' => 'text32', ), self::CONFIG_KEY_SCHEMA => array( 'classPHID' => array( 'columns' => array('classPHID'), ), ), ) + parent::getConfiguration(); } public function getPHIDType() { return SemiStructuredObjectInstancePHIDType::TYPECONST; } /* -( PhabricatorApplicationTransactionInterface )------------------------- */ public function getApplicationTransactionEditor() { return new SemiStructuredObjectInstanceTransactionEditor(); } public function getApplicationTransactionTemplate() { return new SemiStructuredObjectInstanceTransaction(); } /* -( PhabricatorPolicyInterface )----------------------------------------- */ public function getCapabilities() { return array( PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT, ); } public function getPolicy($capability) { return ''; // TODO switch ($capability) { // TODO case PhabricatorPolicyCapability::CAN_VIEW: return $this->getViewPolicy(); case PhabricatorPolicyCapability::CAN_EDIT: return $this->getEditPolicy(); } } public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { return true; } /* -( PhabricatorCustomFieldInterface )------------------------------------ */ public function getCustomFieldSpecificationForRole($role) { return PhabricatorEnv::getEnvConfig('user.fields'); } public function getCustomFieldBaseClass() { return 'SemiStructuredInstanceCustomField'; } public function getCustomFields() { return $this->assertAttached($this->customFields); } public function attachCustomFields(PhabricatorCustomFieldAttachment $fields) { $this->customFields = $fields; return $this; } /* -( PhabricatorDestructibleInterface )----------------------------------- */ public function destroyObjectPermanently( PhabricatorDestructionEngine $engine) { $this->openTransaction(); $this->delete(); $this->saveTransaction(); } /* -( PhabricatorSubscribableInterface )----------------------------------- */ public function isAutomaticallySubscribed($phid) { return false; } } diff --git a/src/storage/SemiStructuredObjectType.php b/src/storage/SemiStructuredObjectType.php index d97e745..2013dde 100644 --- a/src/storage/SemiStructuredObjectType.php +++ b/src/storage/SemiStructuredObjectType.php @@ -1,155 +1,155 @@ setName('') ->setViewPolicy(PhabricatorPolicies::getMostOpenPolicy()) ->setEditPolicy($actor->getPHID()) ->setStatus(self::STATUS_ACTIVE); } public function getCustomFieldsConfig() { if (!$this->customFieldsConfig) { return array(); } return $this->customFieldsConfig; } public static function getStatusNameMap() { return array( self::STATUS_ACTIVE => pht('Active'), self::STATUS_ARCHIVED => pht('Archived'), ); } protected function getConfiguration() { return array( self::CONFIG_AUX_PHID => true, self::CONFIG_SERIALIZATION => array( 'customFieldsConfig' => self::SERIALIZATION_JSON, ), self::CONFIG_COLUMN_SCHEMA => array( 'name' => 'sort255', 'status' => 'text32', 'description' => 'text', ), ) + parent::getConfiguration(); } public function getPHIDType() { return SemiStructuredObjectTypePHIDType::TYPECONST; } public function isArchived() { return ($this->getStatus() == self::STATUS_ARCHIVED); } public function getURI() { return urisprintf('/semistruct/type/%d/', $this->getID()); } public function getObjectName() { return pht('Object Type %d', $this->getID()); } public function getIcon() { // TODO copy the feature from Projects, where you can put a custom image // or select from a list. - return 'fa-camera'; + return SemiStructuredDataApplication::ICON_OBJECT_TYPE; } /* -( PhabricatorApplicationTransactionInterface )------------------------- */ public function getApplicationTransactionEditor() { return new SemiStructuredObjectTypeTransactionEditor(); } public function getApplicationTransactionTemplate() { return new SemiStructuredObjectTypeTransaction(); } /* -( PhabricatorPolicyInterface )----------------------------------------- */ public function getCapabilities() { return array( PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT, // TODO can-create-instances ); } public function getPolicy($capability) { switch ($capability) { case PhabricatorPolicyCapability::CAN_VIEW: return $this->getViewPolicy(); case PhabricatorPolicyCapability::CAN_EDIT: return $this->getEditPolicy(); } } public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { return false; } /* -( PhabricatorDestructibleInterface )----------------------------------- */ public function destroyObjectPermanently( PhabricatorDestructionEngine $engine) { $this->openTransaction(); $this->delete(); $this->saveTransaction(); } /* -( PhabricatorSubscribableInterface )----------------------------------- */ public function isAutomaticallySubscribed($phid) { return false; } /* -( PhabricatorFerretInterface )----------------------------------------- */ public function newFerretEngine() { return new SemiStructuredObjectTypeFerretEngine(); } }