Page MenuHomePhabricator

D9505.diff
No OneTemporary

D9505.diff

diff --git a/resources/celerity/map.php b/resources/celerity/map.php
--- a/resources/celerity/map.php
+++ b/resources/celerity/map.php
@@ -8,7 +8,7 @@
'names' =>
array(
'core.pkg.css' => 'c76b553b',
- 'core.pkg.js' => '0627d27e',
+ 'core.pkg.js' => '8335fe3f',
'darkconsole.pkg.js' => 'ca8671ce',
'differential.pkg.css' => '4a93db37',
'differential.pkg.js' => 'eca39a2c',
@@ -51,7 +51,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' => 'f0092e3e',
+ 'rsrc/css/application/dashboard/dashboard.css' => '0594a469',
'rsrc/css/application/diff/inline-comment-summary.css' => '8cfd34e8',
'rsrc/css/application/differential/add-comment.css' => 'c478bcaa',
'rsrc/css/application/differential/changeset-view.css' => 'ff8eacf8',
@@ -423,7 +423,7 @@
'rsrc/js/application/uiexample/notification-example.js' => 'c51a6616',
'rsrc/js/core/Busy.js' => '6453c869',
'rsrc/js/core/DragAndDropFileUpload.js' => 'ae6abfba',
- 'rsrc/js/core/DraggableList.js' => '1681c4d4',
+ 'rsrc/js/core/DraggableList.js' => '109e2a87',
'rsrc/js/core/FileUpload.js' => 'a4ae61bf',
'rsrc/js/core/Hovercard.js' => '4f344388',
'rsrc/js/core/KeyboardShortcut.js' => '1ae869f2',
@@ -694,9 +694,9 @@
'phabricator-core-css' => '40151074',
'phabricator-countdown-css' => '86b7b0a0',
'phabricator-crumbs-view-css' => '7fbf25b8',
- 'phabricator-dashboard-css' => 'f0092e3e',
+ 'phabricator-dashboard-css' => '0594a469',
'phabricator-drag-and-drop-file-upload' => 'ae6abfba',
- 'phabricator-draggable-list' => '1681c4d4',
+ 'phabricator-draggable-list' => '109e2a87',
'phabricator-fatal-config-template-css' => '25d446d6',
'phabricator-feed-css' => 'dd43ce00',
'phabricator-file-upload' => 'a4ae61bf',
@@ -913,6 +913,15 @@
1 => 'javelin-uri',
2 => 'javelin-install',
),
+ '109e2a87' =>
+ array(
+ 0 => 'javelin-install',
+ 1 => 'javelin-dom',
+ 2 => 'javelin-stratcom',
+ 3 => 'javelin-util',
+ 4 => 'javelin-vector',
+ 5 => 'javelin-magical-init',
+ ),
'127f2018' =>
array(
0 => 'javelin-behavior',
@@ -922,15 +931,6 @@
4 => 'javelin-util',
5 => 'phabricator-shaped-request',
),
- '1681c4d4' =>
- array(
- 0 => 'javelin-install',
- 1 => 'javelin-dom',
- 2 => 'javelin-stratcom',
- 3 => 'javelin-util',
- 4 => 'javelin-vector',
- 5 => 'javelin-magical-init',
- ),
'1693a296' =>
array(
0 => 'javelin-behavior',
diff --git a/src/applications/dashboard/controller/PhabricatorDashboardManageController.php b/src/applications/dashboard/controller/PhabricatorDashboardManageController.php
--- a/src/applications/dashboard/controller/PhabricatorDashboardManageController.php
+++ b/src/applications/dashboard/controller/PhabricatorDashboardManageController.php
@@ -15,6 +15,10 @@
$id = $this->id;
$dashboard_uri = $this->getApplicationURI('view/'.$id.'/');
+ // TODO: This UI should drop a lot of capabilities if the user can't
+ // edit the dashboard, but we should still let them in for "Install" and
+ // "View History".
+
$dashboard = id(new PhabricatorDashboardQuery())
->setViewer($viewer)
->withIDs(array($this->id))
diff --git a/src/applications/dashboard/controller/PhabricatorDashboardPanelEditController.php b/src/applications/dashboard/controller/PhabricatorDashboardPanelEditController.php
--- a/src/applications/dashboard/controller/PhabricatorDashboardPanelEditController.php
+++ b/src/applications/dashboard/controller/PhabricatorDashboardPanelEditController.php
@@ -38,19 +38,45 @@
if ($this->id) {
$is_create = false;
+ if ($dashboard) {
+ $capabilities = array(
+ PhabricatorPolicyCapability::CAN_VIEW,
+ );
+ } else {
+ $capabilities = array(
+ PhabricatorPolicyCapability::CAN_VIEW,
+ PhabricatorPolicyCapability::CAN_EDIT,
+ );
+ }
+
$panel = id(new PhabricatorDashboardPanelQuery())
->setViewer($viewer)
->withIDs(array($this->id))
- ->requireCapabilities(
- array(
- PhabricatorPolicyCapability::CAN_VIEW,
- PhabricatorPolicyCapability::CAN_EDIT,
- ))
+ ->requireCapabilities($capabilities)
->executeOne();
if (!$panel) {
return new Aphront404Response();
}
+ if ($dashboard) {
+ $can_edit = PhabricatorPolicyFilter::hasCapability(
+ $viewer,
+ $panel,
+ PhabricatorPolicyCapability::CAN_EDIT);
+ if (!$can_edit) {
+ if ($request->isFormPost() && $request->getBool('copy')) {
+ $panel = $this->copyPanel(
+ $request,
+ $dashboard,
+ $panel);
+ } else {
+ return $this->processPanelCloneRequest(
+ $request,
+ $dashboard,
+ $panel);
+ }
+ }
+ }
} else {
$is_create = true;
@@ -161,6 +187,10 @@
}
}
+ // NOTE: We're setting the submit URI explicitly because we need to edit
+ // a different panel if we just cloned the original panel.
+ $submit_uri = $this->getApplicationURI('panel/edit/'.$panel->getID().'/');
+
$policies = id(new PhabricatorPolicyQuery())
->setViewer($viewer)
->setObject($panel)
@@ -168,6 +198,7 @@
$form = id(new AphrontFormView())
->setUser($viewer)
+ ->setAction($submit_uri)
->addHiddenInput('edit', true)
->addHiddenInput('dashboardID', $request->getInt('dashboardID'))
->addHiddenInput('column', $request->getInt('column'))
@@ -209,6 +240,7 @@
if ($request->isAjax()) {
return $this->newDialog()
->setTitle($header)
+ ->setSubmitURI($submit_uri)
->setWidth(AphrontDialogView::WIDTH_FORM)
->setValidationException($validation_exception)
->appendChild($form->buildLayoutView())
@@ -317,4 +349,79 @@
));
}
+ private function processPanelCloneRequest(
+ AphrontRequest $request,
+ PhabricatorDashboard $dashboard,
+ PhabricatorDashboardPanel $panel) {
+
+ $viewer = $request->getUser();
+
+ $manage_uri = $this->getApplicationURI('manage/'.$dashboard->getID().'/');
+
+ return $this->newDialog()
+ ->setTitle(pht('Copy Panel?'))
+ ->addHiddenInput('copy', true)
+ ->addHiddenInput('dashboardID', $request->getInt('dashboardID'))
+ ->addHiddenInput('column', $request->getInt('column'))
+ ->appendParagraph(
+ pht(
+ 'You do not have permission to edit this dashboard panel, but you '.
+ 'can make a copy and edit that instead. If you choose to copy the '.
+ 'panel, the original will be replaced with the new copy on this '.
+ 'dashboard.'))
+ ->appendParagraph(
+ pht(
+ 'Do you want to make a copy of this panel?'))
+ ->addCancelButton($manage_uri)
+ ->addSubmitButton(pht('Copy Panel'));
+ }
+
+ private function copyPanel(
+ AphrontRequest $request,
+ PhabricatorDashboard $dashboard,
+ PhabricatorDashboardPanel $panel) {
+
+ $viewer = $request->getUser();
+
+ $copy = PhabricatorDashboardPanel::initializeNewPanel($viewer);
+ $copy = PhabricatorDashboardPanel::copyPanel($copy, $panel);
+
+ $copy->openTransaction();
+ $copy->save();
+
+ // TODO: This should record a transaction on the panel copy, too.
+
+ $xactions = array();
+ $xactions[] = id(new PhabricatorDashboardTransaction())
+ ->setTransactionType(PhabricatorTransactions::TYPE_EDGE)
+ ->setMetadataValue(
+ 'edge:type',
+ PhabricatorEdgeConfig::TYPE_DASHBOARD_HAS_PANEL)
+ ->setNewValue(
+ array(
+ '+' => array(
+ $copy->getPHID() => $copy->getPHID(),
+ ),
+ '-' => array(
+ $panel->getPHID() => $panel->getPHID(),
+ ),
+ ));
+
+ $layout_config = $dashboard->getLayoutConfigObject();
+ $layout_config->replacePanel($panel->getPHID(), $copy->getPHID());
+ $dashboard->setLayoutConfigFromObject($layout_config);
+ $dashboard->save();
+
+ $editor = id(new PhabricatorDashboardTransactionEditor())
+ ->setActor($viewer)
+ ->setContentSourceFromRequest($request)
+ ->setContinueOnMissingFields(true)
+ ->setContinueOnNoEffect(true)
+ ->applyTransactions($dashboard, $xactions);
+ $copy->saveTransaction();
+
+ return $copy;
+ }
+
+
}
diff --git a/src/applications/dashboard/layoutconfig/PhabricatorDashboardLayoutConfig.php b/src/applications/dashboard/layoutconfig/PhabricatorDashboardLayoutConfig.php
--- a/src/applications/dashboard/layoutconfig/PhabricatorDashboardLayoutConfig.php
+++ b/src/applications/dashboard/layoutconfig/PhabricatorDashboardLayoutConfig.php
@@ -32,6 +32,18 @@
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) {
diff --git a/src/applications/dashboard/storage/PhabricatorDashboardPanel.php b/src/applications/dashboard/storage/PhabricatorDashboardPanel.php
--- a/src/applications/dashboard/storage/PhabricatorDashboardPanel.php
+++ b/src/applications/dashboard/storage/PhabricatorDashboardPanel.php
@@ -24,6 +24,14 @@
->setEditPolicy($actor->getPHID());
}
+ public static function copyPanel($dst, $src) {
+ $dst->name = $src->name;
+ $dst->panelType = $src->panelType;
+ $dst->properties = $src->properties;
+
+ return $dst;
+ }
+
public function getConfiguration() {
return array(
self::CONFIG_AUX_PHID => true,
diff --git a/webroot/rsrc/js/core/DraggableList.js b/webroot/rsrc/js/core/DraggableList.js
--- a/webroot/rsrc/js/core/DraggableList.js
+++ b/webroot/rsrc/js/core/DraggableList.js
@@ -151,6 +151,17 @@
return;
}
+ if (e.getNode('tag:a')) {
+ // Never start a drag if we're somewhere inside an <a> tag. This makes
+ // links unclickable in Firefox.
+ return;
+ }
+
+ if (JX.Stratcom.pass()) {
+ // Let other handlers deal with this event before we do.
+ return;
+ }
+
e.kill();
this._dragging = e.getNode(this._sigil);

File Metadata

Mime Type
text/plain
Expires
May 14 2024, 12:23 AM (4 w, 5 d ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
6294428
Default Alt Text
D9505.diff (10 KB)

Event Timeline