Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F14081437
D20408.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
49 KB
Referenced Files
None
Subscribers
None
D20408.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
@@ -10,7 +10,7 @@
'conpherence.pkg.css' => '3c8a0668',
'conpherence.pkg.js' => '020aebcf',
'core.pkg.css' => '294e365c',
- 'core.pkg.js' => '794952ae',
+ 'core.pkg.js' => '69247edd',
'differential.pkg.css' => '8d8360fb',
'differential.pkg.js' => '67e02996',
'diffusion.pkg.css' => '42c75c37',
@@ -371,7 +371,7 @@
'rsrc/js/application/conpherence/behavior-toggle-widget.js' => '8f959ad0',
'rsrc/js/application/countdown/timer.js' => '6a162524',
'rsrc/js/application/daemon/behavior-bulk-job-reload.js' => '3829a3cf',
- 'rsrc/js/application/dashboard/behavior-dashboard-async-panel.js' => '09ecf50c',
+ 'rsrc/js/application/dashboard/behavior-dashboard-async-panel.js' => 'a871fe00',
'rsrc/js/application/dashboard/behavior-dashboard-move-panels.js' => '076bd092',
'rsrc/js/application/dashboard/behavior-dashboard-query-panel-select.js' => '1e413dc9',
'rsrc/js/application/dashboard/behavior-dashboard-tab-panel.js' => '0116d3e8',
@@ -594,7 +594,7 @@
'javelin-behavior-conpherence-search' => '91befbcc',
'javelin-behavior-countdown-timer' => '6a162524',
'javelin-behavior-dark-console' => 'f39d968b',
- 'javelin-behavior-dashboard-async-panel' => '09ecf50c',
+ 'javelin-behavior-dashboard-async-panel' => 'a871fe00',
'javelin-behavior-dashboard-move-panels' => '076bd092',
'javelin-behavior-dashboard-query-panel-select' => '1e413dc9',
'javelin-behavior-dashboard-tab-panel' => '0116d3e8',
@@ -982,11 +982,6 @@
'herald-rule-editor',
'javelin-behavior',
),
- '09ecf50c' => array(
- 'javelin-behavior',
- 'javelin-dom',
- 'javelin-workflow',
- ),
'0ad8d31f' => array(
'javelin-behavior',
'javelin-stratcom',
@@ -1794,6 +1789,11 @@
'javelin-install',
'javelin-dom',
),
+ 'a871fe00' => array(
+ 'javelin-behavior',
+ 'javelin-dom',
+ 'javelin-workflow',
+ ),
'a9942052' => array(
'javelin-behavior',
'javelin-dom',
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
@@ -2906,7 +2906,7 @@
'PhabricatorDarkConsoleTabSetting' => 'applications/settings/setting/PhabricatorDarkConsoleTabSetting.php',
'PhabricatorDarkConsoleVisibleSetting' => 'applications/settings/setting/PhabricatorDarkConsoleVisibleSetting.php',
'PhabricatorDashboard' => 'applications/dashboard/storage/PhabricatorDashboard.php',
- 'PhabricatorDashboardAddPanelController' => 'applications/dashboard/controller/PhabricatorDashboardAddPanelController.php',
+ 'PhabricatorDashboardAdjustController' => 'applications/dashboard/controller/dashboard/PhabricatorDashboardAdjustController.php',
'PhabricatorDashboardApplication' => 'applications/dashboard/application/PhabricatorDashboardApplication.php',
'PhabricatorDashboardApplicationInstallWorkflow' => 'applications/dashboard/install/PhabricatorDashboardApplicationInstallWorkflow.php',
'PhabricatorDashboardArchiveController' => 'applications/dashboard/controller/dashboard/PhabricatorDashboardArchiveController.php',
@@ -2927,7 +2927,6 @@
'PhabricatorDashboardInstall' => 'applications/dashboard/storage/PhabricatorDashboardInstall.php',
'PhabricatorDashboardInstallController' => 'applications/dashboard/controller/dashboard/PhabricatorDashboardInstallController.php',
'PhabricatorDashboardInstallWorkflow' => 'applications/dashboard/install/PhabricatorDashboardInstallWorkflow.php',
- 'PhabricatorDashboardLayoutConfig' => 'applications/dashboard/layoutconfig/PhabricatorDashboardLayoutConfig.php',
'PhabricatorDashboardLayoutMode' => 'applications/dashboard/layoutconfig/PhabricatorDashboardLayoutMode.php',
'PhabricatorDashboardLayoutTransaction' => 'applications/dashboard/xaction/dashboard/PhabricatorDashboardLayoutTransaction.php',
'PhabricatorDashboardListController' => 'applications/dashboard/controller/PhabricatorDashboardListController.php',
@@ -2964,6 +2963,7 @@
'PhabricatorDashboardPanelType' => 'applications/dashboard/paneltype/PhabricatorDashboardPanelType.php',
'PhabricatorDashboardPanelUsedByObjectEdgeType' => 'applications/search/edge/PhabricatorDashboardPanelUsedByObjectEdgeType.php',
'PhabricatorDashboardPanelViewController' => 'applications/dashboard/controller/panel/PhabricatorDashboardPanelViewController.php',
+ 'PhabricatorDashboardPanelsTransaction' => 'applications/dashboard/xaction/dashboard/PhabricatorDashboardPanelsTransaction.php',
'PhabricatorDashboardPortal' => 'applications/dashboard/storage/PhabricatorDashboardPortal.php',
'PhabricatorDashboardPortalController' => 'applications/dashboard/controller/portal/PhabricatorDashboardPortalController.php',
'PhabricatorDashboardPortalDatasource' => 'applications/dashboard/typeahead/PhabricatorDashboardPortalDatasource.php',
@@ -2998,7 +2998,6 @@
'PhabricatorDashboardQueryPanelQueryTransaction' => 'applications/dashboard/xaction/panel/PhabricatorDashboardQueryPanelQueryTransaction.php',
'PhabricatorDashboardQueryPanelType' => 'applications/dashboard/paneltype/PhabricatorDashboardQueryPanelType.php',
'PhabricatorDashboardRemarkupRule' => 'applications/dashboard/remarkup/PhabricatorDashboardRemarkupRule.php',
- 'PhabricatorDashboardRemovePanelController' => 'applications/dashboard/controller/PhabricatorDashboardRemovePanelController.php',
'PhabricatorDashboardRenderingEngine' => 'applications/dashboard/engine/PhabricatorDashboardRenderingEngine.php',
'PhabricatorDashboardSchemaSpec' => 'applications/dashboard/storage/PhabricatorDashboardSchemaSpec.php',
'PhabricatorDashboardSearchEngine' => 'applications/dashboard/query/PhabricatorDashboardSearchEngine.php',
@@ -8906,7 +8905,7 @@
'PhabricatorNgramsInterface',
'PhabricatorDashboardPanelContainerInterface',
),
- 'PhabricatorDashboardAddPanelController' => 'PhabricatorDashboardController',
+ 'PhabricatorDashboardAdjustController' => 'PhabricatorDashboardController',
'PhabricatorDashboardApplication' => 'PhabricatorApplication',
'PhabricatorDashboardApplicationInstallWorkflow' => 'PhabricatorDashboardInstallWorkflow',
'PhabricatorDashboardArchiveController' => 'PhabricatorDashboardController',
@@ -8927,7 +8926,6 @@
'PhabricatorDashboardInstall' => 'PhabricatorDashboardDAO',
'PhabricatorDashboardInstallController' => 'PhabricatorDashboardController',
'PhabricatorDashboardInstallWorkflow' => 'Phobject',
- 'PhabricatorDashboardLayoutConfig' => 'Phobject',
'PhabricatorDashboardLayoutMode' => 'Phobject',
'PhabricatorDashboardLayoutTransaction' => 'PhabricatorDashboardTransactionType',
'PhabricatorDashboardListController' => 'PhabricatorDashboardController',
@@ -8971,6 +8969,7 @@
'PhabricatorDashboardPanelType' => 'Phobject',
'PhabricatorDashboardPanelUsedByObjectEdgeType' => 'PhabricatorEdgeType',
'PhabricatorDashboardPanelViewController' => 'PhabricatorDashboardController',
+ 'PhabricatorDashboardPanelsTransaction' => 'PhabricatorDashboardTransactionType',
'PhabricatorDashboardPortal' => array(
'PhabricatorDashboardDAO',
'PhabricatorApplicationTransactionInterface',
@@ -9013,7 +9012,6 @@
'PhabricatorDashboardQueryPanelQueryTransaction' => 'PhabricatorDashboardPanelPropertyTransaction',
'PhabricatorDashboardQueryPanelType' => 'PhabricatorDashboardPanelType',
'PhabricatorDashboardRemarkupRule' => 'PhabricatorObjectRemarkupRule',
- 'PhabricatorDashboardRemovePanelController' => 'PhabricatorDashboardController',
'PhabricatorDashboardRenderingEngine' => 'Phobject',
'PhabricatorDashboardSchemaSpec' => 'PhabricatorConfigSchemaSpec',
'PhabricatorDashboardSearchEngine' => 'PhabricatorApplicationSearchEngine',
diff --git a/src/applications/auth/engine/PhabricatorAuthSessionEngine.php b/src/applications/auth/engine/PhabricatorAuthSessionEngine.php
--- a/src/applications/auth/engine/PhabricatorAuthSessionEngine.php
+++ b/src/applications/auth/engine/PhabricatorAuthSessionEngine.php
@@ -389,7 +389,7 @@
* appropriate for one-time checks.
*
* @param PhabricatorUser User whose session needs to be in high security.
- * @param AphrontReqeust Current request.
+ * @param AphrontRequest Current request.
* @param string URI to return the user to if they cancel.
* @return PhabricatorAuthHighSecurityToken Security token.
* @task hisec
@@ -421,7 +421,7 @@
* use @{method:requireHighSecurityToken}.
*
* @param PhabricatorUser User whose session needs to be in high security.
- * @param AphrontReqeust Current request.
+ * @param AphrontRequest Current request.
* @param string URI to return the user to if they cancel.
* @param bool True to jump partial sessions directly into high
* security instead of just upgrading them to full
diff --git a/src/applications/dashboard/application/PhabricatorDashboardApplication.php b/src/applications/dashboard/application/PhabricatorDashboardApplication.php
--- a/src/applications/dashboard/application/PhabricatorDashboardApplication.php
+++ b/src/applications/dashboard/application/PhabricatorDashboardApplication.php
@@ -48,10 +48,9 @@
'(?:(?P<modeKey>[^/]+)/)?)?' =>
'PhabricatorDashboardInstallController',
'console/' => 'PhabricatorDashboardConsoleController',
- 'addpanel/(?P<id>\d+)/' => 'PhabricatorDashboardAddPanelController',
'movepanel/(?P<id>\d+)/' => 'PhabricatorDashboardMovePanelController',
- 'removepanel/(?P<id>\d+)/'
- => 'PhabricatorDashboardRemovePanelController',
+ 'adjust/(?P<op>remove|add)/'
+ => 'PhabricatorDashboardAdjustController',
'panel/' => array(
'install/(?P<engineKey>[^/]+)/(?:(?P<queryKey>[^/]+)/)?' =>
'PhabricatorDashboardQueryPanelInstallController',
diff --git a/src/applications/dashboard/controller/PhabricatorDashboardAddPanelController.php b/src/applications/dashboard/controller/PhabricatorDashboardAddPanelController.php
deleted file mode 100644
--- a/src/applications/dashboard/controller/PhabricatorDashboardAddPanelController.php
+++ /dev/null
@@ -1,103 +0,0 @@
-<?php
-
-final class PhabricatorDashboardAddPanelController
- extends PhabricatorDashboardController {
-
- public function handleRequest(AphrontRequest $request) {
- $viewer = $request->getViewer();
- $id = $request->getURIData('id');
-
- $dashboard = id(new PhabricatorDashboardQuery())
- ->setViewer($viewer)
- ->withIDs(array($id))
- ->requireCapabilities(
- array(
- PhabricatorPolicyCapability::CAN_VIEW,
- PhabricatorPolicyCapability::CAN_EDIT,
- ))
- ->executeOne();
- if (!$dashboard) {
- return new Aphront404Response();
- }
-
- $redirect_uri = $this->getApplicationURI(
- 'arrange/'.$dashboard->getID().'/');
-
- $v_panel = head($request->getArr('panel'));
- $e_panel = true;
- $errors = array();
- if ($request->isFormPost()) {
- if (strlen($v_panel)) {
- $panel = id(new PhabricatorDashboardPanelQuery())
- ->setViewer($viewer)
- ->withIDs(array($v_panel))
- ->executeOne();
- if (!$panel) {
- $errors[] = pht('Not a valid panel.');
- $e_panel = pht('Invalid');
- }
-
- $on_dashboard = $dashboard->getPanels();
- $on_ids = mpull($on_dashboard, null, 'getID');
- if (array_key_exists($v_panel, $on_ids)) {
- $p_name = $panel->getName();
- $errors[] = pht('Panel "%s" already exists on dashboard.', $p_name);
- $e_panel = pht('Invalid');
- }
-
- } else {
- $errors[] = pht('Select a panel to add.');
- $e_panel = pht('Required');
- }
-
- if (!$errors) {
- PhabricatorDashboardTransactionEditor::addPanelToDashboard(
- $viewer,
- PhabricatorContentSource::newFromRequest($request),
- $panel,
- $dashboard,
- $request->getInt('column', 0));
-
- return id(new AphrontRedirectResponse())->setURI($redirect_uri);
- }
- }
-
- $panels = id(new PhabricatorDashboardPanelQuery())
- ->setViewer($viewer)
- ->withArchived(false)
- ->execute();
-
- if (!$panels) {
- return $this->newDialog()
- ->setTitle(pht('No Panels Exist Yet'))
- ->appendParagraph(
- pht(
- 'You have not created any dashboard panels yet, so you can not '.
- 'add an existing panel.'))
- ->appendParagraph(
- pht('Instead, add a new panel.'))
- ->addCancelButton($redirect_uri);
- }
-
- $form = id(new AphrontFormView())
- ->setUser($viewer)
- ->addHiddenInput('column', $request->getInt('column'))
- ->appendRemarkupInstructions(
- pht('Choose a panel to add to this dashboard:'))
- ->appendChild(
- id(new AphrontFormTokenizerControl())
- ->setUser($this->getViewer())
- ->setDatasource(new PhabricatorDashboardPanelDatasource())
- ->setLimit(1)
- ->setName('panel')
- ->setLabel(pht('Panel')));
-
- return $this->newDialog()
- ->setTitle(pht('Add Panel'))
- ->setErrors($errors)
- ->appendChild($form->buildLayoutView())
- ->addCancelButton($redirect_uri)
- ->addSubmitButton(pht('Add Panel'));
- }
-
-}
diff --git a/src/applications/dashboard/controller/PhabricatorDashboardRemovePanelController.php b/src/applications/dashboard/controller/PhabricatorDashboardRemovePanelController.php
deleted file mode 100644
--- a/src/applications/dashboard/controller/PhabricatorDashboardRemovePanelController.php
+++ /dev/null
@@ -1,77 +0,0 @@
-<?php
-
-final class PhabricatorDashboardRemovePanelController
- extends PhabricatorDashboardController {
-
- public function handleRequest(AphrontRequest $request) {
- $viewer = $request->getViewer();
- $id = $request->getURIData('id');
-
- $dashboard = id(new PhabricatorDashboardQuery())
- ->setViewer($viewer)
- ->withIDs(array($id))
- ->requireCapabilities(
- array(
- PhabricatorPolicyCapability::CAN_VIEW,
- PhabricatorPolicyCapability::CAN_EDIT,
- ))
- ->executeOne();
- if (!$dashboard) {
- return new Aphront404Response();
- }
-
- // NOTE: If you can edit a dashboard, you can remove panels from it even
- // if you don't have permission to see them or they aren't valid. We only
- // require that the panel be present on the dashboard.
-
- $v_panel = $request->getStr('panelPHID');
-
- $panel_on_dashboard = false;
- $layout = $dashboard->getLayoutConfigObject();
- $columns = $layout->getPanelLocations();
- foreach ($columns as $column) {
- foreach ($column as $column_panel_phid) {
- if ($column_panel_phid == $v_panel) {
- $panel_on_dashboard = true;
- break;
- }
- }
- }
-
- if (!$panel_on_dashboard) {
- return new Aphront404Response();
- }
-
- $redirect_uri = $dashboard->getURI();
- $layout_config = $dashboard->getLayoutConfigObject();
-
- if ($request->isFormPost()) {
- $xactions = array();
-
- $layout_config->removePanel($v_panel);
- $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'))
- ->appendChild($form->buildLayoutView())
- ->addCancelButton($redirect_uri)
- ->addSubmitButton(pht('Remove Panel'));
- }
-
-}
diff --git a/src/applications/dashboard/controller/dashboard/PhabricatorDashboardAdjustController.php b/src/applications/dashboard/controller/dashboard/PhabricatorDashboardAdjustController.php
new file mode 100644
--- /dev/null
+++ b/src/applications/dashboard/controller/dashboard/PhabricatorDashboardAdjustController.php
@@ -0,0 +1,202 @@
+<?php
+
+final class PhabricatorDashboardAdjustController
+ extends PhabricatorDashboardController {
+
+ private $contextPHID;
+ private $panelKey;
+ private $columnKey;
+
+ public function handleRequest(AphrontRequest $request) {
+ $viewer = $this->getViewer();
+
+ $context_phid = $request->getStr('contextPHID');
+
+ $dashboard = id(new PhabricatorDashboardQuery())
+ ->setViewer($viewer)
+ ->withPHIDs(array($context_phid))
+ ->requireCapabilities(
+ array(
+ PhabricatorPolicyCapability::CAN_VIEW,
+ PhabricatorPolicyCapability::CAN_EDIT,
+ ))
+ ->executeOne();
+ if (!$dashboard) {
+ return new Aphront404Response();
+ }
+
+ $this->contextPHID = $context_phid;
+
+ $done_uri = $dashboard->getURI();
+ $ref_list = $dashboard->getPanelRefList();
+
+ $panel_ref = null;
+ $panel_key = $request->getStr('panelKey');
+ if (strlen($panel_key)) {
+ $panel_ref = $ref_list->getPanelRef($panel_key);
+ if (!$panel_ref) {
+ return new Aphront404Response();
+ }
+
+ $this->panelKey = $panel_key;
+ } else {
+ $panel_ref = null;
+ }
+
+ $column_key = $request->getStr('columnKey');
+ if (strlen($column_key)) {
+ $columns = $ref_list->getColumns();
+ if (!isset($columns[$column_key])) {
+ return new Aphront404Response();
+ }
+ $this->columnKey = $column_key;
+ }
+
+ switch ($request->getURIData('op')) {
+ case 'add':
+ return $this->handleAddRequest($dashboard, $done_uri);
+ case 'remove':
+ if (!$panel_ref) {
+ return new Aphront404Response();
+ }
+ return $this->handleRemoveRequest($dashboard, $panel_ref, $done_uri);
+ }
+ }
+
+ private function handleAddRequest(
+ PhabricatorDashboard $dashboard,
+ $done_uri) {
+ $request = $this->getRequest();
+ $viewer = $this->getViewer();
+
+ $errors = array();
+
+ $panel_phid = null;
+ $e_panel = true;
+ if ($request->isFormPost()) {
+ $panel_phid = head($request->getArr('panelPHIDs'));
+
+ if (!$panel_phid) {
+ $errors[] = pht('You must choose a panel to add to the dashboard.');
+ $e_panel = pht('Required');
+ } else {
+ $panel = id(new PhabricatorDashboardPanelQuery())
+ ->setViewer($viewer)
+ ->withPHIDs(array($panel_phid))
+ ->executeOne();
+ if (!$panel) {
+ $errors[] = pht('You must choose a valid panel.');
+ $e_panel = pht('Invalid');
+ }
+ }
+
+ if (!$errors) {
+ $xactions = array();
+
+ $ref_list = clone $dashboard->getPanelRefList();
+ $ref_list->newPanelRef($panel, $this->columnKey);
+ $new_panels = $ref_list->toDictionary();
+
+ $xactions[] = $dashboard->getApplicationTransactionTemplate()
+ ->setTransactionType(
+ PhabricatorDashboardPanelsTransaction::TRANSACTIONTYPE)
+ ->setNewValue($new_panels);
+
+ $editor = $dashboard->getApplicationTransactionEditor()
+ ->setActor($viewer)
+ ->setContentSourceFromRequest($request)
+ ->setContinueOnNoEffect(true)
+ ->setContinueOnMissingFields(true);
+
+ $editor->applyTransactions($dashboard, $xactions);
+
+ return id(new AphrontRedirectResponse())->setURI($done_uri);
+ }
+ }
+
+ if ($panel_phid) {
+ $panel_phids = array($panel_phid);
+ } else {
+ $panel_phids = array();
+ }
+
+ $form = id(new AphrontFormView())
+ ->setViewer($viewer)
+ ->appendRemarkupInstructions(
+ pht('Choose a panel to add to this dashboard:'))
+ ->appendControl(
+ id(new AphrontFormTokenizerControl())
+ ->setDatasource(new PhabricatorDashboardPanelDatasource())
+ ->setLimit(1)
+ ->setName('panelPHIDs')
+ ->setLabel(pht('Panel'))
+ ->setError($e_panel)
+ ->setValue($panel_phids));
+
+ return $this->newEditDialog()
+ ->setTitle(pht('Add Panel'))
+ ->setWidth(AphrontDialogView::WIDTH_FORM)
+ ->setErrors($errors)
+ ->appendForm($form)
+ ->addCancelButton($done_uri)
+ ->addSubmitButton(pht('Add Panel'));
+ }
+
+ private function handleRemoveRequest(
+ PhabricatorDashboard $dashboard,
+ PhabricatorDashboardPanelRef $panel_ref,
+ $done_uri) {
+ $request = $this->getRequest();
+ $viewer = $this->getViewer();
+
+ // NOTE: If you can edit a dashboard, you can remove panels from it even
+ // if you don't have permission to see them or they aren't valid. We only
+ // require that the panel be present on the dashboard.
+
+ if ($request->isFormPost()) {
+ $xactions = array();
+
+ $ref_list = clone $dashboard->getPanelRefList();
+ $ref_list->removePanelRef($panel_ref);
+ $new_panels = $ref_list->toDictionary();
+
+ $xactions[] = $dashboard->getApplicationTransactionTemplate()
+ ->setTransactionType(
+ PhabricatorDashboardPanelsTransaction::TRANSACTIONTYPE)
+ ->setNewValue($new_panels);
+
+ $editor = $dashboard->getApplicationTransactionEditor()
+ ->setActor($viewer)
+ ->setContentSourceFromRequest($request)
+ ->setContinueOnNoEffect(true)
+ ->setContinueOnMissingFields(true);
+
+ $editor->applyTransactions($dashboard, $xactions);
+
+ return id(new AphrontRedirectResponse())->setURI($done_uri);
+ }
+
+ $panel_phid = $panel_ref->getPanelPHID();
+ $handles = $viewer->loadHandles(array($panel_phid));
+ $handle = $handles[$panel_phid];
+
+ $message = pht(
+ 'Remove panel %s from dashboard %s?',
+ phutil_tag('strong', array(), $handle->getFullName()),
+ phutil_tag('strong', array(), $dashboard->getName()));
+
+ return $this->newEditDialog()
+ ->setTitle(pht('Remove Dashboard Panel'))
+ ->appendParagraph($message)
+ ->addCancelButton($done_uri)
+ ->addSubmitButton(pht('Remove Panel'));
+ }
+
+ private function newEditDialog() {
+ return $this->newDialog()
+ ->addHiddenInput('contextPHID', $this->contextPHID)
+ ->addHiddenInput('panelKey', $this->panelKey)
+ ->addHiddenInput('columnKey', $this->columnKey);
+ }
+
+}
diff --git a/src/applications/dashboard/controller/panel/PhabricatorDashboardPanelEditController.php b/src/applications/dashboard/controller/panel/PhabricatorDashboardPanelEditController.php
--- a/src/applications/dashboard/controller/panel/PhabricatorDashboardPanelEditController.php
+++ b/src/applications/dashboard/controller/panel/PhabricatorDashboardPanelEditController.php
@@ -9,37 +9,43 @@
$engine = id(new PhabricatorDashboardPanelEditEngine())
->setController($this);
- // We can create or edit a panel in the context of a dashboard. If we
- // started on a dashboard, we want to return to that dashboard when we're
- // done editing.
- $dashboard_id = $request->getStr('dashboardID');
- if (strlen($dashboard_id)) {
- $dashboard = id(new PhabricatorDashboardQuery())
+ // We can create or edit a panel in the context of a dashboard or
+ // container panel, like a tab panel. If we started this flow on some
+ // container object, we want to return to that container when we're done
+ // editing.
+
+ $context_phid = $request->getStr('contextPHID');
+ if (strlen($context_phid)) {
+ $context = id(new PhabricatorObjectQuery())
->setViewer($viewer)
- ->withIDs(array($dashboard_id))
+ ->withPHIDs(array($context_phid))
->requireCapabilities(
array(
PhabricatorPolicyCapability::CAN_VIEW,
PhabricatorPolicyCapability::CAN_EDIT,
))
->executeOne();
- if (!$dashboard) {
+ if (!$context) {
+ return new Aphront404Response();
+ }
+
+ if (!($context instanceof PhabricatorDashboardPanelContainerInterface)) {
return new Aphront404Response();
}
$engine
- ->setDashboard($dashboard)
- ->addContextParameter('dashboardID', $dashboard_id);
+ ->setContextObject($context)
+ ->addContextParameter('contextPHID', $context_phid);
} else {
- $dashboard = null;
+ $context = null;
}
$id = $request->getURIData('id');
if (!$id) {
- $column_id = $request->getStr('columnID');
+ $column_key = $request->getStr('columnKey');
- if ($dashboard) {
- $cancel_uri = $dashboard->getURI();
+ if ($context) {
+ $cancel_uri = $context->getURI();
} else {
$cancel_uri = $this->getApplicationURI('panel/');
}
@@ -52,9 +58,9 @@
$engine
->addContextParameter('panelType', $panel_type)
- ->addContextParameter('columnID', $column_id)
+ ->addContextParameter('columnKey', $column_key)
->setPanelType($panel_type)
- ->setColumnID($column_id);
+ ->setColumnKey($column_key);
}
return $engine->buildResponse();
diff --git a/src/applications/dashboard/controller/panel/PhabricatorDashboardPanelRenderController.php b/src/applications/dashboard/controller/panel/PhabricatorDashboardPanelRenderController.php
--- a/src/applications/dashboard/controller/panel/PhabricatorDashboardPanelRenderController.php
+++ b/src/applications/dashboard/controller/panel/PhabricatorDashboardPanelRenderController.php
@@ -31,14 +31,27 @@
$parent_phids = array();
}
- $rendered_panel = id(new PhabricatorDashboardPanelRenderingEngine())
+ $engine = id(new PhabricatorDashboardPanelRenderingEngine())
->setViewer($viewer)
->setPanel($panel)
->setPanelPHID($panel->getPHID())
->setParentPanelPHIDs($parent_phids)
->setHeaderMode($request->getStr('headerMode'))
- ->setDashboardID($request->getInt('dashboardID'))
- ->renderPanel();
+ ->setPanelKey($request->getStr('panelKey'));
+
+ $context_phid = $request->getStr('contextPHID');
+ if ($context_phid) {
+ $context = id(new PhabricatorObjectQuery())
+ ->setViewer($viewer)
+ ->withPHIDs(array($context_phid))
+ ->executeOne();
+ if (!$context) {
+ return new Aphront404Response();
+ }
+ $engine->setContextObject($context);
+ }
+
+ $rendered_panel = $engine->renderPanel();
if ($request->isAjax()) {
return id(new AphrontAjaxResponse())
diff --git a/src/applications/dashboard/editor/PhabricatorDashboardPanelEditEngine.php b/src/applications/dashboard/editor/PhabricatorDashboardPanelEditEngine.php
--- a/src/applications/dashboard/editor/PhabricatorDashboardPanelEditEngine.php
+++ b/src/applications/dashboard/editor/PhabricatorDashboardPanelEditEngine.php
@@ -6,8 +6,8 @@
const ENGINECONST = 'dashboard.panel';
private $panelType;
- private $dashboard;
- private $columnID;
+ private $contextObject;
+ private $columnKey;
public function setPanelType($panel_type) {
$this->panelType = $panel_type;
@@ -18,22 +18,22 @@
return $this->panelType;
}
- public function setDashboard(PhabricatorDashboard $dashboard) {
- $this->dashboard = $dashboard;
+ public function setContextObject($context) {
+ $this->contextObject = $context;
return $this;
}
- public function getDashboard() {
- return $this->dashboard;
+ public function getContextObject() {
+ return $this->contextObject;
}
- public function setColumnID($column_id) {
- $this->columnID = $column_id;
+ public function setColumnKey($column_key) {
+ $this->columnKey = $column_key;
return $this;
}
- public function getColumnID() {
- return $this->columnID;
+ public function getColumnKey() {
+ return $this->columnKey;
}
public function isEngineConfigurable() {
@@ -84,27 +84,27 @@
}
protected function getObjectCreateCancelURI($object) {
- $dashboard = $this->getDashboard();
- if ($dashboard) {
- return $dashboard->getURI();
+ $context = $this->getContextObject();
+ if ($context) {
+ return $context->getURI();
}
return parent::getObjectCreateCancelURI($object);
}
public function getEffectiveObjectEditDoneURI($object) {
- $dashboard = $this->getDashboard();
- if ($dashboard) {
- return $dashboard->getURI();
+ $context = $this->getContextObject();
+ if ($context) {
+ return $context->getURI();
}
return parent::getEffectiveObjectEditDoneURI($object);
}
protected function getObjectEditCancelURI($object) {
- $dashboard = $this->getDashboard();
- if ($dashboard) {
- return $dashboard->getURI();
+ $context = $this->getContextObject();
+ if ($context) {
+ return $context->getURI();
}
return parent::getObjectEditCancelURI($object);
@@ -131,18 +131,34 @@
}
protected function didApplyTransactions($object, array $xactions) {
- $dashboard = $this->getDashboard();
- if ($dashboard) {
+ $context = $this->getContextObject();
+
+ if ($context instanceof PhabricatorDashboard) {
$viewer = $this->getViewer();
$controller = $this->getController();
$request = $controller->getRequest();
- PhabricatorDashboardTransactionEditor::addPanelToDashboard(
- $viewer,
- PhabricatorContentSource::newFromRequest($request),
- $object,
- $dashboard,
- (int)$this->getColumnID());
+ $dashboard = $context;
+
+ $xactions = array();
+
+ $ref_list = clone $dashboard->getPanelRefList();
+
+ $ref_list->newPanelRef($object, $this->getColumnKey());
+ $new_panels = $ref_list->toDictionary();
+
+ $xactions[] = $dashboard->getApplicationTransactionTemplate()
+ ->setTransactionType(
+ PhabricatorDashboardPanelsTransaction::TRANSACTIONTYPE)
+ ->setNewValue($new_panels);
+
+ $editor = $dashboard->getApplicationTransactionEditor()
+ ->setActor($viewer)
+ ->setContentSourceFromRequest($request)
+ ->setContinueOnNoEffect(true)
+ ->setContinueOnMissingFields(true);
+
+ $editor->applyTransactions($dashboard, $xactions);
}
}
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
@@ -12,11 +12,11 @@
private $enableAsyncRendering;
private $parentPanelPHIDs;
private $headerMode = self::HEADER_MODE_NORMAL;
- private $dashboardID;
private $movable = true;
private $panelHandle;
private $editMode;
private $contextObject;
+ private $panelKey;
public function setContextObject($object) {
$this->contextObject = $object;
@@ -27,13 +27,13 @@
return $this->contextObject;
}
- public function setDashboardID($id) {
- $this->dashboardID = $id;
+ public function setPanelKey($panel_key) {
+ $this->panelKey = $panel_key;
return $this;
}
- public function getDashboardID() {
- return $this->dashboardID;
+ public function getPanelKey() {
+ return $this->panelKey;
}
public function setHeaderMode($header_mode) {
@@ -182,10 +182,10 @@
private function renderAsyncPanel() {
+ $context_phid = $this->getContextPHID();
$panel = $this->getPanel();
$panel_id = celerity_generate_unique_node_id();
- $dashboard_id = $this->getDashboardID();
Javelin::initBehavior(
'dashboard-async-panel',
@@ -193,7 +193,8 @@
'panelID' => $panel_id,
'parentPanelPHIDs' => $this->getParentPanelPHIDs(),
'headerMode' => $this->getHeaderMode(),
- 'dashboardID' => $dashboard_id,
+ 'contextPHID' => $context_phid,
+ 'panelKey' => $this->getPanelKey(),
'uri' => '/dashboard/panel/render/'.$panel->getID().'/',
));
@@ -322,7 +323,7 @@
$viewer = $this->getViewer();
$panel = $this->getPanel();
- $dashboard_id = $this->getDashboardID();
+ $context_phid = $this->getContextPHID();
$actions = array();
@@ -330,15 +331,15 @@
$panel_id = $panel->getID();
$edit_uri = "/dashboard/panel/edit/{$panel_id}/";
- $edit_uri = new PhutilURI($edit_uri);
- if ($dashboard_id) {
- $edit_uri->replaceQueryParam('dashboardID', $dashboard_id);
- }
+ $params = array(
+ 'contextPHID' => $context_phid,
+ );
+ $edit_uri = new PhutilURI($edit_uri, $params);
$actions[] = id(new PhabricatorActionView())
->setIcon('fa-pencil')
->setName(pht('Edit Panel'))
- ->setHref((string)$edit_uri);
+ ->setHref($edit_uri);
$actions[] = id(new PhabricatorActionView())
->setIcon('fa-window-maximize')
@@ -346,16 +347,19 @@
->setHref($panel->getURI());
}
- if ($dashboard_id) {
+ if ($context_phid) {
$panel_phid = $this->getPanelPHID();
- $remove_uri = "/dashboard/removepanel/{$dashboard_id}/";
- $remove_uri = id(new PhutilURI($remove_uri))
- ->replaceQueryParam('panelPHID', $panel_phid);
+ $remove_uri = urisprintf('/dashboard/adjust/remove/');
+ $params = array(
+ 'contextPHID' => $context_phid,
+ 'panelKey' => $this->getPanelKey(),
+ );
+ $remove_uri = new PhutilURI($remove_uri, $params);
$actions[] = id(new PhabricatorActionView())
->setIcon('fa-times')
- ->setHref((string)$remove_uri)
+ ->setHref($remove_uri)
->setName(pht('Remove Panel'))
->setWorkflow(true);
}
@@ -415,5 +419,14 @@
}
}
+ private function getContextPHID() {
+ $context = $this->getContextObject();
+
+ if ($context) {
+ return $context->getPHID();
+ }
+
+ return null;
+ }
}
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
@@ -73,9 +73,9 @@
$panel_engine = id(new PhabricatorDashboardPanelRenderingEngine())
->setViewer($viewer)
- ->setDashboardID($dashboard->getID())
->setEnableAsyncRendering(true)
->setContextObject($dashboard)
+ ->setPanelKey($panel_ref->getPanelKey())
->setPanelPHID($panel_phid)
->setParentPanelPHIDs(array())
->setHeaderMode($h_mode)
@@ -94,14 +94,20 @@
if ($is_editable) {
$column_views[] = $this->renderAddPanelPlaceHolder();
- $column_views[] = $this->renderAddPanelUI($column->getColumnKey());
+ $column_views[] = $this->renderAddPanelUI($column);
}
+ $sigil = 'dashboard-column';
+
+ $metadata = array(
+ 'columnKey' => $column->getColumnKey(),
+ );
+
$result->addColumn(
$column_views,
implode(' ', $column_classes),
- $sigil = 'dashboard-column',
- $metadata = array('columnID' => $column));
+ $sigil,
+ $metadata);
}
if ($is_editable) {
@@ -133,15 +139,17 @@
pht('This column does not have any panels yet.'));
}
- private function renderAddPanelUI($column) {
- $dashboard_id = $this->dashboard->getID();
+ private function renderAddPanelUI(PhabricatorDashboardColumn $column) {
+ $dashboard = $this->getDashboard();
+ $column_key = $column->getColumnKey();
$create_uri = id(new PhutilURI('/dashboard/panel/edit/'))
- ->replaceQueryParam('dashboardID', $dashboard_id)
- ->replaceQueryParam('columnID', $column);
+ ->replaceQueryParam('contextPHID', $dashboard->getPHID())
+ ->replaceQueryParam('columnKey', $column_key);
- $add_uri = id(new PhutilURI('/dashboard/addpanel/'.$dashboard_id.'/'))
- ->replaceQueryParam('columnID', $column);
+ $add_uri = id(new PhutilURI('/dashboard/adjust/add/'))
+ ->replaceQueryParam('contextPHID', $dashboard->getPHID())
+ ->replaceQueryParam('columnKey', $column_key);
$create_button = id(new PHUIButtonView())
->setTag('a')
diff --git a/src/applications/dashboard/layoutconfig/PhabricatorDashboardLayoutConfig.php b/src/applications/dashboard/layoutconfig/PhabricatorDashboardLayoutConfig.php
deleted file mode 100644
--- a/src/applications/dashboard/layoutconfig/PhabricatorDashboardLayoutConfig.php
+++ /dev/null
@@ -1,128 +0,0 @@
-<?php
-
-final class PhabricatorDashboardLayoutConfig extends Phobject {
-
- const MODE_FULL = 'layout-mode-full';
- const MODE_HALF_AND_HALF = 'layout-mode-half-and-half';
- const MODE_THIRD_AND_THIRDS = 'layout-mode-third-and-thirds';
- const MODE_THIRDS_AND_THIRD = 'layout-mode-thirds-and-third';
-
- private $layoutMode = self::MODE_FULL;
- private $panelLocations = array();
-
- public function setLayoutMode($mode) {
- $this->layoutMode = $mode;
- return $this;
- }
- public function getLayoutMode() {
- return $this->layoutMode;
- }
-
- public function setPanelLocation($which_column, $panel_phid) {
- $this->panelLocations[$which_column][] = $panel_phid;
- return $this;
- }
-
- public function setPanelLocations(array $locations) {
- $this->panelLocations = $locations;
- return $this;
- }
-
- public function getPanelLocations() {
- return $this->panelLocations;
- }
-
- public function replacePanel($old_phid, $new_phid) {
- $locations = $this->getPanelLocations();
- foreach ($locations as $column => $panel_phids) {
- foreach ($panel_phids as $key => $panel_phid) {
- if ($panel_phid == $old_phid) {
- $locations[$column][$key] = $new_phid;
- }
- }
- }
- return $this->setPanelLocations($locations);
- }
-
- 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:
- case self::MODE_THIRD_AND_THIRDS:
- case self::MODE_THIRDS_AND_THIRD:
- $locations = array(array(), array());
- break;
- case self::MODE_FULL:
- default:
- $locations = array(array());
- break;
- }
- return $locations;
- }
-
- public function getColumnClass($column_index, $grippable = false) {
- switch ($this->getLayoutMode()) {
- case self::MODE_HALF_AND_HALF:
- $class = 'half';
- break;
- case self::MODE_THIRD_AND_THIRDS:
- if ($column_index) {
- $class = 'thirds';
- } else {
- $class = 'third';
- }
- break;
- case self::MODE_THIRDS_AND_THIRD:
- if ($column_index) {
- $class = 'third';
- } else {
- $class = 'thirds';
- }
- break;
- case self::MODE_FULL:
- default:
- $class = null;
- break;
- }
- if ($grippable) {
- $class .= ' grippable';
- }
- return $class;
- }
-
- public static function newFromDictionary(array $dict) {
- $layout_config = id(new PhabricatorDashboardLayoutConfig())
- ->setLayoutMode(idx($dict, 'layoutMode', self::MODE_FULL));
- $layout_config->setPanelLocations(idx(
- $dict,
- 'panelLocations',
- $layout_config->getDefaultPanelLocations()));
-
- return $layout_config;
- }
-
- public function toDictionary() {
- return array(
- 'layoutMode' => $this->getLayoutMode(),
- 'panelLocations' => $this->getPanelLocations(),
- );
- }
-
-}
diff --git a/src/applications/dashboard/layoutconfig/PhabricatorDashboardPanelRef.php b/src/applications/dashboard/layoutconfig/PhabricatorDashboardPanelRef.php
--- a/src/applications/dashboard/layoutconfig/PhabricatorDashboardPanelRef.php
+++ b/src/applications/dashboard/layoutconfig/PhabricatorDashboardPanelRef.php
@@ -34,4 +34,12 @@
return $this->panelKey;
}
+ public function toDictionary() {
+ return array(
+ 'panelKey' => $this->getPanelKey(),
+ 'panelPHID' => $this->getPanelPHID(),
+ 'columnKey' => $this->getColumnKey(),
+ );
+ }
+
}
diff --git a/src/applications/dashboard/layoutconfig/PhabricatorDashboardPanelRefList.php b/src/applications/dashboard/layoutconfig/PhabricatorDashboardPanelRefList.php
--- a/src/applications/dashboard/layoutconfig/PhabricatorDashboardPanelRefList.php
+++ b/src/applications/dashboard/layoutconfig/PhabricatorDashboardPanelRefList.php
@@ -73,4 +73,47 @@
return $this->refs;
}
+ public function getPanelRef($panel_key) {
+ foreach ($this->getPanelRefs() as $ref) {
+ if ($ref->getPanelKey() === $panel_key) {
+ return $ref;
+ }
+ }
+
+ return null;
+ }
+
+ public function toDictionary() {
+ return array_values(mpull($this->getPanelRefs(), 'toDictionary'));
+ }
+
+ public function newPanelRef(PhabricatorDashboardPanel $panel, $column_key) {
+ $ref = id(new PhabricatorDashboardPanelRef())
+ ->setPanelKey($this->newPanelKey())
+ ->setPanelPHID($panel->getPHID())
+ ->setColumnKey($column_key);
+
+ $this->refs[] = $ref;
+
+ return $ref;
+ }
+
+ public function removePanelRef(PhabricatorDashboardPanelRef $target) {
+ foreach ($this->refs as $key => $ref) {
+ if ($ref->getPanelKey() !== $target->getPanelKey()) {
+ continue;
+ }
+
+ unset($this->refs[$key]);
+ return $ref;
+ }
+
+ return null;
+ }
+
+ private function newPanelKey() {
+ return Filesystem::readRandomCharacters(8);
+ }
+
+
}
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,9 +24,6 @@
const STATUS_ACTIVE = 'active';
const STATUS_ARCHIVED = 'archived';
- private $panels = self::ATTACHABLE;
- private $edgeProjectPHIDs = self::ATTACHABLE;
-
private $panelRefList;
public static function initializeNewDashboard(PhabricatorUser $actor) {
@@ -36,8 +33,7 @@
->setViewPolicy(PhabricatorPolicies::getMostOpenPolicy())
->setEditPolicy($actor->getPHID())
->setStatus(self::STATUS_ACTIVE)
- ->setAuthorPHID($actor->getPHID())
- ->attachPanels(array());
+ ->setAuthorPHID($actor->getPHID());
}
public static function getStatusNameMap() {
@@ -62,9 +58,8 @@
) + parent::getConfiguration();
}
- public function generatePHID() {
- return PhabricatorPHID::generateNewPHID(
- PhabricatorDashboardDashboardPHIDType::TYPECONST);
+ public function getPHIDType() {
+ return PhabricatorDashboardDashboardPHIDType::TYPECONST;
}
public function getRawLayoutMode() {
@@ -75,11 +70,18 @@
public function setRawLayoutMode($mode) {
$config = $this->getRawLayoutConfig();
$config['layoutMode'] = $mode;
+ return $this->setRawLayoutConfig($config);
+ }
- // If a cached panel ref list exists, clear it.
- $this->panelRefList = null;
+ public function getRawPanels() {
+ $config = $this->getRawLayoutConfig();
+ return idx($config, 'panels');
+ }
- return $this->setLayoutConfig($config);
+ public function setRawPanels(array $panels) {
+ $config = $this->getRawLayoutConfig();
+ $config['panels'] = $panels;
+ return $this->setRawLayoutConfig($config);
}
private function getRawLayoutConfig() {
@@ -92,6 +94,13 @@
return $config;
}
+ private function setRawLayoutConfig(array $config) {
+ // If a cached panel ref list exists, clear it.
+ $this->panelRefList = null;
+
+ return $this->setLayoutConfig($config);
+ }
+
public function isArchived() {
return ($this->getStatus() == self::STATUS_ARCHIVED);
}
diff --git a/src/applications/dashboard/xaction/dashboard/PhabricatorDashboardPanelsTransaction.php b/src/applications/dashboard/xaction/dashboard/PhabricatorDashboardPanelsTransaction.php
new file mode 100644
--- /dev/null
+++ b/src/applications/dashboard/xaction/dashboard/PhabricatorDashboardPanelsTransaction.php
@@ -0,0 +1,153 @@
+<?php
+
+final class PhabricatorDashboardPanelsTransaction
+ extends PhabricatorDashboardTransactionType {
+
+ const TRANSACTIONTYPE = 'panels';
+
+ public function generateOldValue($object) {
+ return $object->getRawPanels();
+ }
+
+ public function applyInternalEffects($object, $value) {
+ $object->setRawPanels($value);
+ }
+
+ public function getTitle() {
+ return pht(
+ '%s changed the panels on this dashboard.',
+ $this->renderAuthor());
+ }
+
+ public function validateTransactions($object, array $xactions) {
+ $actor = $this->getActor();
+ $errors = array();
+
+ $ref_list = $object->getPanelRefList();
+ $columns = $ref_list->getColumns();
+
+ $old_phids = $object->getPanelPHIDs();
+ $old_phids = array_fuse($old_phids);
+
+ foreach ($xactions as $xaction) {
+ $new_value = $xaction->getNewValue();
+ if (!is_array($new_value)) {
+ $errors[] = $this->newInvalidError(
+ pht('Panels must be a list of panel specifications.'),
+ $xaction);
+ continue;
+ }
+
+ if (!phutil_is_natural_list($new_value)) {
+ $errors[] = $this->newInvalidError(
+ pht('Panels must be a list, not a map.'),
+ $xaction);
+ continue;
+ }
+
+ $new_phids = array();
+ $seen_keys = array();
+ foreach ($new_value as $idx => $spec) {
+ if (!is_array($spec)) {
+ $errors[] = $this->newInvalidError(
+ pht(
+ 'Each panel specification must be a map of panel attributes. '.
+ 'Panel specification at index "%s" is "%s".',
+ $idx,
+ phutil_describe_type($spec)),
+ $xaction);
+ continue;
+ }
+
+ try {
+ PhutilTypeSpec::checkMap(
+ $spec,
+ array(
+ 'panelPHID' => 'string',
+ 'columnKey' => 'string',
+ 'panelKey' => 'string',
+ ));
+ } catch (PhutilTypeCheckException $ex) {
+ $errors[] = $this->newInvalidError(
+ pht(
+ 'Panel specification at index "%s" is invalid: %s',
+ $idx,
+ $ex->getMessage()),
+ $xaction);
+ continue;
+ }
+
+ $panel_key = $spec['panelKey'];
+
+ if (!strlen($panel_key)) {
+ $errors[] = $this->newInvalidError(
+ pht(
+ 'Panel specification at index "%s" has bad panel key "%s". '.
+ 'Panel keys must be nonempty.',
+ $idx,
+ $panel_key),
+ $xaction);
+ continue;
+ }
+
+ if (isset($seen_keys[$panel_key])) {
+ $errors[] = $this->newInvalidError(
+ pht(
+ 'Panel specification at index "%s" has duplicate panel key '.
+ '"%s". Each panel must have a unique panel key.',
+ $idx,
+ $panel_key),
+ $xaction);
+ continue;
+ }
+
+ $seen_keys[$panel_key] = true;
+
+ $panel_phid = $spec['panelPHID'];
+ $new_phids[] = $panel_phid;
+
+ $column_key = $spec['columnKey'];
+
+ if (!isset($columns[$column_key])) {
+ $errors[] = $this->newInvalidError(
+ pht(
+ 'Panel specification at index "%s" has bad column key "%s", '.
+ 'valid column keys are: %s.',
+ $idx,
+ $column_key,
+ implode(', ', array_keys($columns))),
+ $xaction);
+ continue;
+ }
+ }
+
+ $new_phids = array_fuse($new_phids);
+ $add_phids = array_diff_key($new_phids, $old_phids);
+
+ if ($add_phids) {
+ $panels = id(new PhabricatorDashboardPanelQuery())
+ ->setViewer($actor)
+ ->withPHIDs($add_phids)
+ ->execute();
+ $panels = mpull($panels, null, 'getPHID');
+
+ foreach ($add_phids as $add_phid) {
+ $panel = idx($panels, $add_phid);
+
+ if (!$panel) {
+ $errors[] = $this->newInvalidError(
+ pht(
+ 'Panel specification adds panel "%s", but this is not a '.
+ 'valid panel or not a visible panel. You can only add '.
+ 'valid panels which you have permission to see to a dashboard.',
+ $add_phid));
+ continue;
+ }
+ }
+ }
+ }
+
+ return $errors;
+ }
+
+}
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
@@ -12,7 +12,8 @@
var data = {
parentPanelPHIDs: config.parentPanelPHIDs.join(','),
headerMode: config.headerMode,
- dashboardID: config.dashboardID
+ contextPHID: config.contextPHID,
+ panelKey: config.panelKey
};
new JX.Workflow(config.uri)
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sat, Nov 23, 7:51 PM (15 h, 42 m)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
6779462
Default Alt Text
D20408.diff (49 KB)
Attached To
Mode
D20408: Update "add panel" and "remove panel" Dashboard flows to the new panel storage format
Attached
Detach File
Event Timeline
Log In to Comment