diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 4f79c9b..b3b2e34 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -1,95 +1,97 @@ 2, 'class' => array( 'SemiStructuredBaseController' => 'applications/semistruct/controller/SemiStructuredBaseController.php', 'SemiStructuredDAO' => 'applications/semistruct/storage/SemiStructuredDAO.php', 'SemiStructuredDataApplication' => 'applications/semistruct/application/SemiStructuredDataApplication.php', 'SemiStructuredObjectInstance' => 'applications/semistruct/storage/SemiStructuredObjectInstance.php', 'SemiStructuredObjectInstanceClassTransaction' => 'applications/semistruct/xaction/instance/SemiStructuredObjectInstanceClassTransaction.php', 'SemiStructuredObjectInstanceController' => 'applications/semistruct/controller/instance/SemiStructuredObjectInstanceController.php', 'SemiStructuredObjectInstanceEditController' => 'applications/semistruct/controller/instance/SemiStructuredObjectInstanceEditController.php', 'SemiStructuredObjectInstanceEditEngine' => 'applications/semistruct/editor/SemiStructuredObjectInstanceEditEngine.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', + 'SemiStructuredObjectInstanceSearchEngine' => 'applications/semistruct/query/SemiStructuredObjectInstanceSearchEngine.php', 'SemiStructuredObjectInstanceTransaction' => 'applications/semistruct/storage/SemiStructuredObjectInstanceTransaction.php', 'SemiStructuredObjectInstanceTransactionEditor' => 'applications/semistruct/editor/SemiStructuredObjectInstanceTransactionEditor.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', 'SemiStructuredObjectTypeController' => 'applications/semistruct/controller/class/SemiStructuredObjectTypeController.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', 'SemiStructuredObjectTypeNameTransaction' => 'applications/semistruct/xaction/class/SemiStructuredObjectTypeNameTransaction.php', 'SemiStructuredObjectTypePHIDType' => 'applications/semistruct/phid/SemiStructuredObjectTypePHIDType.php', 'SemiStructuredObjectTypeQuery' => 'applications/semistruct/query/SemiStructuredObjectTypeQuery.php', 'SemiStructuredObjectTypeSearchEngine' => 'applications/semistruct/query/SemiStructuredObjectTypeSearchEngine.php', 'SemiStructuredObjectTypeTransaction' => 'applications/semistruct/storage/SemiStructuredObjectTypeTransaction.php', 'SemiStructuredObjectTypeTransactionEditor' => 'applications/semistruct/editor/SemiStructuredObjectTypeTransactionEditor.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', 'SemiStructuredObjectInstance' => array( 'SemiStructuredDAO', 'PhabricatorPolicyInterface', 'PhabricatorApplicationTransactionInterface', 'PhabricatorFlaggableInterface', 'PhabricatorDestructibleInterface', ), 'SemiStructuredObjectInstanceClassTransaction' => 'SemiStructuredObjectInstanceTransactionType', 'SemiStructuredObjectInstanceController' => 'SemiStructuredBaseController', 'SemiStructuredObjectInstanceEditController' => 'SemiStructuredBaseController', 'SemiStructuredObjectInstanceEditEngine' => 'PhabricatorEditEngine', 'SemiStructuredObjectInstanceNameTransaction' => 'SemiStructuredObjectInstanceTransactionType', 'SemiStructuredObjectInstancePHIDType' => 'PhabricatorPHIDType', 'SemiStructuredObjectInstanceQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'SemiStructuredObjectInstanceRawDataTransaction' => 'SemiStructuredObjectInstanceTransactionType', + 'SemiStructuredObjectInstanceSearchEngine' => 'PhabricatorApplicationSearchEngine', 'SemiStructuredObjectInstanceTransaction' => 'PhabricatorModularTransaction', 'SemiStructuredObjectInstanceTransactionEditor' => 'PhabricatorApplicationTransactionEditor', 'SemiStructuredObjectInstanceTransactionType' => 'PhabricatorModularTransactionType', 'SemiStructuredObjectInstanceViewController' => 'SemiStructuredObjectInstanceController', 'SemiStructuredObjectNewInstanceController' => 'SemiStructuredObjectTypeController', 'SemiStructuredObjectType' => array( 'SemiStructuredDAO', 'PhabricatorPolicyInterface', 'PhabricatorApplicationTransactionInterface', 'PhabricatorFlaggableInterface', 'PhabricatorDestructibleInterface', 'PhabricatorFerretInterface', ), 'SemiStructuredObjectTypeController' => 'SemiStructuredBaseController', 'SemiStructuredObjectTypeDescriptionTransaction' => 'SemiStructuredObjectTypeTransactionType', 'SemiStructuredObjectTypeEditController' => 'SemiStructuredBaseController', 'SemiStructuredObjectTypeEditEngine' => 'PhabricatorEditEngine', 'SemiStructuredObjectTypeFerretEngine' => 'PhabricatorFerretEngine', 'SemiStructuredObjectTypeListController' => 'SemiStructuredBaseController', 'SemiStructuredObjectTypeNameTransaction' => 'SemiStructuredObjectTypeTransactionType', 'SemiStructuredObjectTypePHIDType' => 'PhabricatorPHIDType', 'SemiStructuredObjectTypeQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'SemiStructuredObjectTypeSearchEngine' => 'PhabricatorApplicationSearchEngine', 'SemiStructuredObjectTypeTransaction' => 'PhabricatorModularTransaction', 'SemiStructuredObjectTypeTransactionEditor' => 'PhabricatorApplicationTransactionEditor', 'SemiStructuredObjectTypeTransactionType' => 'PhabricatorModularTransactionType', 'SemiStructuredObjectTypeViewController' => 'SemiStructuredObjectTypeController', 'SemiStructuredPatchList' => 'PhabricatorSQLPatchList', ), )); diff --git a/src/controller/class/SemiStructuredObjectTypeViewController.php b/src/controller/class/SemiStructuredObjectTypeViewController.php index d89fa34..4521ac4 100644 --- a/src/controller/class/SemiStructuredObjectTypeViewController.php +++ b/src/controller/class/SemiStructuredObjectTypeViewController.php @@ -1,126 +1,166 @@ 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 PhabricatorBadgesTransactionQuery()); /// TODO $timeline = null; $comment_view = id(new SemiStructuredObjectTypeEditEngine()) ->setViewer($viewer) ->buildEditEngineCommentView($object_type); + $instances_view = $this->buildInstancesView(); + $view = id(new PHUITwoColumnView()) ->setHeader($header) ->setCurtain($curtain) ->setMainColumn(array( - // TODO add instance list here + $instances_view, $timeline, $comment_view, )) ->addPropertySection(pht('Description'), $details); $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)); } 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("/archive/{$id}/"); $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) + ->withClassIds(array($object_type->getId())) + ->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; + + + } + } diff --git a/src/controller/instance/SemiStructuredObjectInstanceController.php b/src/controller/instance/SemiStructuredObjectInstanceController.php index f046d57..4e7a41a 100644 --- a/src/controller/instance/SemiStructuredObjectInstanceController.php +++ b/src/controller/instance/SemiStructuredObjectInstanceController.php @@ -1,88 +1,88 @@ 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'); } 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("/recipients/{$id}/"), 'fa-group'); $nav->selectFilter($filter); return $nav; } } diff --git a/src/query/SemiStructuredObjectInstanceQuery.php b/src/query/SemiStructuredObjectInstanceQuery.php index be4edde..54687e7 100644 --- a/src/query/SemiStructuredObjectInstanceQuery.php +++ b/src/query/SemiStructuredObjectInstanceQuery.php @@ -1,119 +1,119 @@ ids = $ids; return $this; } public function withPHIDs(array $phids) { $this->phids = $phids; return $this; } - public function withClassPHIDs(array $class_phids) { - $this->classPHIDs = $class_phids; + public function withClassIDs(array $class_ids) { + $this->classIDs = $class_ids; return $this; } public function withStatuses(array $statuses) { $this->statuses = $statuses; return $this; } public function withCanEdit($can_edit) { $this->canEdit = $can_edit; return $this; } public function newResultObject() { return new SemiStructuredObjectInstance(); } protected function didFilterPage(array $items) { $phids = mpull($items, 'getPHID'); if ($this->canEdit) { $items = id(new PhabricatorPolicyFilter()) ->setViewer($this->getViewer()) ->requireCapabilities(array( PhabricatorPolicyCapability::CAN_EDIT, )) ->apply($items); } return $items; } protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) { $where = parent::buildWhereClauseParts($conn); if ($this->ids !== null) { $where[] = qsprintf( $conn, 'instances.id IN (%Ld)', $this->ids); } if ($this->phids !== null) { $where[] = qsprintf( $conn, 'instances.phid IN (%Ls)', $this->phids); } - if ($this->classPHIDs !== null) { + if ($this->classIDs !== null) { $where[] = qsprintf( $conn, - 'instances.classPHID IN (%Ls)', - $this->phids); + 'instances.classID IN (%Ls)', + $this->classIDs); } if ($this->statuses !== null) { $where[] = qsprintf( $conn, 'instances.status IN (%Ls)', $this->statuses); } return $where; } protected function willFilterPage(array $objects) { $classes = id(new SemiStructuredObjectTypeQuery()) ->setViewer($this->getViewer()) ->withIDs(mpull($objects, 'getClassID')) ->execute(); foreach ($objects as $key => $object) { $class = idx($classes, $object->getClassID()); if (!$class) { unset($objects[$key]); continue; } $object->attachClass($class); } return $objects; } public function getQueryApplicationClass() { return 'SemiStructuredDataApplication'; } protected function getPrimaryTableAlias() { return 'instances'; } } diff --git a/src/query/SemiStructuredObjectInstanceSearchEngine.php b/src/query/SemiStructuredObjectInstanceSearchEngine.php new file mode 100644 index 0000000..1177baa --- /dev/null +++ b/src/query/SemiStructuredObjectInstanceSearchEngine.php @@ -0,0 +1,141 @@ +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(); + + // 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()); + } + + 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); + + $bg_color = 'bg-dark'; + + $icon = id(new PHUIIconView()) + ->setIcon($instance->getIcon()) + ->setBackground($bg_color); + $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/storage/SemiStructuredObjectInstance.php b/src/storage/SemiStructuredObjectInstance.php index 762dedb..0b8de71 100644 --- a/src/storage/SemiStructuredObjectInstance.php +++ b/src/storage/SemiStructuredObjectInstance.php @@ -1,137 +1,142 @@ setViewPolicy(PhabricatorPolicies::getMostOpenPolicy()) // TODO take policies from class? // ->setEditPolicy($actor->getPHID()) ->setStatus(self::STATUS_ACTIVE); if ($object_class !== null) { $object ->setClassID($object_class->getID()) ->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 getURI() { return urisprintf('/semistruct/instance/%d/', $this->getID()); } + public function getIcon() { + // TODO + return 'fa-google'; + } + 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_COLUMN_SCHEMA => array( 'name' => 'sort255', 'status' => 'text32', 'rawData' => 'text', ), self::CONFIG_KEY_SCHEMA => array( 'classID' => array( 'columns' => array('classID'), ), ), ) + 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; 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; } /* -( PhabricatorDestructibleInterface )----------------------------------- */ public function destroyObjectPermanently( PhabricatorDestructionEngine $engine) { $this->openTransaction(); $this->delete(); $this->saveTransaction(); } }