Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F15466792
D9140.id.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
10 KB
Referenced Files
None
Subscribers
None
D9140.id.diff
View Options
diff --git a/resources/celerity/map.php b/resources/celerity/map.php
--- a/resources/celerity/map.php
+++ b/resources/celerity/map.php
@@ -52,7 +52,7 @@
'rsrc/css/application/conpherence/widget-pane.css' => 'bf275a6c',
'rsrc/css/application/contentsource/content-source-view.css' => '4b8b05d4',
'rsrc/css/application/countdown/timer.css' => '86b7b0a0',
- 'rsrc/css/application/dashboard/dashboard.css' => '5b532b7b',
+ 'rsrc/css/application/dashboard/dashboard.css' => '2b41640b',
'rsrc/css/application/diff/inline-comment-summary.css' => '8cfd34e8',
'rsrc/css/application/differential/add-comment.css' => 'c478bcaa',
'rsrc/css/application/differential/changeset-view.css' => '1570a1ff',
@@ -358,8 +358,8 @@
'rsrc/js/application/conpherence/behavior-pontificate.js' => '53f6f2dd',
'rsrc/js/application/conpherence/behavior-widget-pane.js' => '40b1ff90',
'rsrc/js/application/countdown/timer.js' => '889c96f3',
- 'rsrc/js/application/dashboard/behavior-dashboard-async-panel.js' => '4398eabb',
- 'rsrc/js/application/dashboard/behavior-dashboard-move-panels.js' => 'aa3f313b',
+ 'rsrc/js/application/dashboard/behavior-dashboard-async-panel.js' => 'fd965b41',
+ 'rsrc/js/application/dashboard/behavior-dashboard-move-panels.js' => 'fa187a68',
'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',
@@ -553,8 +553,8 @@
'javelin-behavior-conpherence-widget-pane' => '40b1ff90',
'javelin-behavior-countdown-timer' => '889c96f3',
'javelin-behavior-dark-console' => 'e9fdb5e5',
- 'javelin-behavior-dashboard-async-panel' => '4398eabb',
- 'javelin-behavior-dashboard-move-panels' => 'aa3f313b',
+ 'javelin-behavior-dashboard-async-panel' => 'fd965b41',
+ 'javelin-behavior-dashboard-move-panels' => 'fa187a68',
'javelin-behavior-device' => '03d6ed07',
'javelin-behavior-differential-add-reviewers-and-ccs' => '533a187b',
'javelin-behavior-differential-comment-jump' => '71755c79',
@@ -701,7 +701,7 @@
'phabricator-core-css' => '40151074',
'phabricator-countdown-css' => '86b7b0a0',
'phabricator-crumbs-view-css' => '6a23399c',
- 'phabricator-dashboard-css' => '5b532b7b',
+ 'phabricator-dashboard-css' => '2b41640b',
'phabricator-drag-and-drop-file-upload' => 'ae6abfba',
'phabricator-draggable-list' => '1681c4d4',
'phabricator-fatal-config-template-css' => '25d446d6',
@@ -1133,12 +1133,6 @@
8 => 'phuix-action-list-view',
9 => 'phuix-action-view',
),
- '4398eabb' =>
- array(
- 0 => 'javelin-behavior',
- 1 => 'javelin-dom',
- 2 => 'javelin-workflow',
- ),
'441f2137' =>
array(
0 => 'javelin-behavior',
@@ -1270,11 +1264,6 @@
2 => 'javelin-util',
3 => 'phabricator-shaped-request',
),
- '7319e029' =>
- array(
- 0 => 'javelin-behavior',
- 1 => 'javelin-dom',
- ),
'62e18640' =>
array(
0 => 'javelin-install',
@@ -1329,6 +1318,11 @@
1 => 'javelin-stratcom',
2 => 'javelin-dom',
),
+ '7319e029' =>
+ array(
+ 0 => 'javelin-behavior',
+ 1 => 'javelin-dom',
+ ),
'76f4ebed' =>
array(
0 => 'javelin-install',
@@ -1598,15 +1592,6 @@
1 => 'javelin-stratcom',
2 => 'javelin-dom',
),
- 'aa3f313b' =>
- array(
- 0 => 'javelin-behavior',
- 1 => 'javelin-dom',
- 2 => 'javelin-util',
- 3 => 'javelin-stratcom',
- 4 => 'javelin-workflow',
- 5 => 'phabricator-draggable-list',
- ),
'ad7a69ca' =>
array(
0 => 'javelin-install',
@@ -2034,11 +2019,26 @@
4 => 'javelin-stratcom',
5 => 'phabricator-shaped-request',
),
+ 'fa187a68' =>
+ array(
+ 0 => 'javelin-behavior',
+ 1 => 'javelin-dom',
+ 2 => 'javelin-util',
+ 3 => 'javelin-stratcom',
+ 4 => 'javelin-workflow',
+ 5 => 'phabricator-draggable-list',
+ ),
'fbbce3bf' =>
array(
0 => 'phabricator-busy',
1 => 'javelin-behavior',
),
+ 'fd965b41' =>
+ array(
+ 0 => 'javelin-behavior',
+ 1 => 'javelin-dom',
+ 2 => 'javelin-workflow',
+ ),
'fe2e0ba4' =>
array(
0 => 'javelin-behavior',
diff --git a/src/applications/dashboard/controller/PhabricatorDashboardPanelRenderController.php b/src/applications/dashboard/controller/PhabricatorDashboardPanelRenderController.php
--- a/src/applications/dashboard/controller/PhabricatorDashboardPanelRenderController.php
+++ b/src/applications/dashboard/controller/PhabricatorDashboardPanelRenderController.php
@@ -21,9 +21,22 @@
return new Aphront404Response();
}
+ if ($request->isAjax()) {
+ $parent_phids = $request->getStrList('parentPanelPHIDs', null);
+ if ($parent_phids === null) {
+ throw new Exception(
+ pht(
+ 'Required parameter `parentPanelPHIDs` is not present in '.
+ 'request.'));
+ }
+ } else {
+ $parent_phids = array();
+ }
+
$rendered_panel = id(new PhabricatorDashboardPanelRenderingEngine())
->setViewer($viewer)
->setPanel($panel)
+ ->setParentPanelPHIDs($parent_phids)
->renderPanel();
if ($request->isAjax()) {
diff --git a/src/applications/dashboard/controller/PhabricatorDashboardPanelViewController.php b/src/applications/dashboard/controller/PhabricatorDashboardPanelViewController.php
--- a/src/applications/dashboard/controller/PhabricatorDashboardPanelViewController.php
+++ b/src/applications/dashboard/controller/PhabricatorDashboardPanelViewController.php
@@ -41,6 +41,7 @@
$rendered_panel = id(new PhabricatorDashboardPanelRenderingEngine())
->setViewer($viewer)
->setPanel($panel)
+ ->setParentPanelPHIDs(array())
->renderPanel();
return $this->buildApplicationPage(
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
@@ -5,6 +5,7 @@
private $panel;
private $viewer;
private $enableAsyncRendering;
+ private $parentPanelPHIDs;
/**
* Allow the engine to render the panel via Ajax.
@@ -14,6 +15,11 @@
return $this;
}
+ public function setParentPanelPHIDs(array $parents) {
+ $this->parentPanelPHIDs = $parents;
+ return $this;
+ }
+
public function setViewer(PhabricatorUser $viewer) {
$this->viewer = $viewer;
return $this;
@@ -44,13 +50,15 @@
$panel->getPanelType()));
}
- if ($this->enableAsyncRendering) {
- if ($panel_type->shouldRenderAsync()) {
- return $this->renderAsyncPanel($panel);
+ try {
+ $this->detectRenderingCycle($panel);
+
+ if ($this->enableAsyncRendering) {
+ if ($panel_type->shouldRenderAsync()) {
+ return $this->renderAsyncPanel($panel);
+ }
}
- }
- try {
return $panel_type->renderPanel($viewer, $panel);
} catch (Exception $ex) {
return $this->renderErrorPanel(
@@ -75,6 +83,7 @@
'dashboard-async-panel',
array(
'panelID' => $panel_id,
+ 'parentPanelPHIDs' => $this->parentPanelPHIDs,
'uri' => '/dashboard/panel/render/'.$panel->getID().'/',
));
@@ -87,4 +96,43 @@
->appendChild(pht('Loading...'));
}
+ /**
+ * Detect graph cycles in panels, and deeply nested panels.
+ *
+ * This method throws if the current rendering stack is too deep or contains
+ * a cycle. This can happen if you embed layout panels inside each other,
+ * build a big stack of panels, or embed a panel in remarkup inside another
+ * panel. Generally, all of this stuff is ridiculous and we just want to
+ * shut it down.
+ *
+ * @param PhabricatorDashboardPanel Panel being rendered.
+ * @return void
+ */
+ private function detectRenderingCycle(PhabricatorDashboardPanel $panel) {
+ if ($this->parentPanelPHIDs === null) {
+ throw new Exception(
+ pht(
+ 'You must call setParentPanelPHIDs() before rendering panels.'));
+ }
+
+ $max_depth = 4;
+ if (count($this->parentPanelPHIDs) >= $max_depth) {
+ throw new Exception(
+ pht(
+ 'To render more than %s levels of panels nested inside other '.
+ 'panels, purchase a subscription to Phabricator Gold.',
+ new PhutilNumber($max_depth)));
+ }
+
+ if (in_array($panel->getPHID(), $this->parentPanelPHIDs)) {
+ throw new Exception(
+ pht(
+ 'You awake in a twisting maze of mirrors, all alike. '.
+ 'You are likely to be eaten by a graph cycle. '.
+ 'Should you escape alive, you resolve to be more careful about '.
+ 'putting dashboard panels inside themselves.'));
+ }
+ }
+
+
}
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
@@ -43,6 +43,7 @@
->setViewer($viewer)
->setPanel($panel)
->setEnableAsyncRendering(true)
+ ->setParentPanelPHIDs(array())
->renderPanel();
}
$column_class = $layout_config->getColumnClass(
diff --git a/webroot/rsrc/js/application/dashboard/behavior-dashboard-async-panel.js b/webroot/rsrc/js/application/dashboard/behavior-dashboard-async-panel.js
--- a/webroot/rsrc/js/application/dashboard/behavior-dashboard-async-panel.js
+++ b/webroot/rsrc/js/application/dashboard/behavior-dashboard-async-panel.js
@@ -10,6 +10,7 @@
panel.style.opacity = '0.5';
new JX.Workflow(config.uri)
+ .setData({parentPanelPHIDs: config.parentPanelPHIDs.join(',')})
.setHandler(function(r) {
JX.DOM.replace(panel, JX.$H(r.panelMarkup));
})
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Fri, Apr 4, 9:52 AM (1 w, 4 d ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
7706125
Default Alt Text
D9140.id.diff (10 KB)
Attached To
Mode
D9140: Allow dashboard panels to detect rendering cycles and arrest stack overflows
Attached
Detach File
Event Timeline
Log In to Comment