From d9058d7f3ff762067f1a7f39b09392ee14cf30b9 Mon Sep 17 00:00:00 2001 From: Bob Trahan Date: Mon, 19 May 2014 14:04:26 -0700 Subject: [PATCH] Dashboards - add remove functionality Summary: To get there, upgrade "headerless" to "headerMode". Add a new removepanel controller. Fixes T5084. Test Plan: removed some panels to much success Reviewers: chad, epriestley Reviewed By: epriestley Subscribers: epriestley, Korvin Maniphest Tasks: T5078, T5084 Differential Revision: https://secure.phabricator.com/D9156 --- resources/celerity/map.php | 34 +-- src/__phutil_library_map__.php | 2 + .../PhabricatorApplicationDashboard.php | 2 + ...PhabricatorDashboardAddPanelController.php | 10 +- ...habricatorDashboardMovePanelController.php | 14 +- ...habricatorDashboardPanelEditController.php | 16 +- ...bricatorDashboardPanelRenderController.php | 3 +- ...bricatorDashboardRemovePanelController.php | 82 ++++++++ ...abricatorDashboardPanelRenderingEngine.php | 193 ++++++++++++++---- .../PhabricatorDashboardRenderingEngine.php | 7 + .../PhabricatorDashboardLayoutConfig.php | 18 ++ .../PhabricatorDashboardPanelType.php | 19 +- .../PhabricatorDashboardPanelTypeQuery.php | 2 +- .../PhabricatorDashboardPanelTypeTabs.php | 5 +- .../PhabricatorDashboardPanelTypeText.php | 2 +- .../css/application/dashboard/dashboard.css | 14 +- .../behavior-dashboard-async-panel.js | 3 +- 17 files changed, 327 insertions(+), 99 deletions(-) create mode 100644 src/applications/dashboard/controller/PhabricatorDashboardRemovePanelController.php diff --git a/resources/celerity/map.php b/resources/celerity/map.php index 685dda2f18..719a5ffcb2 100644 --- a/resources/celerity/map.php +++ b/resources/celerity/map.php @@ -52,7 +52,7 @@ return array( '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' => '2b41640b', + 'rsrc/css/application/dashboard/dashboard.css' => 'fbf815b5', 'rsrc/css/application/diff/inline-comment-summary.css' => '8cfd34e8', 'rsrc/css/application/differential/add-comment.css' => 'c478bcaa', 'rsrc/css/application/differential/changeset-view.css' => 'c45747f0', @@ -355,7 +355,7 @@ return array( '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' => 'f1375ea5', + 'rsrc/js/application/dashboard/behavior-dashboard-async-panel.js' => '469c0d9e', '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', @@ -550,7 +550,7 @@ return array( 'javelin-behavior-conpherence-widget-pane' => '40b1ff90', 'javelin-behavior-countdown-timer' => '889c96f3', 'javelin-behavior-dark-console' => 'e9fdb5e5', - 'javelin-behavior-dashboard-async-panel' => 'f1375ea5', + 'javelin-behavior-dashboard-async-panel' => '469c0d9e', 'javelin-behavior-dashboard-move-panels' => 'fa187a68', 'javelin-behavior-device' => '03d6ed07', 'javelin-behavior-differential-add-reviewers-and-ccs' => '533a187b', @@ -698,7 +698,7 @@ return array( 'phabricator-core-css' => '40151074', 'phabricator-countdown-css' => '86b7b0a0', 'phabricator-crumbs-view-css' => '6a23399c', - 'phabricator-dashboard-css' => '2b41640b', + 'phabricator-dashboard-css' => 'fbf815b5', 'phabricator-drag-and-drop-file-upload' => 'ae6abfba', 'phabricator-draggable-list' => '1681c4d4', 'phabricator-fatal-config-template-css' => '25d446d6', @@ -1129,6 +1129,12 @@ return array( 1 => 'javelin-stratcom', 2 => 'javelin-dom', ), + '469c0d9e' => + array( + 0 => 'javelin-behavior', + 1 => 'javelin-dom', + 2 => 'javelin-workflow', + ), '46efd18e' => array( 0 => 'multirow-row-manager', @@ -1254,6 +1260,13 @@ return array( 2 => 'javelin-util', 3 => 'phabricator-shaped-request', ), + '62e18640' => + array( + 0 => 'javelin-install', + 1 => 'javelin-util', + 2 => 'javelin-dom', + 3 => 'javelin-typeahead-normalizer', + ), '6453c869' => array( 0 => 'javelin-install', @@ -1322,13 +1335,6 @@ return array( 0 => 'javelin-behavior', 1 => 'javelin-dom', ), - '62e18640' => - array( - 0 => 'javelin-install', - 1 => 'javelin-util', - 2 => 'javelin-dom', - 3 => 'javelin-typeahead-normalizer', - ), '76f4ebed' => array( 0 => 'javelin-install', @@ -1961,12 +1967,6 @@ return array( 0 => 'javelin-install', 1 => 'javelin-util', ), - 'f1375ea5' => - array( - 0 => 'javelin-behavior', - 1 => 'javelin-dom', - 2 => 'javelin-workflow', - ), 'f2441746' => array( 0 => 'javelin-dom', diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 56bc1e7d6f..6dd9cddcdd 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -1487,6 +1487,7 @@ phutil_register_library_map(array( 'PhabricatorDashboardPanelTypeText' => 'applications/dashboard/paneltype/PhabricatorDashboardPanelTypeText.php', 'PhabricatorDashboardPanelViewController' => 'applications/dashboard/controller/PhabricatorDashboardPanelViewController.php', 'PhabricatorDashboardQuery' => 'applications/dashboard/query/PhabricatorDashboardQuery.php', + 'PhabricatorDashboardRemovePanelController' => 'applications/dashboard/controller/PhabricatorDashboardRemovePanelController.php', 'PhabricatorDashboardRenderingEngine' => 'applications/dashboard/engine/PhabricatorDashboardRenderingEngine.php', 'PhabricatorDashboardSearchEngine' => 'applications/dashboard/query/PhabricatorDashboardSearchEngine.php', 'PhabricatorDashboardTransaction' => 'applications/dashboard/storage/PhabricatorDashboardTransaction.php', @@ -4278,6 +4279,7 @@ phutil_register_library_map(array( 'PhabricatorDashboardPanelTypeText' => 'PhabricatorDashboardPanelType', 'PhabricatorDashboardPanelViewController' => 'PhabricatorDashboardController', 'PhabricatorDashboardQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', + 'PhabricatorDashboardRemovePanelController' => 'PhabricatorDashboardController', 'PhabricatorDashboardRenderingEngine' => 'Phobject', 'PhabricatorDashboardSearchEngine' => 'PhabricatorApplicationSearchEngine', 'PhabricatorDashboardTransaction' => 'PhabricatorApplicationTransaction', diff --git a/src/applications/dashboard/application/PhabricatorApplicationDashboard.php b/src/applications/dashboard/application/PhabricatorApplicationDashboard.php index 6aca83a10e..7572688e64 100644 --- a/src/applications/dashboard/application/PhabricatorApplicationDashboard.php +++ b/src/applications/dashboard/application/PhabricatorApplicationDashboard.php @@ -26,6 +26,8 @@ final class PhabricatorApplicationDashboard extends PhabricatorApplication { 'edit/(?:(?P\d+)/)?' => 'PhabricatorDashboardEditController', 'addpanel/(?P\d+)/' => 'PhabricatorDashboardAddPanelController', 'movepanel/(?P\d+)/' => 'PhabricatorDashboardMovePanelController', + 'removepanel/(?P\d+)/' + => 'PhabricatorDashboardRemovePanelController', 'panel/' => array( '(?:query/(?P[^/]+)/)?' => 'PhabricatorDashboardPanelListController', diff --git a/src/applications/dashboard/controller/PhabricatorDashboardAddPanelController.php b/src/applications/dashboard/controller/PhabricatorDashboardAddPanelController.php index 76bb0804c7..c6081c7702 100644 --- a/src/applications/dashboard/controller/PhabricatorDashboardAddPanelController.php +++ b/src/applications/dashboard/controller/PhabricatorDashboardAddPanelController.php @@ -68,12 +68,10 @@ final class PhabricatorDashboardAddPanelController ), )); - if ($layout_config->isMultiColumnLayout()) { - $layout_config->setPanelLocation( - $request->getInt('column'), - $panel->getPHID()); - $dashboard->setLayoutConfigFromObject($layout_config); - } + $layout_config->setPanelLocation( + $request->getInt('column', 0), + $panel->getPHID()); + $dashboard->setLayoutConfigFromObject($layout_config); $editor = id(new PhabricatorDashboardTransactionEditor()) ->setActor($viewer) diff --git a/src/applications/dashboard/controller/PhabricatorDashboardMovePanelController.php b/src/applications/dashboard/controller/PhabricatorDashboardMovePanelController.php index ed3a672df4..4adbcf721f 100644 --- a/src/applications/dashboard/controller/PhabricatorDashboardMovePanelController.php +++ b/src/applications/dashboard/controller/PhabricatorDashboardMovePanelController.php @@ -38,21 +38,9 @@ final class PhabricatorDashboardMovePanelController } $layout_config = $dashboard->getLayoutConfigObject(); + $layout_config->removePanel($panel_phid); $panel_location_grid = $layout_config->getPanelLocations(); - foreach ($panel_location_grid as $column => $panel_columns) { - $found_old_column = array_search($panel_phid, $panel_columns); - if ($found_old_column !== false) { - $new_panel_columns = $panel_columns; - array_splice( - $new_panel_columns, - $found_old_column, - 1, - array()); - $panel_location_grid[$column] = $new_panel_columns; - break; - } - } $panel_columns = idx($panel_location_grid, $column_id, array()); if ($panel_columns) { $insert_at = 0; diff --git a/src/applications/dashboard/controller/PhabricatorDashboardPanelEditController.php b/src/applications/dashboard/controller/PhabricatorDashboardPanelEditController.php index 1d8e9816c1..154f6f55df 100644 --- a/src/applications/dashboard/controller/PhabricatorDashboardPanelEditController.php +++ b/src/applications/dashboard/controller/PhabricatorDashboardPanelEditController.php @@ -52,7 +52,7 @@ final class PhabricatorDashboardPanelEditController $title = pht('Edit %s', $panel->getMonogram()); $header = pht('Edit %s %s', $panel->getMonogram(), $panel->getName()); $button = pht('Save Panel'); - $cancel_uri = '/'.$panel->getMonogram(); + $cancel_uri = $this->getPanelRedirectURI($panel); } $v_name = $panel->getName(); @@ -89,7 +89,7 @@ final class PhabricatorDashboardPanelEditController ->applyTransactions($panel, $xactions); return id(new AphrontRedirectResponse()) - ->setURI('/'.$panel->getMonogram()); + ->setURI($this->getPanelRedirectURI($panel)); } catch (PhabricatorApplicationTransactionValidationException $ex) { $validation_exception = $ex; @@ -144,4 +144,16 @@ final class PhabricatorDashboardPanelEditController )); } + private function getPanelRedirectURI(PhabricatorDashboardPanel $panel) { + $request = $this->getRequest(); + $dashboard_id = $request->getInt('dashboardID'); + if ($dashboard_id) { + $uri = $this->getApplicationURI('arrange/'.$dashboard_id.'/'); + } else { + $uri = '/'.$panel->getMonogram(); + } + + return $uri; + } + } diff --git a/src/applications/dashboard/controller/PhabricatorDashboardPanelRenderController.php b/src/applications/dashboard/controller/PhabricatorDashboardPanelRenderController.php index 648c21cc87..0fb2bc2474 100644 --- a/src/applications/dashboard/controller/PhabricatorDashboardPanelRenderController.php +++ b/src/applications/dashboard/controller/PhabricatorDashboardPanelRenderController.php @@ -37,7 +37,8 @@ final class PhabricatorDashboardPanelRenderController ->setViewer($viewer) ->setPanel($panel) ->setParentPanelPHIDs($parent_phids) - ->setHeaderless($request->getBool('headerless')) + ->setHeaderMode($request->getStr('headerMode')) + ->setDashboardID($request->getInt('dashboardID')) ->renderPanel(); if ($request->isAjax()) { diff --git a/src/applications/dashboard/controller/PhabricatorDashboardRemovePanelController.php b/src/applications/dashboard/controller/PhabricatorDashboardRemovePanelController.php new file mode 100644 index 0000000000..191d691343 --- /dev/null +++ b/src/applications/dashboard/controller/PhabricatorDashboardRemovePanelController.php @@ -0,0 +1,82 @@ +id = idx($data, 'id'); + } + + public function processRequest() { + $request = $this->getRequest(); + $viewer = $request->getUser(); + + $dashboard = id(new PhabricatorDashboardQuery()) + ->setViewer($viewer) + ->withIDs(array($this->id)) + ->requireCapabilities( + array( + PhabricatorPolicyCapability::CAN_VIEW, + PhabricatorPolicyCapability::CAN_EDIT, + )) + ->executeOne(); + if (!$dashboard) { + return new Aphront404Response(); + } + + $v_panel = $request->getStr('panelPHID'); + $panel = id(new PhabricatorDashboardPanelQuery()) + ->setViewer($viewer) + ->withPHIDs(array($v_panel)) + ->executeOne(); + if (!$panel) { + return new Aphront404Response(); + } + + $redirect_uri = $this->getApplicationURI( + 'arrange/'.$dashboard->getID().'/'); + $layout_config = $dashboard->getLayoutConfigObject(); + + if ($request->isFormPost()) { + $xactions = array(); + $xactions[] = id(new PhabricatorDashboardTransaction()) + ->setTransactionType(PhabricatorTransactions::TYPE_EDGE) + ->setMetadataValue( + 'edge:type', + PhabricatorEdgeConfig::TYPE_DASHBOARD_HAS_PANEL) + ->setNewValue( + array( + '-' => array( + $panel->getPHID() => $panel->getPHID(), + ), + )); + + $layout_config->removePanel($panel->getPHID()); + $dashboard->setLayoutConfigFromObject($layout_config); + + $editor = id(new PhabricatorDashboardTransactionEditor()) + ->setActor($viewer) + ->setContentSourceFromRequest($request) + ->setContinueOnMissingFields(true) + ->setContinueOnNoEffect(true) + ->applyTransactions($dashboard, $xactions); + + return id(new AphrontRedirectResponse())->setURI($redirect_uri); + } + + $form = id(new AphrontFormView()) + ->setUser($viewer) + ->addHiddenInput('confirm', true) + ->addHiddenInput('panelPHID', $v_panel) + ->appendChild(pht('Are you sure you want to remove this panel?')); + + return $this->newDialog() + ->setTitle(pht('Remove Panel %s', $panel->getMonogram())) + ->appendChild($form->buildLayoutView()) + ->addCancelButton($redirect_uri) + ->addSubmitButton(pht('Remove Panel')); + } + +} diff --git a/src/applications/dashboard/engine/PhabricatorDashboardPanelRenderingEngine.php b/src/applications/dashboard/engine/PhabricatorDashboardPanelRenderingEngine.php index 3c62d38129..1188e31faa 100644 --- a/src/applications/dashboard/engine/PhabricatorDashboardPanelRenderingEngine.php +++ b/src/applications/dashboard/engine/PhabricatorDashboardPanelRenderingEngine.php @@ -2,19 +2,33 @@ final class PhabricatorDashboardPanelRenderingEngine extends Phobject { + const HEADER_MODE_NORMAL = 'normal'; + const HEADER_MODE_NONE = 'none'; + const HEADER_MODE_EDIT = 'edit'; + private $panel; private $viewer; private $enableAsyncRendering; private $parentPanelPHIDs; - private $headerless; + private $headerMode = self::HEADER_MODE_NORMAL; + private $dashboardID; - public function setHeaderless($headerless) { - $this->headerless = $headerless; + public function setDashboardID($id) { + $this->dashboardID = $id; return $this; } - public function getHeaderless() { - return $this->headerless; + public function getDashboardID() { + return $this->dashboardID; + } + + public function setHeaderMode($header_mode) { + $this->headerMode = $header_mode; + return $this; + } + + public function getHeaderMode() { + return $this->headerMode; } /** @@ -39,14 +53,22 @@ final class PhabricatorDashboardPanelRenderingEngine extends Phobject { return $this; } + public function getViewer() { + return $this->viewer; + } + public function setPanel(PhabricatorDashboardPanel $panel) { $this->panel = $panel; return $this; } + public function getPanel() { + return $this->panel; + } + public function renderPanel() { - $panel = $this->panel; - $viewer = $this->viewer; + $panel = $this->getPanel(); + $viewer = $this->getViewer(); if (!$panel) { return $this->renderErrorPanel( @@ -69,11 +91,11 @@ final class PhabricatorDashboardPanelRenderingEngine extends Phobject { if ($this->enableAsyncRendering) { if ($panel_type->shouldRenderAsync()) { - return $this->renderAsyncPanel($panel); + return $this->renderAsyncPanel(); } } - return $panel_type->renderPanel($viewer, $panel, $this); + return $this->renderNormalPanel($viewer, $panel, $this); } catch (Exception $ex) { return $this->renderErrorPanel( $panel->getName(), @@ -84,47 +106,146 @@ final class PhabricatorDashboardPanelRenderingEngine extends Phobject { } } - private function renderErrorPanel($title, $body) { - if ($this->getHeaderless()) { - return id(new AphrontErrorView()) - ->setErrors(array($body)); - } else { - return id(new PHUIObjectBoxView()) - ->setHeaderText($title) - ->setFormErrors(array($body)); - } + private function renderNormalPanel() { + $panel = $this->getPanel(); + $panel_type = $panel->getImplementation(); + + $content = $panel_type->renderPanelContent( + $this->getViewer(), + $panel, + $this); + $header = $this->renderPanelHeader(); + + return $this->renderPanelDiv( + $content, + $header); } - private function renderAsyncPanel(PhabricatorDashboardPanel $panel) { + + private function renderAsyncPanel() { + $panel = $this->getPanel(); + $panel_id = celerity_generate_unique_node_id(); + $dashboard_id = $this->getDashboardID(); Javelin::initBehavior( 'dashboard-async-panel', array( 'panelID' => $panel_id, 'parentPanelPHIDs' => $this->getParentPanelPHIDs(), - 'headerless' => $this->getHeaderless(), + 'headerMode' => $this->getHeaderMode(), + 'dashboardID' => $dashboard_id, 'uri' => '/dashboard/panel/render/'.$panel->getID().'/', )); - $content = pht('Loading...'); + $header = $this->renderPanelHeader(); + $content = id(new PHUIPropertyListView()) + ->addTextContent(pht('Loading...')); - if ($this->headerless) { - return phutil_tag( - 'div', - array( - 'id' => $panel_id, - ), - $content); - } else { - return id(new PHUIObjectBoxView()) - ->addSigil('dashboard-panel') - ->setMetadata(array( - 'objectPHID' => $panel->getPHID())) - ->setHeaderText($panel->getName()) - ->setID($panel_id) - ->appendChild($content); + return $this->renderPanelDiv( + $content, + $header, + $panel_id); + } + + private function renderErrorPanel($title, $body) { + switch ($this->getHeaderMode()) { + case self::HEADER_MODE_NONE: + $header = null; + break; + case self::HEADER_MODE_EDIT: + $header = id(new PhabricatorActionHeaderView()) + ->setHeaderTitle($title) + ->setHeaderColor(PhabricatorActionHeaderView::HEADER_RED); + $header = $this->addPanelHeaderActions($header); + break; + case self::HEADER_MODE_NORMAL: + default: + $header = id(new PhabricatorActionHeaderView()) + ->setHeaderTitle($title) + ->setHeaderColor(PhabricatorActionHeaderView::HEADER_RED); + break; } + return $this->renderPanelDiv( + id(new AphrontErrorView()) + ->appendChild($body), + $header); + } + + private function renderPanelDiv( + $content, + $header = null, + $id = null) { + + $panel = $this->getPanel(); + if (!$id) { + $id = celerity_generate_unique_node_id(); + } + return javelin_tag( + 'div', + array( + 'id' => $id, + 'sigil' => 'dashboard-panel', + 'meta' => array( + 'objectPHID' => $panel->getPHID()), + 'class' => 'dashboard-panel'), + array( + $header, + $content)); + } + + + private function renderPanelHeader() { + + $panel = $this->getPanel(); + switch ($this->getHeaderMode()) { + case self::HEADER_MODE_NONE: + $header = null; + break; + case self::HEADER_MODE_EDIT: + $header = id(new PhabricatorActionHeaderView()) + ->setHeaderTitle($panel->getName()) + ->setHeaderColor(PhabricatorActionHeaderView::HEADER_GREY); + $header = $this->addPanelHeaderActions($header); + break; + case self::HEADER_MODE_NORMAL: + default: + $header = id(new PhabricatorActionHeaderView()) + ->setHeaderTitle($panel->getName()) + ->setHeaderColor(PhabricatorActionHeaderView::HEADER_GREY); + break; + } + return $header; + } + + private function addPanelHeaderActions( + PhabricatorActionHeaderView $header) { + $panel = $this->getPanel(); + + $dashboard_id = $this->getDashboardID(); + $edit_uri = id(new PhutilURI( + '/dashboard/panel/edit/'.$panel->getID().'/')); + if ($dashboard_id) { + $edit_uri->setQueryParam('dashboardID', $dashboard_id); + } + $action_edit = id(new PHUIIconView()) + ->setSpriteSheet(PHUIIconView::SPRITE_ACTIONS) + ->setSpriteIcon('settings-grey') + ->setHref((string) $edit_uri); + $header->addAction($action_edit); + + if ($dashboard_id) { + $uri = id(new PhutilURI( + '/dashboard/removepanel/'.$dashboard_id.'/')) + ->setQueryParam('panelPHID', $panel->getPHID()); + $action_remove = id(new PHUIIconView()) + ->setSpriteSheet(PHUIIconView::SPRITE_ACTIONS) + ->setSpriteIcon('close-grey') + ->setHref((string) $uri) + ->setWorkflow(true); + $header->addAction($action_remove); + } + return $header; } /** diff --git a/src/applications/dashboard/engine/PhabricatorDashboardRenderingEngine.php b/src/applications/dashboard/engine/PhabricatorDashboardRenderingEngine.php index 6f4199ef02..57602c5a70 100644 --- a/src/applications/dashboard/engine/PhabricatorDashboardRenderingEngine.php +++ b/src/applications/dashboard/engine/PhabricatorDashboardRenderingEngine.php @@ -34,6 +34,11 @@ final class PhabricatorDashboardRenderingEngine extends Phobject { ->setID($dashboard_id) ->setFluidlayout(true); + if ($this->arrangeMode) { + $h_mode = PhabricatorDashboardPanelRenderingEngine::HEADER_MODE_EDIT; + } else { + $h_mode = PhabricatorDashboardPanelRenderingEngine::HEADER_MODE_NORMAL; + } foreach ($panel_grid_locations as $column => $panel_column_locations) { $panel_phids = $panel_column_locations; $column_panels = array_select_keys($panels, $panel_phids); @@ -42,8 +47,10 @@ final class PhabricatorDashboardRenderingEngine extends Phobject { $column_result[] = id(new PhabricatorDashboardPanelRenderingEngine()) ->setViewer($viewer) ->setPanel($panel) + ->setDashboardID($dashboard->getID()) ->setEnableAsyncRendering(true) ->setParentPanelPHIDs(array()) + ->setHeaderMode($h_mode) ->renderPanel(); } $column_class = $layout_config->getColumnClass( diff --git a/src/applications/dashboard/layoutconfig/PhabricatorDashboardLayoutConfig.php b/src/applications/dashboard/layoutconfig/PhabricatorDashboardLayoutConfig.php index 0c9f3c383d..3e739074dc 100644 --- a/src/applications/dashboard/layoutconfig/PhabricatorDashboardLayoutConfig.php +++ b/src/applications/dashboard/layoutconfig/PhabricatorDashboardLayoutConfig.php @@ -32,6 +32,24 @@ final class PhabricatorDashboardLayoutConfig { return $this->panelLocations; } + public function removePanel($panel_phid) { + $panel_location_grid = $this->getPanelLocations(); + foreach ($panel_location_grid as $column => $panel_columns) { + $found_old_column = array_search($panel_phid, $panel_columns); + if ($found_old_column !== false) { + $new_panel_columns = $panel_columns; + array_splice( + $new_panel_columns, + $found_old_column, + 1, + array()); + $panel_location_grid[$column] = $new_panel_columns; + break; + } + } + $this->setPanelLocations($panel_location_grid); + } + public function getDefaultPanelLocations() { switch ($this->getLayoutMode()) { case self::MODE_HALF_AND_HALF: diff --git a/src/applications/dashboard/paneltype/PhabricatorDashboardPanelType.php b/src/applications/dashboard/paneltype/PhabricatorDashboardPanelType.php index e5c7f8c09f..4bcc6200a7 100644 --- a/src/applications/dashboard/paneltype/PhabricatorDashboardPanelType.php +++ b/src/applications/dashboard/paneltype/PhabricatorDashboardPanelType.php @@ -40,26 +40,9 @@ abstract class PhabricatorDashboardPanelType extends Phobject { return $types; } - public function renderPanel( - PhabricatorUser $viewer, - PhabricatorDashboardPanel $panel, - PhabricatorDashboardPanelRenderingEngine $engine) { - $content = $this->renderPanelContent($viewer, $panel, $engine); - if ($engine->getHeaderless()) { - return $content; - } - - return id(new PHUIObjectBoxView()) - ->addSigil('dashboard-panel') - ->setMetadata(array( - 'objectPHID' => $panel->getPHID())) - ->setHeaderText($panel->getName()) - ->appendChild($content); - } - - protected function renderPanelContent( + public function renderPanelContent( PhabricatorUser $viewer, PhabricatorDashboardPanel $panel, PhabricatorDashboardPanelRenderingEngine $engine) { diff --git a/src/applications/dashboard/paneltype/PhabricatorDashboardPanelTypeQuery.php b/src/applications/dashboard/paneltype/PhabricatorDashboardPanelTypeQuery.php index 105ca89845..d677e30800 100644 --- a/src/applications/dashboard/paneltype/PhabricatorDashboardPanelTypeQuery.php +++ b/src/applications/dashboard/paneltype/PhabricatorDashboardPanelTypeQuery.php @@ -30,7 +30,7 @@ final class PhabricatorDashboardPanelTypeQuery ); } - protected function renderPanelContent( + public function renderPanelContent( PhabricatorUser $viewer, PhabricatorDashboardPanel $panel, PhabricatorDashboardPanelRenderingEngine $engine) { diff --git a/src/applications/dashboard/paneltype/PhabricatorDashboardPanelTypeTabs.php b/src/applications/dashboard/paneltype/PhabricatorDashboardPanelTypeTabs.php index 61c6199184..90b2071dc8 100644 --- a/src/applications/dashboard/paneltype/PhabricatorDashboardPanelTypeTabs.php +++ b/src/applications/dashboard/paneltype/PhabricatorDashboardPanelTypeTabs.php @@ -25,7 +25,7 @@ final class PhabricatorDashboardPanelTypeTabs ); } - protected function renderPanelContent( + public function renderPanelContent( PhabricatorUser $viewer, PhabricatorDashboardPanel $panel, PhabricatorDashboardPanelRenderingEngine $engine) { @@ -81,6 +81,7 @@ final class PhabricatorDashboardPanelTypeTabs $parent_phids[] = $panel->getPHID(); $content = array(); + $no_headers = PhabricatorDashboardPanelRenderingEngine::HEADER_MODE_NONE; foreach ($config as $idx => $tab_spec) { $panel_id = idx($tab_spec, 'panelID'); $panel = idx($panels, $panel_id); @@ -91,7 +92,7 @@ final class PhabricatorDashboardPanelTypeTabs ->setEnableAsyncRendering(true) ->setParentPanelPHIDs($parent_phids) ->setPanel($panel) - ->setHeaderless(true) + ->setHeaderMode($no_headers) ->renderPanel(); } else { $panel_content = pht('(Invalid Panel)'); diff --git a/src/applications/dashboard/paneltype/PhabricatorDashboardPanelTypeText.php b/src/applications/dashboard/paneltype/PhabricatorDashboardPanelTypeText.php index e928857423..9c39b740fe 100644 --- a/src/applications/dashboard/paneltype/PhabricatorDashboardPanelTypeText.php +++ b/src/applications/dashboard/paneltype/PhabricatorDashboardPanelTypeText.php @@ -26,7 +26,7 @@ final class PhabricatorDashboardPanelTypeText ); } - protected function renderPanelContent( + public function renderPanelContent( PhabricatorUser $viewer, PhabricatorDashboardPanel $panel, PhabricatorDashboardPanelRenderingEngine $engine) { diff --git a/webroot/rsrc/css/application/dashboard/dashboard.css b/webroot/rsrc/css/application/dashboard/dashboard.css index 67aafd416b..a25c2d9089 100644 --- a/webroot/rsrc/css/application/dashboard/dashboard.css +++ b/webroot/rsrc/css/application/dashboard/dashboard.css @@ -17,9 +17,15 @@ width: 66.66%; } +.aphront-multi-column-fluid +.aphront-multi-column-column-outer +.aphront-multi-column-column .dashboard-panel { + margin: 16px 16px 0px 16px; +} + .aphront-multi-column-fluid .aphront-multi-column-column-outer.grippable -.aphront-multi-column-column .phui-object-box { +.aphront-multi-column-column .dashboard-panel { cursor: move; } @@ -57,3 +63,9 @@ .dashboard-panel-placeholder { display: none; } + +.aphront-multi-column-fluid +.aphront-multi-column-column-outer +.aphront-multi-column-column .aphront-error-view { + margin: 0; +} diff --git a/webroot/rsrc/js/application/dashboard/behavior-dashboard-async-panel.js b/webroot/rsrc/js/application/dashboard/behavior-dashboard-async-panel.js index 0b5f2af825..0ab1796e5b 100644 --- a/webroot/rsrc/js/application/dashboard/behavior-dashboard-async-panel.js +++ b/webroot/rsrc/js/application/dashboard/behavior-dashboard-async-panel.js @@ -11,7 +11,8 @@ JX.behavior('dashboard-async-panel', function(config) { var data = { parentPanelPHIDs: config.parentPanelPHIDs.join(','), - headerless: config.headerless ? 1 : 0 + headerMode: config.headerMode, + dashboardID: config.dashboardID }; new JX.Workflow(config.uri)