diff --git a/src/applications/dashboard/engine/PhabricatorDashboardPanelRenderingEngine.php b/src/applications/dashboard/engine/PhabricatorDashboardPanelRenderingEngine.php --- a/src/applications/dashboard/engine/PhabricatorDashboardPanelRenderingEngine.php +++ b/src/applications/dashboard/engine/PhabricatorDashboardPanelRenderingEngine.php @@ -72,8 +72,10 @@ if (!$panel) { return $this->renderErrorPanel( - pht('Missing Panel'), - pht('This panel does not exist.')); + pht('Missing or Restricted Panel'), + pht( + 'This panel does not exist, or you do not have permission '. + 'to see it.')); } $panel_type = $panel->getImplementation(); @@ -166,10 +168,13 @@ } $icon = id(new PHUIIconView()) ->setIcon('fa-warning red msr'); + $content = id(new PHUIBoxView()) ->addClass('dashboard-box') + ->addMargin(PHUI::MARGIN_MEDIUM) ->appendChild($icon) ->appendChild($body); + return $this->renderPanelDiv( $content, $header); @@ -203,10 +208,17 @@ $box->appendChild($content); } - $box->setHeader($header) + $box + ->setHeader($header) ->setID($id) - ->addSigil('dashboard-panel') - ->setMetadata(array('objectPHID' => $panel->getPHID())); + ->addSigil('dashboard-panel'); + + if ($panel) { + $box->setMetadata( + array( + 'objectPHID' => $panel->getPHID(), + )); + } return phutil_tag_div('dashboard-pane', $box); } 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 @@ -32,7 +32,7 @@ $dashboard_id = celerity_generate_unique_node_id(); $result = id(new AphrontMultiColumnView()) ->setID($dashboard_id) - ->setFluidlayout(true) + ->setFluidLayout(true) ->setGutter(AphrontMultiColumnView::GUTTER_LARGE); if ($this->arrangeMode) { @@ -43,17 +43,27 @@ foreach ($panel_grid_locations as $column => $panel_column_locations) { $panel_phids = $panel_column_locations; - $column_panels = array_select_keys($panels, $panel_phids); + + // 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); + $column_result = array(); - foreach ($column_panels as $panel) { - $column_result[] = id(new PhabricatorDashboardPanelRenderingEngine()) + foreach ($panel_phids as $panel_phid) { + $panel_engine = id(new PhabricatorDashboardPanelRenderingEngine()) ->setViewer($viewer) - ->setPanel($panel) ->setDashboardID($dashboard->getID()) ->setEnableAsyncRendering(true) ->setParentPanelPHIDs(array()) - ->setHeaderMode($h_mode) - ->renderPanel(); + ->setHeaderMode($h_mode); + + $panel = idx($panels, $panel_phid); + if ($panel) { + $panel_engine->setPanel($panel); + } + + $column_result[] = $panel_engine->renderPanel(); } $column_class = $layout_config->getColumnClass( $column, 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 @@ -70,8 +70,13 @@ $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();