diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -5622,6 +5622,7 @@ 'PhabricatorPolicyInterface', 'PhabricatorFlaggableInterface', 'PhabricatorDestructibleInterface', + 'PhabricatorProjectInterface', ), 'PhabricatorDashboardAddPanelController' => 'PhabricatorDashboardController', 'PhabricatorDashboardApplication' => 'PhabricatorApplication', @@ -5644,6 +5645,7 @@ 'PhabricatorPolicyInterface', 'PhabricatorCustomFieldInterface', 'PhabricatorFlaggableInterface', + 'PhabricatorProjectInterface', 'PhabricatorDestructibleInterface', ), 'PhabricatorDashboardPanelArchiveController' => 'PhabricatorDashboardController', diff --git a/src/applications/dashboard/controller/PhabricatorDashboardEditController.php b/src/applications/dashboard/controller/PhabricatorDashboardEditController.php --- a/src/applications/dashboard/controller/PhabricatorDashboardEditController.php +++ b/src/applications/dashboard/controller/PhabricatorDashboardEditController.php @@ -27,7 +27,10 @@ if (!$dashboard) { return new Aphront404Response(); } - + $v_projects = PhabricatorEdgeQuery::loadDestinationPHIDs( + $dashboard->getPHID(), + PhabricatorProjectObjectHasProjectEdgeType::EDGECONST); + $v_projects = array_reverse($v_projects); $is_new = false; } else { if (!$request->getStr('edit')) { @@ -44,7 +47,7 @@ } $dashboard = PhabricatorDashboard::initializeNewDashboard($viewer); - + $v_projects = array(); $is_new = true; } @@ -79,6 +82,7 @@ $v_layout_mode = $request->getStr('layout_mode'); $v_view_policy = $request->getStr('viewPolicy'); $v_edit_policy = $request->getStr('editPolicy'); + $v_projects = $request->getArr('projects'); $xactions = array(); @@ -100,6 +104,12 @@ ->setTransactionType($type_edit_policy) ->setNewValue($v_edit_policy); + $proj_edge_type = PhabricatorProjectObjectHasProjectEdgeType::EDGECONST; + $xactions[] = id(new PhabricatorDashboardTransaction()) + ->setTransactionType(PhabricatorTransactions::TYPE_EDGE) + ->setMetadataValue('edge:type', $proj_edge_type) + ->setNewValue(array('=' => array_fuse($v_projects))); + try { $editor = id(new PhabricatorDashboardTransactionEditor()) ->setActor($viewer) @@ -153,8 +163,16 @@ ->setLabel(pht('Layout Mode')) ->setName('layout_mode') ->setValue($v_layout_mode) - ->setOptions($layout_mode_options)) - ->appendChild( + ->setOptions($layout_mode_options)); + + $form->appendControl( + id(new AphrontFormTokenizerControl()) + ->setLabel(pht('Projects')) + ->setName('projects') + ->setValue($v_projects) + ->setDatasource(new PhabricatorProjectDatasource())); + + $form->appendChild( id(new AphrontFormSubmitControl()) ->setValue($button) ->addCancelButton($cancel_uri)); diff --git a/src/applications/dashboard/controller/PhabricatorDashboardManageController.php b/src/applications/dashboard/controller/PhabricatorDashboardManageController.php --- a/src/applications/dashboard/controller/PhabricatorDashboardManageController.php +++ b/src/applications/dashboard/controller/PhabricatorDashboardManageController.php @@ -170,6 +170,8 @@ pht('Panels'), $viewer->renderHandleList($dashboard->getPanelPHIDs())); + $properties->invokeWillRenderEvent(); + return $properties; } diff --git a/src/applications/dashboard/controller/PhabricatorDashboardPanelEditController.php b/src/applications/dashboard/controller/PhabricatorDashboardPanelEditController.php --- a/src/applications/dashboard/controller/PhabricatorDashboardPanelEditController.php +++ b/src/applications/dashboard/controller/PhabricatorDashboardPanelEditController.php @@ -57,6 +57,10 @@ if (!$panel) { return new Aphront404Response(); } + $v_projects = PhabricatorEdgeQuery::loadDestinationPHIDs( + $panel->getPHID(), + PhabricatorProjectObjectHasProjectEdgeType::EDGECONST); + $v_projects = array_reverse($v_projects); if ($dashboard) { $can_edit = PhabricatorPolicyFilter::hasCapability( @@ -86,6 +90,7 @@ if (empty($types[$type])) { return $this->processPanelTypeRequest($request); } + $v_projects = array(); $panel->setPanelType($type); } @@ -136,6 +141,7 @@ $v_name = $request->getStr('name'); $v_view_policy = $request->getStr('viewPolicy'); $v_edit_policy = $request->getStr('editPolicy'); + $v_projects = $request->getArr('projects'); $type_name = PhabricatorDashboardPanelTransaction::TYPE_NAME; $type_view_policy = PhabricatorTransactions::TYPE_VIEW_POLICY; @@ -155,6 +161,12 @@ ->setTransactionType($type_edit_policy) ->setNewValue($v_edit_policy); + $proj_edge_type = PhabricatorProjectObjectHasProjectEdgeType::EDGECONST; + $xactions[] = id(new PhabricatorDashboardPanelTransaction()) + ->setTransactionType(PhabricatorTransactions::TYPE_EDGE) + ->setMetadataValue('edge:type', $proj_edge_type) + ->setNewValue(array('=' => array_fuse($v_projects))); + $field_xactions = $field_list->buildFieldTransactionsFromRequest( new PhabricatorDashboardPanelTransaction(), $request); @@ -232,6 +244,13 @@ ->setCapability(PhabricatorPolicyCapability::CAN_EDIT) ->setPolicies($policies)); + $form->appendControl( + id(new AphrontFormTokenizerControl()) + ->setLabel(pht('Projects')) + ->setName('projects') + ->setValue($v_projects) + ->setDatasource(new PhabricatorProjectDatasource())); + $field_list->appendFieldsToForm($form); $crumbs = $this->buildApplicationCrumbs(); diff --git a/src/applications/dashboard/query/PhabricatorDashboardPanelQuery.php b/src/applications/dashboard/query/PhabricatorDashboardPanelQuery.php --- a/src/applications/dashboard/query/PhabricatorDashboardPanelQuery.php +++ b/src/applications/dashboard/query/PhabricatorDashboardPanelQuery.php @@ -29,54 +29,53 @@ } protected function loadPage() { - $table = new PhabricatorDashboardPanel(); - $conn_r = $table->establishConnection('r'); - - $data = queryfx_all( - $conn_r, - 'SELECT * FROM %T %Q %Q %Q', - $table->getTableName(), - $this->buildWhereClause($conn_r), - $this->buildOrderClause($conn_r), - $this->buildLimitClause($conn_r)); - - return $table->loadAllFromArray($data); + return $this->loadStandardPage($this->newResultObject()); } - protected function buildWhereClause(AphrontDatabaseConnection $conn_r) { - $where = array(); + public function newResultObject() { + // TODO: If we don't do this, SearchEngine explodes when trying to + // enumerate custom fields. For now, just give the panel a default panel + // type so custom fields work. In the long run, we may want to find a + // cleaner or more general approach for this. + $text_type = id(new PhabricatorDashboardTextPanelType()) + ->getPanelTypeKey(); + + return id(new PhabricatorDashboardPanel()) + ->setPanelType($text_type); + } + + protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) { + $where = parent::buildWhereClauseParts($conn); if ($this->ids !== null) { $where[] = qsprintf( - $conn_r, + $conn, 'id IN (%Ld)', $this->ids); } if ($this->phids !== null) { $where[] = qsprintf( - $conn_r, + $conn, 'phid IN (%Ls)', $this->phids); } if ($this->archived !== null) { $where[] = qsprintf( - $conn_r, + $conn, 'isArchived = %d', (int)$this->archived); } if ($this->panelTypes !== null) { $where[] = qsprintf( - $conn_r, + $conn, 'panelType IN (%Ls)', $this->panelTypes); } - $where[] = $this->buildPagingClause($conn_r); - - return $this->formatWhereClause($where); + return $where; } public function getQueryApplicationClass() { diff --git a/src/applications/dashboard/query/PhabricatorDashboardPanelSearchEngine.php b/src/applications/dashboard/query/PhabricatorDashboardPanelSearchEngine.php --- a/src/applications/dashboard/query/PhabricatorDashboardPanelSearchEngine.php +++ b/src/applications/dashboard/query/PhabricatorDashboardPanelSearchEngine.php @@ -11,66 +11,48 @@ return 'PhabricatorDashboardApplication'; } - public function buildSavedQueryFromRequest(AphrontRequest $request) { - $saved = new PhabricatorSavedQuery(); - $saved->setParameter('status', $request->getStr('status')); - $saved->setParameter('paneltype', $request->getStr('paneltype')); - return $saved; + public function newQuery() { + return new PhabricatorDashboardPanelQuery(); } - public function buildQueryFromSavedQuery(PhabricatorSavedQuery $saved) { - $query = id(new PhabricatorDashboardPanelQuery()); - - $status = $saved->getParameter('status'); - switch ($status) { - case 'active': - $query->withArchived(false); - break; - case 'archived': - $query->withArchived(true); - break; - default: - break; + protected function buildQueryFromParameters(array $map) { + $query = $this->newQuery(); + if ($map['status']) { + switch ($map['status']) { + case 'active': + $query->withArchived(false); + break; + case 'archived': + $query->withArchived(true); + break; + default: + break; + } } - $paneltype = $saved->getParameter('paneltype'); - if ($paneltype) { - $query->withPanelTypes(array($paneltype)); + if ($map['paneltype']) { + $query->withPanelTypes(array($map['paneltype'])); } return $query; } - public function buildSearchForm( - AphrontFormView $form, - PhabricatorSavedQuery $saved_query) { - - $status = $saved_query->getParameter('status', ''); - $paneltype = $saved_query->getParameter('paneltype', ''); + protected function buildCustomSearchFields() { - $panel_types = PhabricatorDashboardPanelType::getAllPanelTypes(); - $panel_types = mpull($panel_types, 'getPanelTypeName', 'getPanelTypeKey'); - asort($panel_types); - $panel_types = (array('' => pht('(All Types)')) + $panel_types); - - $form - ->appendChild( - id(new AphrontFormSelectControl()) + return array( + id(new PhabricatorSearchSelectField()) + ->setKey('status') ->setLabel(pht('Status')) - ->setName('status') - ->setValue($status) ->setOptions( - array( - '' => pht('(All Panels)'), - 'active' => pht('Active Panels'), - 'archived' => pht('Archived Panels'), - ))) - ->appendChild( - id(new AphrontFormSelectControl()) + id(new PhabricatorDashboardPanel()) + ->getStatuses()), + id(new PhabricatorSearchSelectField()) + ->setKey('paneltype') ->setLabel(pht('Panel Type')) - ->setName('paneltype') - ->setValue($paneltype) - ->setOptions($panel_types)); + ->setOptions( + id(new PhabricatorDashboardPanel()) + ->getPanelTypes()), + ); } protected function getURI($path) { @@ -117,13 +99,14 @@ $impl = $panel->getImplementation(); if ($impl) { $type_text = $impl->getPanelTypeName(); - $type_icon = 'none'; } else { $type_text = nonempty($panel->getPanelType(), pht('Unknown Type')); - $type_icon = 'fa-question'; } + $item->addAttribute($type_text); - $item->addIcon($type_icon, $type_text); + $properties = $panel->getProperties(); + $class = idx($properties, 'class'); + $item->addAttribute($class); if ($panel->getIsArchived()) { $item->setDisabled(true); diff --git a/src/applications/dashboard/query/PhabricatorDashboardQuery.php b/src/applications/dashboard/query/PhabricatorDashboardQuery.php --- a/src/applications/dashboard/query/PhabricatorDashboardQuery.php +++ b/src/applications/dashboard/query/PhabricatorDashboardQuery.php @@ -7,6 +7,7 @@ private $phids; private $needPanels; + private $needProjects; public function withIDs(array $ids) { $this->ids = $ids; @@ -23,25 +24,26 @@ return $this; } + public function needProjects($need_projects) { + $this->needProjects = $need_projects; + return $this; + } + protected function loadPage() { - $table = new PhabricatorDashboard(); - $conn_r = $table->establishConnection('r'); - - $data = queryfx_all( - $conn_r, - 'SELECT * FROM %T %Q %Q %Q', - $table->getTableName(), - $this->buildWhereClause($conn_r), - $this->buildOrderClause($conn_r), - $this->buildLimitClause($conn_r)); - - return $table->loadAllFromArray($data); + return $this->loadStandardPage($this->newResultObject()); + } + + public function newResultObject() { + return new PhabricatorDashboard(); } protected function didFilterPage(array $dashboards) { + + $phids = mpull($dashboards, 'getPHID'); + if ($this->needPanels) { $edge_query = id(new PhabricatorEdgeQuery()) - ->withSourcePHIDs(mpull($dashboards, 'getPHID')) + ->withSourcePHIDs($phids) ->withEdgeTypes( array( PhabricatorDashboardDashboardHasPanelEdgeType::EDGECONST, @@ -70,29 +72,43 @@ } } + if ($this->needProjects) { + $edge_query = id(new PhabricatorEdgeQuery()) + ->withSourcePHIDs($phids) + ->withEdgeTypes( + array( + PhabricatorProjectObjectHasProjectEdgeType::EDGECONST, + )); + $edge_query->execute(); + + foreach ($dashboards as $dashboard) { + $project_phids = $edge_query->getDestinationPHIDs( + array($dashboard->getPHID())); + $dashboard->attachProjectPHIDs($project_phids); + } + } + return $dashboards; } - protected function buildWhereClause(AphrontDatabaseConnection $conn_r) { - $where = array(); + protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) { + $where = parent::buildWhereClauseParts($conn); - if ($this->ids) { + if ($this->ids !== null) { $where[] = qsprintf( - $conn_r, + $conn, 'id IN (%Ld)', $this->ids); } - if ($this->phids) { + if ($this->phids !== null) { $where[] = qsprintf( - $conn_r, + $conn, 'phid IN (%Ls)', $this->phids); } - $where[] = $this->buildPagingClause($conn_r); - - return $this->formatWhereClause($where); + return $where; } public function getQueryApplicationClass() { diff --git a/src/applications/dashboard/query/PhabricatorDashboardSearchEngine.php b/src/applications/dashboard/query/PhabricatorDashboardSearchEngine.php --- a/src/applications/dashboard/query/PhabricatorDashboardSearchEngine.php +++ b/src/applications/dashboard/query/PhabricatorDashboardSearchEngine.php @@ -11,18 +11,13 @@ return 'PhabricatorDashboardApplication'; } - public function buildSavedQueryFromRequest(AphrontRequest $request) { - return new PhabricatorSavedQuery(); + public function newQuery() { + return id(new PhabricatorDashboardQuery()) + ->needProjects(true); } - public function buildQueryFromSavedQuery(PhabricatorSavedQuery $saved) { - return new PhabricatorDashboardQuery(); - } - - public function buildSearchForm( - AphrontFormView $form, - PhabricatorSavedQuery $saved_query) { - return; + protected function buildCustomSearchFields() { + return array(); } protected function getURI($path) { @@ -48,6 +43,11 @@ return parent::buildSavedQueryFromBuiltin($query_key); } + protected function buildQueryFromParameters(array $map) { + $query = $this->newQuery(); + return $query; + } + protected function renderResultList( array $dashboards, PhabricatorSavedQuery $query, @@ -70,6 +70,18 @@ $installs = array(); } + $proj_phids = array(); + foreach ($dashboards as $dashboard) { + foreach ($dashboard->getProjectPHIDs() as $project_phid) { + $proj_phids[] = $project_phid; + } + } + + $proj_handles = id(new PhabricatorHandleQuery()) + ->setViewer($viewer) + ->withPHIDs($proj_phids) + ->execute(); + $list = new PHUIObjectItemListView(); $list->setUser($viewer); $list->initBehavior('phabricator-tooltips', array()); @@ -101,6 +113,17 @@ } } + $project_handles = array_select_keys( + $proj_handles, + $dashboard->getProjectPHIDs()); + + $item->addAttribute( + id(new PHUIHandleTagListView()) + ->setLimit(4) + ->setNoDataString(pht('No Projects')) + ->setSlim(true) + ->setHandles($project_handles)); + $list->addItem($item); } @@ -109,7 +132,6 @@ $result->setNoDataString(pht('No dashboards found.')); return $result; - } } diff --git a/src/applications/dashboard/storage/PhabricatorDashboard.php b/src/applications/dashboard/storage/PhabricatorDashboard.php --- a/src/applications/dashboard/storage/PhabricatorDashboard.php +++ b/src/applications/dashboard/storage/PhabricatorDashboard.php @@ -8,7 +8,8 @@ PhabricatorApplicationTransactionInterface, PhabricatorPolicyInterface, PhabricatorFlaggableInterface, - PhabricatorDestructibleInterface { + PhabricatorDestructibleInterface, + PhabricatorProjectInterface { protected $name; protected $viewPolicy; @@ -17,6 +18,8 @@ private $panelPHIDs = self::ATTACHABLE; private $panels = self::ATTACHABLE; + private $edgeProjectPHIDs = self::ATTACHABLE; + public static function initializeNewDashboard(PhabricatorUser $actor) { return id(new PhabricatorDashboard()) @@ -65,6 +68,15 @@ return $this; } + public function getProjectPHIDs() { + return $this->assertAttached($this->edgeProjectPHIDs); + } + + public function attachProjectPHIDs(array $phids) { + $this->edgeProjectPHIDs = $phids; + return $this; + } + public function attachPanelPHIDs(array $phids) { $this->panelPHIDs = $phids; return $this; diff --git a/src/applications/dashboard/storage/PhabricatorDashboardPanel.php b/src/applications/dashboard/storage/PhabricatorDashboardPanel.php --- a/src/applications/dashboard/storage/PhabricatorDashboardPanel.php +++ b/src/applications/dashboard/storage/PhabricatorDashboardPanel.php @@ -10,6 +10,7 @@ PhabricatorPolicyInterface, PhabricatorCustomFieldInterface, PhabricatorFlaggableInterface, + PhabricatorProjectInterface, PhabricatorDestructibleInterface { protected $name; @@ -71,6 +72,24 @@ return 'W'.$this->getID(); } + public function getPanelTypes() { + $panel_types = PhabricatorDashboardPanelType::getAllPanelTypes(); + $panel_types = mpull($panel_types, 'getPanelTypeName', 'getPanelTypeKey'); + asort($panel_types); + $panel_types = (array('' => pht('(All Types)')) + $panel_types); + return $panel_types; + } + + public function getStatuses() { + $statuses = + array( + '' => pht('(All Panels)'), + 'active' => pht('Active Panels'), + 'archived' => pht('Archived Panels'), + ); + return $statuses; + } + public function getImplementation() { return idx( PhabricatorDashboardPanelType::getAllPanelTypes(),