diff --git a/resources/celerity/map.php b/resources/celerity/map.php --- a/resources/celerity/map.php +++ b/resources/celerity/map.php @@ -356,6 +356,7 @@ 'rsrc/js/application/conpherence/behavior-pontificate.js' => '53f6f2dd', 'rsrc/js/application/conpherence/behavior-widget-pane.js' => 'd8ef8659', 'rsrc/js/application/countdown/timer.js' => '889c96f3', + 'rsrc/js/application/dashboard/behavior-dashboard-async-panel.js' => '4398eabb', 'rsrc/js/application/differential/DifferentialInlineCommentEditor.js' => 'f2441746', 'rsrc/js/application/differential/behavior-add-reviewers-and-ccs.js' => '533a187b', 'rsrc/js/application/differential/behavior-comment-jump.js' => '71755c79', @@ -546,6 +547,7 @@ 'javelin-behavior-conpherence-widget-pane' => 'd8ef8659', 'javelin-behavior-countdown-timer' => '889c96f3', 'javelin-behavior-dark-console' => 'e9fdb5e5', + 'javelin-behavior-dashboard-async-panel' => '4398eabb', 'javelin-behavior-device' => '03d6ed07', 'javelin-behavior-differential-add-reviewers-and-ccs' => '533a187b', 'javelin-behavior-differential-comment-jump' => '71755c79', @@ -1073,6 +1075,12 @@ 1 => 'javelin-dom', 2 => 'phortune-credit-card-form', ), + '4398eabb' => + array( + 0 => 'javelin-behavior', + 1 => 'javelin-dom', + 2 => 'javelin-workflow', + ), '441f2137' => array( 0 => 'javelin-behavior', 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 @@ -1454,6 +1454,7 @@ 'PhabricatorDashboardPanelTypeText' => 'applications/dashboard/paneltype/PhabricatorDashboardPanelTypeText.php', 'PhabricatorDashboardPanelViewController' => 'applications/dashboard/controller/PhabricatorDashboardPanelViewController.php', 'PhabricatorDashboardQuery' => 'applications/dashboard/query/PhabricatorDashboardQuery.php', + 'PhabricatorDashboardRenderingEngine' => 'applications/dashboard/engine/PhabricatorDashboardRenderingEngine.php', 'PhabricatorDashboardSearchEngine' => 'applications/dashboard/query/PhabricatorDashboardSearchEngine.php', 'PhabricatorDashboardTransaction' => 'applications/dashboard/storage/PhabricatorDashboardTransaction.php', 'PhabricatorDashboardTransactionEditor' => 'applications/dashboard/editor/PhabricatorDashboardTransactionEditor.php', @@ -4267,6 +4268,7 @@ 'PhabricatorDashboardPanelTypeText' => 'PhabricatorDashboardPanelType', 'PhabricatorDashboardPanelViewController' => 'PhabricatorDashboardController', 'PhabricatorDashboardQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', + 'PhabricatorDashboardRenderingEngine' => 'Phobject', 'PhabricatorDashboardSearchEngine' => 'PhabricatorApplicationSearchEngine', 'PhabricatorDashboardTransaction' => 'PhabricatorApplicationTransaction', 'PhabricatorDashboardTransactionEditor' => 'PhabricatorApplicationTransactionEditor', diff --git a/src/applications/dashboard/controller/PhabricatorDashboardViewController.php b/src/applications/dashboard/controller/PhabricatorDashboardViewController.php --- a/src/applications/dashboard/controller/PhabricatorDashboardViewController.php +++ b/src/applications/dashboard/controller/PhabricatorDashboardViewController.php @@ -36,11 +36,17 @@ ->setHeader($header) ->addPropertyList($properties); + $rendered_dashboard = id(new PhabricatorDashboardRenderingEngine()) + ->setViewer($viewer) + ->setDashboard($dashboard) + ->renderDashboard(); + return $this->buildApplicationPage( array( $crumbs, $box, $timeline, + $rendered_dashboard, ), array( 'title' => $title, 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 @@ -4,6 +4,15 @@ private $panel; private $viewer; + private $enableAsyncRendering; + + /** + * Allow the engine to render the panel via Ajax. + */ + public function setEnableAsyncRendering($enable) { + $this->enableAsyncRendering = $enable; + return $this; + } public function setViewer(PhabricatorUser $viewer) { $this->viewer = $viewer; @@ -35,6 +44,13 @@ $panel->getPanelType())); } + if ($this->enableAsyncRendering) { + if ($panel_type->shouldRenderAsync()) { + return $this->renderAsyncPanel($panel); + } + } + + return $panel_type->renderPanel($viewer, $panel); } @@ -44,4 +60,20 @@ ->setFormErrors(array($body)); } + private function renderAsyncPanel(PhabricatorDashboardPanel $panel) { + $panel_id = celerity_generate_unique_node_id(); + + Javelin::initBehavior( + 'dashboard-async-panel', + array( + 'panelID' => $panel_id, + 'uri' => '/dashboard/panel/render/'.$panel->getID().'/', + )); + + return id(new PHUIObjectBoxView()) + ->setHeaderText($panel->getName()) + ->setID($panel_id) + ->appendChild(pht('Loading...')); + } + } diff --git a/src/applications/dashboard/engine/PhabricatorDashboardRenderingEngine.php b/src/applications/dashboard/engine/PhabricatorDashboardRenderingEngine.php new file mode 100644 --- /dev/null +++ b/src/applications/dashboard/engine/PhabricatorDashboardRenderingEngine.php @@ -0,0 +1,34 @@ +viewer = $viewer; + return $this; + } + + public function setDashboard(PhabricatorDashboard $dashboard) { + $this->dashboard = $dashboard; + return $this; + } + + public function renderDashboard() { + $dashboard = $this->dashboard; + $viewer = $this->viewer; + + $result = array(); + foreach ($dashboard->getPanels() as $panel) { + $result[] = id(new PhabricatorDashboardPanelRenderingEngine()) + ->setViewer($viewer) + ->setPanel($panel) + ->setEnableAsyncRendering(true) + ->renderPanel(); + } + + return $result; + } + +} diff --git a/src/applications/dashboard/paneltype/PhabricatorDashboardPanelType.php b/src/applications/dashboard/paneltype/PhabricatorDashboardPanelType.php --- a/src/applications/dashboard/paneltype/PhabricatorDashboardPanelType.php +++ b/src/applications/dashboard/paneltype/PhabricatorDashboardPanelType.php @@ -48,4 +48,10 @@ ->appendChild(pht('TODO: Panel content goes here.')); } + public function shouldRenderAsync() { + // TODO: For now, just make these things random so we can catch anything + // that breaks. + return (mt_rand(0, 1) == 1); + } + } diff --git a/webroot/rsrc/js/application/dashboard/behavior-dashboard-async-panel.js b/webroot/rsrc/js/application/dashboard/behavior-dashboard-async-panel.js new file mode 100644 --- /dev/null +++ b/webroot/rsrc/js/application/dashboard/behavior-dashboard-async-panel.js @@ -0,0 +1,17 @@ +/** + * @provides javelin-behavior-dashboard-async-panel + * @requires javelin-behavior + * javelin-dom + * javelin-workflow + */ + +JX.behavior('dashboard-async-panel', function(config) { + var panel = JX.$(config.panelID); + panel.style.opacity = '0.5'; + + new JX.Workflow(config.uri) + .setHandler(function(r) { + JX.DOM.replace(panel, JX.$H(r.panelMarkup)); + }) + .start(); +});