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 @@ -2914,7 +2914,6 @@ 'PhabricatorDashboardConsoleController' => 'applications/dashboard/controller/PhabricatorDashboardConsoleController.php', 'PhabricatorDashboardController' => 'applications/dashboard/controller/PhabricatorDashboardController.php', 'PhabricatorDashboardDAO' => 'applications/dashboard/storage/PhabricatorDashboardDAO.php', - 'PhabricatorDashboardDashboardHasPanelEdgeType' => 'applications/dashboard/edge/PhabricatorDashboardDashboardHasPanelEdgeType.php', 'PhabricatorDashboardDashboardPHIDType' => 'applications/dashboard/phid/PhabricatorDashboardDashboardPHIDType.php', 'PhabricatorDashboardDatasource' => 'applications/dashboard/typeahead/PhabricatorDashboardDatasource.php', 'PhabricatorDashboardEditController' => 'applications/dashboard/controller/dashboard/PhabricatorDashboardEditController.php', @@ -2945,13 +2944,14 @@ 'PhabricatorDashboardPanelEditConduitAPIMethod' => 'applications/dashboard/conduit/PhabricatorDashboardPanelEditConduitAPIMethod.php', 'PhabricatorDashboardPanelEditController' => 'applications/dashboard/controller/panel/PhabricatorDashboardPanelEditController.php', 'PhabricatorDashboardPanelEditEngine' => 'applications/dashboard/editor/PhabricatorDashboardPanelEditEngine.php', - 'PhabricatorDashboardPanelHasDashboardEdgeType' => 'applications/dashboard/edge/PhabricatorDashboardPanelHasDashboardEdgeType.php', 'PhabricatorDashboardPanelListController' => 'applications/dashboard/controller/panel/PhabricatorDashboardPanelListController.php', 'PhabricatorDashboardPanelNameTransaction' => 'applications/dashboard/xaction/panel/PhabricatorDashboardPanelNameTransaction.php', 'PhabricatorDashboardPanelNgrams' => 'applications/dashboard/storage/PhabricatorDashboardPanelNgrams.php', 'PhabricatorDashboardPanelPHIDType' => 'applications/dashboard/phid/PhabricatorDashboardPanelPHIDType.php', 'PhabricatorDashboardPanelPropertyTransaction' => 'applications/dashboard/xaction/panel/PhabricatorDashboardPanelPropertyTransaction.php', 'PhabricatorDashboardPanelQuery' => 'applications/dashboard/query/PhabricatorDashboardPanelQuery.php', + 'PhabricatorDashboardPanelRef' => 'applications/dashboard/layoutconfig/PhabricatorDashboardPanelRef.php', + 'PhabricatorDashboardPanelRefList' => 'applications/dashboard/layoutconfig/PhabricatorDashboardPanelRefList.php', 'PhabricatorDashboardPanelRenderController' => 'applications/dashboard/controller/panel/PhabricatorDashboardPanelRenderController.php', 'PhabricatorDashboardPanelRenderingEngine' => 'applications/dashboard/engine/PhabricatorDashboardPanelRenderingEngine.php', 'PhabricatorDashboardPanelSearchEngine' => 'applications/dashboard/query/PhabricatorDashboardPanelSearchEngine.php', @@ -8914,7 +8914,6 @@ 'PhabricatorDashboardConsoleController' => 'PhabricatorDashboardController', 'PhabricatorDashboardController' => 'PhabricatorController', 'PhabricatorDashboardDAO' => 'PhabricatorLiskDAO', - 'PhabricatorDashboardDashboardHasPanelEdgeType' => 'PhabricatorEdgeType', 'PhabricatorDashboardDashboardPHIDType' => 'PhabricatorPHIDType', 'PhabricatorDashboardDatasource' => 'PhabricatorTypeaheadDatasource', 'PhabricatorDashboardEditController' => 'PhabricatorDashboardController', @@ -8952,13 +8951,14 @@ 'PhabricatorDashboardPanelEditConduitAPIMethod' => 'PhabricatorEditEngineAPIMethod', 'PhabricatorDashboardPanelEditController' => 'PhabricatorDashboardController', 'PhabricatorDashboardPanelEditEngine' => 'PhabricatorEditEngine', - 'PhabricatorDashboardPanelHasDashboardEdgeType' => 'PhabricatorEdgeType', 'PhabricatorDashboardPanelListController' => 'PhabricatorDashboardController', 'PhabricatorDashboardPanelNameTransaction' => 'PhabricatorDashboardPanelTransactionType', 'PhabricatorDashboardPanelNgrams' => 'PhabricatorSearchNgrams', 'PhabricatorDashboardPanelPHIDType' => 'PhabricatorPHIDType', 'PhabricatorDashboardPanelPropertyTransaction' => 'PhabricatorDashboardPanelTransactionType', 'PhabricatorDashboardPanelQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', + 'PhabricatorDashboardPanelRef' => 'Phobject', + 'PhabricatorDashboardPanelRefList' => 'Phobject', 'PhabricatorDashboardPanelRenderController' => 'PhabricatorDashboardController', 'PhabricatorDashboardPanelRenderingEngine' => 'Phobject', 'PhabricatorDashboardPanelSearchEngine' => 'PhabricatorApplicationSearchEngine', diff --git a/src/applications/dashboard/controller/PhabricatorDashboardAddPanelController.php b/src/applications/dashboard/controller/PhabricatorDashboardAddPanelController.php --- a/src/applications/dashboard/controller/PhabricatorDashboardAddPanelController.php +++ b/src/applications/dashboard/controller/PhabricatorDashboardAddPanelController.php @@ -10,7 +10,6 @@ $dashboard = id(new PhabricatorDashboardQuery()) ->setViewer($viewer) ->withIDs(array($id)) - ->needPanels(true) ->requireCapabilities( array( PhabricatorPolicyCapability::CAN_VIEW, diff --git a/src/applications/dashboard/controller/PhabricatorDashboardMovePanelController.php b/src/applications/dashboard/controller/PhabricatorDashboardMovePanelController.php --- a/src/applications/dashboard/controller/PhabricatorDashboardMovePanelController.php +++ b/src/applications/dashboard/controller/PhabricatorDashboardMovePanelController.php @@ -15,7 +15,6 @@ $dashboard = id(new PhabricatorDashboardQuery()) ->setViewer($viewer) ->withIDs(array($id)) - ->needPanels(true) ->requireCapabilities( array( PhabricatorPolicyCapability::CAN_VIEW, diff --git a/src/applications/dashboard/controller/PhabricatorDashboardRemovePanelController.php b/src/applications/dashboard/controller/PhabricatorDashboardRemovePanelController.php --- a/src/applications/dashboard/controller/PhabricatorDashboardRemovePanelController.php +++ b/src/applications/dashboard/controller/PhabricatorDashboardRemovePanelController.php @@ -47,17 +47,6 @@ if ($request->isFormPost()) { $xactions = array(); - $xactions[] = id(new PhabricatorDashboardTransaction()) - ->setTransactionType(PhabricatorTransactions::TYPE_EDGE) - ->setMetadataValue( - 'edge:type', - PhabricatorDashboardDashboardHasPanelEdgeType::EDGECONST) - ->setNewValue( - array( - '-' => array( - $v_panel => $v_panel, - ), - )); $layout_config->removePanel($v_panel); $dashboard->setLayoutConfigFromObject($layout_config); diff --git a/src/applications/dashboard/controller/dashboard/PhabricatorDashboardViewController.php b/src/applications/dashboard/controller/dashboard/PhabricatorDashboardViewController.php --- a/src/applications/dashboard/controller/dashboard/PhabricatorDashboardViewController.php +++ b/src/applications/dashboard/controller/dashboard/PhabricatorDashboardViewController.php @@ -14,7 +14,6 @@ $dashboard = id(new PhabricatorDashboardQuery()) ->setViewer($viewer) ->withIDs(array($id)) - ->needPanels(true) ->executeOne(); if (!$dashboard) { return new Aphront404Response(); diff --git a/src/applications/dashboard/edge/PhabricatorDashboardDashboardHasPanelEdgeType.php b/src/applications/dashboard/edge/PhabricatorDashboardDashboardHasPanelEdgeType.php deleted file mode 100644 --- a/src/applications/dashboard/edge/PhabricatorDashboardDashboardHasPanelEdgeType.php +++ /dev/null @@ -1,103 +0,0 @@ -setTransactionType(PhabricatorTransactions::TYPE_EDGE) - ->setMetadataValue( - 'edge:type', - PhabricatorDashboardDashboardHasPanelEdgeType::EDGECONST) - ->setNewValue( - array( - '+' => array( - $panel->getPHID() => $panel->getPHID(), - ), - )); - - $layout_config = $dashboard->getLayoutConfigObject(); - $layout_config->setPanelLocation($column, $panel->getPHID()); - $dashboard->setLayoutConfigFromObject($layout_config); - - $editor = id(new PhabricatorDashboardTransactionEditor()) - ->setActor($actor) - ->setContentSource($content_source) - ->setContinueOnMissingFields(true) - ->setContinueOnNoEffect(true) - ->applyTransactions($dashboard, $xactions); - } - public function getTransactionTypes() { $types = parent::getTransactionTypes(); diff --git a/src/applications/dashboard/engine/PhabricatorDashboardRenderingEngine.php b/src/applications/dashboard/engine/PhabricatorDashboardRenderingEngine.php --- a/src/applications/dashboard/engine/PhabricatorDashboardRenderingEngine.php +++ b/src/applications/dashboard/engine/PhabricatorDashboardRenderingEngine.php @@ -31,44 +31,46 @@ public function renderDashboard() { require_celerity_resource('phabricator-dashboard-css'); - $dashboard = $this->dashboard; - $viewer = $this->viewer; + $dashboard = $this->getDashboard(); + $viewer = $this->getViewer(); $is_editable = $this->arrangeMode; - $layout_config = $dashboard->getLayoutConfigObject(); - $panel_grid_locations = $layout_config->getPanelLocations(); - $panels = mpull($dashboard->getPanels(), null, 'getPHID'); - $dashboard_id = celerity_generate_unique_node_id(); - $result = id(new AphrontMultiColumnView()) - ->setID($dashboard_id) - ->setFluidLayout(true) - ->setGutter(AphrontMultiColumnView::GUTTER_LARGE); - if ($is_editable) { $h_mode = PhabricatorDashboardPanelRenderingEngine::HEADER_MODE_EDIT; } else { $h_mode = PhabricatorDashboardPanelRenderingEngine::HEADER_MODE_NORMAL; } - $panel_phids = array(); - foreach ($panel_grid_locations as $panel_column_locations) { - foreach ($panel_column_locations as $panel_phid) { - $panel_phids[] = $panel_phid; - } + $panel_phids = $dashboard->getPanelPHIDs(); + if ($panel_phids) { + $panels = id(new PhabricatorDashboardPanelQuery()) + ->setViewer($viewer) + ->withPHIDs($panel_phids) + ->execute(); + $panels = mpull($panels, null, 'getPHID'); + + $handles = $viewer->loadHandles($panel_phids); + } else { + $panels = array(); + $handles = array(); } - $handles = $viewer->loadHandles($panel_phids); - foreach ($panel_grid_locations as $column => $panel_column_locations) { - $panel_phids = $panel_column_locations; + $ref_list = $dashboard->getPanelRefList(); + $columns = $ref_list->getColumns(); + + $dashboard_id = celerity_generate_unique_node_id(); + + $result = id(new AphrontMultiColumnView()) + ->setID($dashboard_id) + ->setFluidLayout(true) + ->setGutter(AphrontMultiColumnView::GUTTER_LARGE); - // TODO: This list may contain duplicates when the dashboard itself - // does not? Perhaps this is related to T10612. For now, just unique - // the list before moving on. - $panel_phids = array_unique($panel_phids); + foreach ($columns as $column) { + $column_views = array(); + foreach ($column->getPanelRefs() as $panel_ref) { + $panel_phid = $panel_ref->getPanelPHID(); - $column_result = array(); - foreach ($panel_phids as $panel_phid) { $panel_engine = id(new PhabricatorDashboardPanelRenderingEngine()) ->setViewer($viewer) ->setDashboardID($dashboard->getID()) @@ -85,18 +87,19 @@ $panel_engine->setPanel($panel); } - $column_result[] = $panel_engine->renderPanel(); + $column_views[] = $panel_engine->renderPanel(); } - $column_class = $layout_config->getColumnClass( - $column, - $is_editable); + + $column_classes = $column->getClasses(); + if ($is_editable) { - $column_result[] = $this->renderAddPanelPlaceHolder($column); - $column_result[] = $this->renderAddPanelUI($column); + $column_views[] = $this->renderAddPanelPlaceHolder(); + $column_views[] = $this->renderAddPanelUI($column->getColumnKey()); } + $result->addColumn( - $column_result, - $column_class, + $column_views, + implode(' ', $column_classes), $sigil = 'dashboard-column', $metadata = array('columnID' => $column)); } @@ -120,10 +123,7 @@ return $view; } - private function renderAddPanelPlaceHolder($column) { - $dashboard = $this->dashboard; - $panels = $dashboard->getPanels(); - + private function renderAddPanelPlaceHolder() { return javelin_tag( 'span', array( diff --git a/src/applications/dashboard/layoutconfig/PhabricatorDashboardColumn.php b/src/applications/dashboard/layoutconfig/PhabricatorDashboardColumn.php --- a/src/applications/dashboard/layoutconfig/PhabricatorDashboardColumn.php +++ b/src/applications/dashboard/layoutconfig/PhabricatorDashboardColumn.php @@ -5,6 +5,7 @@ private $columnKey; private $classes = array(); + private $refs = array(); public function setColumnKey($column_key) { $this->columnKey = $column_key; @@ -24,4 +25,13 @@ return $this->classes; } + public function addPanelRef(PhabricatorDashboardPanelRef $ref) { + $this->refs[] = $ref; + return $this; + } + + public function getPanelRefs() { + return $this->refs; + } + } diff --git a/src/applications/dashboard/layoutconfig/PhabricatorDashboardPanelRef.php b/src/applications/dashboard/layoutconfig/PhabricatorDashboardPanelRef.php new file mode 100644 --- /dev/null +++ b/src/applications/dashboard/layoutconfig/PhabricatorDashboardPanelRef.php @@ -0,0 +1,37 @@ +panelPHID = $panel_phid; + return $this; + } + + public function getPanelPHID() { + return $this->panelPHID; + } + + public function setColumnKey($column_key) { + $this->columnKey = $column_key; + return $this; + } + + public function getColumnKey() { + return $this->columnKey; + } + + public function setPanelKey($panel_key) { + $this->panelKey = $panel_key; + return $this; + } + + public function getPanelKey() { + return $this->panelKey; + } + +} diff --git a/src/applications/dashboard/layoutconfig/PhabricatorDashboardPanelRefList.php b/src/applications/dashboard/layoutconfig/PhabricatorDashboardPanelRefList.php new file mode 100644 --- /dev/null +++ b/src/applications/dashboard/layoutconfig/PhabricatorDashboardPanelRefList.php @@ -0,0 +1,76 @@ +getLayoutModeColumns(); + $columns = mpull($columns, null, 'getColumnKey'); + $default_column = head($columns); + + $panels = idx($config, 'panels'); + if (!is_array($panels)) { + $panels = array(); + } + + $seen_panels = array(); + $refs = array(); + foreach ($panels as $panel) { + $panel_phid = idx($panel, 'panelPHID'); + if (!strlen($panel_phid)) { + continue; + } + + $panel_key = idx($panel, 'panelKey'); + if (!strlen($panel_key)) { + continue; + } + + if (isset($seen_panels[$panel_key])) { + continue; + } + $seen_panels[$panel_key] = true; + + $column_key = idx($panel, 'columnKey'); + $column = idx($columns, $column_key, $default_column); + + $ref = id(new PhabricatorDashboardPanelRef()) + ->setPanelPHID($panel_phid) + ->setPanelKey($panel_key) + ->setColumnKey($column->getColumnKey()); + + $column->addPanelRef($ref); + $refs[] = $ref; + } + + $list = new self(); + + $list->columns = $columns; + $list->refs = $refs; + + return $list; + } + + public function getColumns() { + return $this->columns; + } + + public function getPanelRefs() { + return $this->refs; + } + +} 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 @@ -9,9 +9,6 @@ private $authorPHIDs; private $canEdit; - private $needPanels; - private $needProjects; - public function withIDs(array $ids) { $this->ids = $ids; return $this; @@ -32,16 +29,6 @@ return $this; } - public function needPanels($need_panels) { - $this->needPanels = $need_panels; - return $this; - } - - public function needProjects($need_projects) { - $this->needProjects = $need_projects; - return $this; - } - public function withCanEdit($can_edit) { $this->canEdit = $can_edit; return $this; @@ -74,58 +61,6 @@ ->apply($dashboards); } - if ($this->needPanels) { - $edge_query = id(new PhabricatorEdgeQuery()) - ->withSourcePHIDs($phids) - ->withEdgeTypes( - array( - PhabricatorDashboardDashboardHasPanelEdgeType::EDGECONST, - )); - $edge_query->execute(); - - $panel_phids = $edge_query->getDestinationPHIDs(); - if ($panel_phids) { - // NOTE: We explicitly disable policy exceptions when loading panels. - // If a particular panel is invalid or not visible to the viewer, - // we'll still render the dashboard, just not that panel. - - $panels = id(new PhabricatorDashboardPanelQuery()) - ->setParentQuery($this) - ->setRaisePolicyExceptions(false) - ->setViewer($this->getViewer()) - ->withPHIDs($panel_phids) - ->execute(); - $panels = mpull($panels, null, 'getPHID'); - } else { - $panels = array(); - } - - foreach ($dashboards as $dashboard) { - $dashboard_phids = $edge_query->getDestinationPHIDs( - array($dashboard->getPHID())); - $dashboard_panels = array_select_keys($panels, $dashboard_phids); - - $dashboard->attachPanelPHIDs($dashboard_phids); - $dashboard->attachPanels($dashboard_panels); - } - } - - 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; } 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 @@ -12,8 +12,7 @@ } public function newQuery() { - return id(new PhabricatorDashboardQuery()) - ->needPanels(true); + return id(new PhabricatorDashboardQuery()); } public function canUseInPanelContext() { @@ -139,16 +138,6 @@ $bg_color = 'bg-grey'; } - $panels = $dashboard->getPanels(); - foreach ($panels as $panel) { - $item->addAttribute($panel->getName()); - } - - if (empty($panels)) { - $empty = phutil_tag('em', array(), pht('No panels.')); - $item->addAttribute($empty); - } - $icon = id(new PHUIIconView()) ->setIcon($dashboard->getIcon()) ->setBackground($bg_color); 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 @@ -24,10 +24,10 @@ const STATUS_ACTIVE = 'active'; const STATUS_ARCHIVED = 'archived'; - private $panelPHIDs = self::ATTACHABLE; private $panels = self::ATTACHABLE; private $edgeProjectPHIDs = self::ATTACHABLE; + private $panelRefList; public static function initializeNewDashboard(PhabricatorUser $actor) { return id(new PhabricatorDashboard()) @@ -37,8 +37,7 @@ ->setEditPolicy($actor->getPHID()) ->setStatus(self::STATUS_ACTIVE) ->setAuthorPHID($actor->getPHID()) - ->attachPanels(array()) - ->attachPanelPHIDs(array()); + ->attachPanels(array()); } public static function getStatusNameMap() { @@ -76,6 +75,10 @@ public function setRawLayoutMode($mode) { $config = $this->getRawLayoutConfig(); $config['layoutMode'] = $mode; + + // If a cached panel ref list exists, clear it. + $this->panelRefList = null; + return $this->setLayoutConfig($config); } @@ -89,63 +92,34 @@ return $config; } - public function getLayoutConfigObject() { - return PhabricatorDashboardLayoutConfig::newFromDictionary( - $this->getLayoutConfig()); + public function isArchived() { + return ($this->getStatus() == self::STATUS_ARCHIVED); } - public function setLayoutConfigFromObject( - PhabricatorDashboardLayoutConfig $object) { - - $this->setLayoutConfig($object->toDictionary()); - - // See PHI385. Dashboard panel mutations rely on changes to the Dashboard - // object persisting when transactions are applied, but this assumption is - // no longer valid after T13054. For now, just save the dashboard - // explicitly. - $this->save(); - - return $this; + public function getURI() { + return urisprintf('/dashboard/view/%d/', $this->getID()); } - public function getProjectPHIDs() { - return $this->assertAttached($this->edgeProjectPHIDs); + public function getObjectName() { + return pht('Dashboard %d', $this->getID()); } - public function attachProjectPHIDs(array $phids) { - $this->edgeProjectPHIDs = $phids; - return $this; + public function getPanelRefList() { + if (!$this->panelRefList) { + $this->panelRefList = $this->newPanelRefList(); + } + return $this->panelRefList; } - public function attachPanelPHIDs(array $phids) { - $this->panelPHIDs = $phids; - return $this; + private function newPanelRefList() { + $raw_config = $this->getLayoutConfig(); + return PhabricatorDashboardPanelRefList::newFromDictionary($raw_config); } public function getPanelPHIDs() { - return $this->assertAttached($this->panelPHIDs); - } - - public function attachPanels(array $panels) { - assert_instances_of($panels, 'PhabricatorDashboardPanel'); - $this->panels = $panels; - return $this; - } - - public function getPanels() { - return $this->assertAttached($this->panels); - } - - public function isArchived() { - return ($this->getStatus() == self::STATUS_ARCHIVED); - } - - public function getURI() { - return urisprintf('/dashboard/view/%d/', $this->getID()); - } - - public function getObjectName() { - return pht('Dashboard %d', $this->getID()); + $ref_list = $this->getPanelRefList(); + $phids = mpull($ref_list->getPanelRefs(), 'getPanelPHID'); + return array_unique($phids); } /* -( PhabricatorApplicationTransactionInterface )------------------------- */ @@ -216,9 +190,7 @@ /* -( PhabricatorDashboardPanelContainerInterface )------------------------ */ public function getDashboardPanelContainerPanelPHIDs() { - return PhabricatorEdgeQuery::loadDestinationPHIDs( - $this->getPHID(), - PhabricatorDashboardDashboardHasPanelEdgeType::EDGECONST); + return $this->getPanelPHIDs(); } } diff --git a/src/applications/dashboard/storage/PhabricatorDashboardInstall.php b/src/applications/dashboard/storage/PhabricatorDashboardInstall.php --- a/src/applications/dashboard/storage/PhabricatorDashboardInstall.php +++ b/src/applications/dashboard/storage/PhabricatorDashboardInstall.php @@ -43,7 +43,6 @@ $dashboard = id(new PhabricatorDashboardQuery()) ->setViewer($viewer) ->withPHIDs(array($dashboard_install->getDashboardPHID())) - ->needPanels(true) ->executeOne(); } diff --git a/src/applications/search/menuitem/PhabricatorDashboardProfileMenuItem.php b/src/applications/search/menuitem/PhabricatorDashboardProfileMenuItem.php --- a/src/applications/search/menuitem/PhabricatorDashboardProfileMenuItem.php +++ b/src/applications/search/menuitem/PhabricatorDashboardProfileMenuItem.php @@ -54,7 +54,6 @@ $dashboard = id(new PhabricatorDashboardQuery()) ->setViewer($viewer) ->withPHIDs(array($dashboard_phid)) - ->needPanels(true) ->executeOne(); if (!$dashboard) { return $this->newEmptyView(