1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-11-26 08:42:41 +01:00

When editing a tab panel from a dashboard, redirect back to the dashboard

Summary:
Depends on D20396. Ref T13272. Currently, using the dropdowns to edit a tab panel from a dashboard redirects you to the tab panel page.

Instead, redirect back to the context page (usually, a dashboard -- but theoretically a containing tab panel, since you can put tab panels inside tab panels).

Also, fix some JS issues with non-integer panel keys. I've moved panel keys from "0, 1, 2, ..." to having arbitrary keys to make some operations less flimsy/error-prone, but this needs some JS tweaks.

Test Plan: Edited a tab panel from a dashboard, got sent sensibly back to the dashboard.

Reviewers: amckinley

Reviewed By: amckinley

Maniphest Tasks: T13272

Differential Revision: https://secure.phabricator.com/D20397
This commit is contained in:
epriestley 2019-04-11 09:13:43 -07:00
parent 9ad9ac9be6
commit cbe13b3065
7 changed files with 122 additions and 38 deletions

View file

@ -10,7 +10,7 @@ return array(
'conpherence.pkg.css' => '3c8a0668', 'conpherence.pkg.css' => '3c8a0668',
'conpherence.pkg.js' => '020aebcf', 'conpherence.pkg.js' => '020aebcf',
'core.pkg.css' => '9d654dff', 'core.pkg.css' => '9d654dff',
'core.pkg.js' => '350acda5', 'core.pkg.js' => '794952ae',
'differential.pkg.css' => '8d8360fb', 'differential.pkg.css' => '8d8360fb',
'differential.pkg.js' => '67e02996', 'differential.pkg.js' => '67e02996',
'diffusion.pkg.css' => '42c75c37', 'diffusion.pkg.css' => '42c75c37',
@ -374,7 +374,7 @@ return array(
'rsrc/js/application/dashboard/behavior-dashboard-async-panel.js' => '09ecf50c', 'rsrc/js/application/dashboard/behavior-dashboard-async-panel.js' => '09ecf50c',
'rsrc/js/application/dashboard/behavior-dashboard-move-panels.js' => '076bd092', '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-query-panel-select.js' => '1e413dc9',
'rsrc/js/application/dashboard/behavior-dashboard-tab-panel.js' => '8d4490a2', 'rsrc/js/application/dashboard/behavior-dashboard-tab-panel.js' => '0116d3e8',
'rsrc/js/application/diff/DiffChangeset.js' => 'd0a85a85', 'rsrc/js/application/diff/DiffChangeset.js' => 'd0a85a85',
'rsrc/js/application/diff/DiffChangesetList.js' => '04023d82', 'rsrc/js/application/diff/DiffChangesetList.js' => '04023d82',
'rsrc/js/application/diff/DiffInline.js' => 'a4a14a94', 'rsrc/js/application/diff/DiffInline.js' => 'a4a14a94',
@ -597,7 +597,7 @@ return array(
'javelin-behavior-dashboard-async-panel' => '09ecf50c', 'javelin-behavior-dashboard-async-panel' => '09ecf50c',
'javelin-behavior-dashboard-move-panels' => '076bd092', 'javelin-behavior-dashboard-move-panels' => '076bd092',
'javelin-behavior-dashboard-query-panel-select' => '1e413dc9', 'javelin-behavior-dashboard-query-panel-select' => '1e413dc9',
'javelin-behavior-dashboard-tab-panel' => '8d4490a2', 'javelin-behavior-dashboard-tab-panel' => '0116d3e8',
'javelin-behavior-day-view' => '727a5a61', 'javelin-behavior-day-view' => '727a5a61',
'javelin-behavior-desktop-notifications-control' => '070679fe', 'javelin-behavior-desktop-notifications-control' => '070679fe',
'javelin-behavior-detect-timezone' => '78bc5d94', 'javelin-behavior-detect-timezone' => '78bc5d94',
@ -902,6 +902,11 @@ return array(
'unhandled-exception-css' => '9ecfc00d', 'unhandled-exception-css' => '9ecfc00d',
), ),
'requires' => array( 'requires' => array(
'0116d3e8' => array(
'javelin-behavior',
'javelin-dom',
'javelin-stratcom',
),
'01384686' => array( '01384686' => array(
'javelin-behavior', 'javelin-behavior',
'javelin-uri', 'javelin-uri',
@ -1644,11 +1649,6 @@ return array(
'phabricator-shaped-request', 'phabricator-shaped-request',
'conpherence-thread-manager', 'conpherence-thread-manager',
), ),
'8d4490a2' => array(
'javelin-behavior',
'javelin-dom',
'javelin-stratcom',
),
'8e0aa661' => array( '8e0aa661' => array(
'javelin-install', 'javelin-install',
'javelin-dom', 'javelin-dom',

View file

@ -3,6 +3,17 @@
final class PhabricatorDashboardPanelTabsController final class PhabricatorDashboardPanelTabsController
extends PhabricatorDashboardController { extends PhabricatorDashboardController {
private $contextObject;
private function setContextObject($context_object) {
$this->contextObject = $context_object;
return $this;
}
private function getContextObject() {
return $this->contextObject;
}
public function handleRequest(AphrontRequest $request) { public function handleRequest(AphrontRequest $request) {
$viewer = $this->getViewer(); $viewer = $this->getViewer();
@ -86,6 +97,43 @@ final class PhabricatorDashboardPanelTabsController
} }
} }
// Tab panels may be edited from the panel page, or from the context of
// a dashboard. If we're editing from a dashboard, we want to redirect
// back to the dashboard after making changes.
$context_phid = $request->getStr('contextPHID');
$context = null;
if (strlen($context_phid)) {
$context = id(new PhabricatorObjectQuery())
->setViewer($viewer)
->withPHIDs(array($context_phid))
->executeOne();
if (!$context) {
return new Aphront404Response();
}
switch (phid_get_type($context_phid)) {
case PhabricatorDashboardDashboardPHIDType::TYPECONST:
$cancel_uri = $context->getURI();
break;
case PhabricatorDashboardPanelPHIDType::TYPECONST:
$cancel_uri = $context->getURI();
break;
default:
return $this->newDialog()
->setTitle(pht('Context Object Unsupported'))
->appendParagraph(
pht(
'Context object ("%s") has unsupported type. Panels should '.
'be rendered from the context of a dashboard or another '.
'panel.',
$context_phid))
->addCancelButton($cancel_uri);
}
$this->setContextObject($context);
}
switch ($op) { switch ($op) {
case 'add': case 'add':
return $this->handleAddOperation($panel, $after, $cancel_uri); return $this->handleAddOperation($panel, $after, $cancel_uri);
@ -176,10 +224,9 @@ final class PhabricatorDashboardPanelTabsController
->setLabel(pht('Panel')) ->setLabel(pht('Panel'))
->setValue($v_panel)); ->setValue($v_panel));
return $this->newDialog() return $this->newEditDialog()
->setTitle(pht('Choose Dashboard Panel')) ->setTitle(pht('Choose Dashboard Panel'))
->setErrors($errors) ->setErrors($errors)
->setWidth(AphrontDialogView::WIDTH_FORM)
->addHiddenInput('after', $after) ->addHiddenInput('after', $after)
->appendForm($form) ->appendForm($form)
->addCancelButton($cancel_uri) ->addCancelButton($cancel_uri)
@ -205,7 +252,7 @@ final class PhabricatorDashboardPanelTabsController
return id(new AphrontRedirectResponse())->setURI($cancel_uri); return id(new AphrontRedirectResponse())->setURI($cancel_uri);
} }
return $this->newDialog() return $this->newEditDialog()
->setTitle(pht('Remove tab?')) ->setTitle(pht('Remove tab?'))
->addHiddenInput('target', $target) ->addHiddenInput('target', $target)
->appendParagraph(pht('Really remove this tab?')) ->appendParagraph(pht('Really remove this tab?'))
@ -243,7 +290,7 @@ final class PhabricatorDashboardPanelTabsController
->setName('name') ->setName('name')
->setLabel(pht('Tab Name'))); ->setLabel(pht('Tab Name')));
return $this->newDialog() return $this->newEditDialog()
->setTitle(pht('Rename Panel')) ->setTitle(pht('Rename Panel'))
->addHiddenInput('target', $target) ->addHiddenInput('target', $target)
->appendForm($form) ->appendForm($form)
@ -292,4 +339,16 @@ final class PhabricatorDashboardPanelTabsController
return $config; return $config;
} }
protected function newEditDialog() {
$dialog = $this->newDialog()
->setWidth(AphrontDialogView::WIDTH_FORM);
$context = $this->getContextObject();
if ($context) {
$dialog->addHiddenInput('contextPHID', $context->getPHID());
}
return $dialog;
}
} }

View file

@ -42,6 +42,7 @@ final class PhabricatorDashboardPanelViewController
$rendered_panel = id(new PhabricatorDashboardPanelRenderingEngine()) $rendered_panel = id(new PhabricatorDashboardPanelRenderingEngine())
->setViewer($viewer) ->setViewer($viewer)
->setPanel($panel) ->setPanel($panel)
->setContextObject($panel)
->setPanelPHID($panel->getPHID()) ->setPanelPHID($panel->getPHID())
->setParentPanelPHIDs(array()) ->setParentPanelPHIDs(array())
->setEditMode(true) ->setEditMode(true)
@ -69,18 +70,11 @@ final class PhabricatorDashboardPanelViewController
$viewer = $this->getViewer(); $viewer = $this->getViewer();
$id = $panel->getID(); $id = $panel->getID();
$button = id(new PHUIButtonView())
->setTag('a')
->setText(pht('View Panel'))
->setIcon('fa-columns')
->setHref($this->getApplicationURI("panel/render/{$id}/"));
$header = id(new PHUIHeaderView()) $header = id(new PHUIHeaderView())
->setUser($viewer) ->setUser($viewer)
->setHeader($panel->getName()) ->setHeader($panel->getName())
->setPolicyObject($panel) ->setPolicyObject($panel)
->setHeaderIcon('fa-columns') ->setHeaderIcon('fa-window-maximize');
->addActionLink($button);
if (!$panel->getIsArchived()) { if (!$panel->getIsArchived()) {
$header->setStatus('fa-check', 'bluegrey', pht('Active')); $header->setStatus('fa-check', 'bluegrey', pht('Active'));

View file

@ -16,6 +16,16 @@ final class PhabricatorDashboardPanelRenderingEngine extends Phobject {
private $movable = true; private $movable = true;
private $panelHandle; private $panelHandle;
private $editMode; private $editMode;
private $contextObject;
public function setContextObject($object) {
$this->contextObject = $object;
return $this;
}
public function getContextObject() {
return $this->contextObject;
}
public function setDashboardID($id) { public function setDashboardID($id) {
$this->dashboardID = $id; $this->dashboardID = $id;

View file

@ -73,6 +73,7 @@ final class PhabricatorDashboardRenderingEngine extends Phobject {
->setViewer($viewer) ->setViewer($viewer)
->setDashboardID($dashboard->getID()) ->setDashboardID($dashboard->getID())
->setEnableAsyncRendering(true) ->setEnableAsyncRendering(true)
->setContextObject($dashboard)
->setPanelPHID($panel_phid) ->setPanelPHID($panel_phid)
->setParentPanelPHIDs(array()) ->setParentPanelPHIDs(array())
->setHeaderMode($h_mode) ->setHeaderMode($h_mode)

View file

@ -51,14 +51,16 @@ final class PhabricatorDashboardTabsPanelType
$is_edit = $engine->isEditMode(); $is_edit = $engine->isEditMode();
$config = $this->getPanelConfiguration($panel); $config = $this->getPanelConfiguration($panel);
$context_object = $engine->getContextObject();
if (!$context_object) {
$context_object = $panel;
}
$context_phid = $context_object->getPHID();
$list = id(new PHUIListView()) $list = id(new PHUIListView())
->setType(PHUIListView::NAVBAR_LIST); ->setType(PHUIListView::NAVBAR_LIST);
$node_ids = array();
foreach ($config as $idx => $tab_spec) {
$node_ids[$idx] = celerity_generate_unique_node_id();
}
$ids = ipull($config, 'panelID'); $ids = ipull($config, 'panelID');
if ($ids) { if ($ids) {
$panels = id(new PhabricatorDashboardPanelQuery()) $panels = id(new PhabricatorDashboardPanelQuery())
@ -72,13 +74,16 @@ final class PhabricatorDashboardTabsPanelType
$id = $panel->getID(); $id = $panel->getID();
$add_uri = urisprintf('/dashboard/panel/tabs/%d/add/', $id); $add_uri = urisprintf('/dashboard/panel/tabs/%d/add/', $id);
$add_uri = new PhutilURI($add_uri); $add_uri = id(new PhutilURI($add_uri))
->replaceQueryParam('contextPHID', $context_phid);
$remove_uri = urisprintf('/dashboard/panel/tabs/%d/remove/', $id); $remove_uri = urisprintf('/dashboard/panel/tabs/%d/remove/', $id);
$remove_uri = new PhutilURI($remove_uri); $remove_uri = id(new PhutilURI($remove_uri))
->replaceQueryParam('contextPHID', $context_phid);
$rename_uri = urisprintf('/dashboard/panel/tabs/%d/rename/', $id); $rename_uri = urisprintf('/dashboard/panel/tabs/%d/rename/', $id);
$rename_uri = new PhutilURI($rename_uri); $rename_uri = id(new PhutilURI($rename_uri))
->replaceQueryParam('contextPHID', $context_phid);
$selected = 0; $selected = 0;
@ -102,7 +107,7 @@ final class PhabricatorDashboardTabsPanelType
->setHref('#') ->setHref('#')
->setSelected($idx == $selected) ->setSelected($idx == $selected)
->addSigil('dashboard-tab-panel-tab') ->addSigil('dashboard-tab-panel-tab')
->setMetadata(array('idx' => $idx)) ->setMetadata(array('panelKey' => $idx))
->setName($name); ->setName($name);
if ($is_edit) { if ($is_edit) {
@ -212,6 +217,7 @@ final class PhabricatorDashboardTabsPanelType
// remains selected across page loads. // remains selected across page loads.
$content = array(); $content = array();
$panel_list = array();
$no_headers = PhabricatorDashboardPanelRenderingEngine::HEADER_MODE_NONE; $no_headers = PhabricatorDashboardPanelRenderingEngine::HEADER_MODE_NONE;
foreach ($config as $idx => $tab_spec) { foreach ($config as $idx => $tab_spec) {
$panel_id = idx($tab_spec, 'panelID'); $panel_id = idx($tab_spec, 'panelID');
@ -221,6 +227,7 @@ final class PhabricatorDashboardTabsPanelType
$panel_content = id(new PhabricatorDashboardPanelRenderingEngine()) $panel_content = id(new PhabricatorDashboardPanelRenderingEngine())
->setViewer($viewer) ->setViewer($viewer)
->setEnableAsyncRendering(true) ->setEnableAsyncRendering(true)
->setContextObject($context_object)
->setParentPanelPHIDs($parent_phids) ->setParentPanelPHIDs($parent_phids)
->setPanel($subpanel) ->setPanel($subpanel)
->setPanelPHID($subpanel->getPHID()) ->setPanelPHID($subpanel->getPHID())
@ -231,13 +238,20 @@ final class PhabricatorDashboardTabsPanelType
$panel_content = pht('(Invalid Panel)'); $panel_content = pht('(Invalid Panel)');
} }
$content_id = celerity_generate_unique_node_id();
$content[] = phutil_tag( $content[] = phutil_tag(
'div', 'div',
array( array(
'id' => $node_ids[$idx], 'id' => $content_id,
'style' => ($idx == $selected) ? null : 'display: none', 'style' => ($idx == $selected) ? null : 'display: none',
), ),
$panel_content); $panel_content);
$panel_list[] = array(
'panelKey' => (string)$idx,
'panelContentID' => $content_id,
);
} }
if (!$content) { if (!$content) {
@ -269,7 +283,7 @@ final class PhabricatorDashboardTabsPanelType
array( array(
'sigil' => 'dashboard-tab-panel-container', 'sigil' => 'dashboard-tab-panel-container',
'meta' => array( 'meta' => array(
'panels' => $node_ids, 'panels' => $panel_list,
), ),
), ),
array( array(

View file

@ -18,26 +18,32 @@ JX.behavior('dashboard-tab-panel', function() {
e.kill(); e.kill();
var ii; var selected_key = e.getNodeData('dashboard-tab-panel-tab').panelKey;
var idx = e.getNodeData('dashboard-tab-panel-tab').idx;
var root = e.getNode('dashboard-tab-panel-container'); var root = e.getNode('dashboard-tab-panel-container');
var data = JX.Stratcom.getData(root); var data = JX.Stratcom.getData(root);
var ii;
// Give the tab the user clicked a selected style, and remove it from // Give the tab the user clicked a selected style, and remove it from
// the other tabs. // the other tabs.
var tabs = JX.DOM.scry(root, 'li', 'dashboard-tab-panel-tab'); var tabs = JX.DOM.scry(root, 'li', 'dashboard-tab-panel-tab');
for (ii = 0; ii < tabs.length; ii++) { for (ii = 0; ii < tabs.length; ii++) {
JX.DOM.alterClass(tabs[ii], 'phui-list-item-selected', (ii == idx)); var tab = tabs[ii];
var tab_data = JX.Stratcom.getData(tab);
var is_selected = (tab_data.panelKey === selected_key);
JX.DOM.alterClass(tabs[ii], 'phui-list-item-selected', is_selected);
} }
// Switch the visible content to correspond to whatever the user clicked. // Switch the visible content to correspond to whatever the user clicked.
for (ii = 0; ii < data.panels.length; ii++) { for (ii = 0; ii < data.panels.length; ii++) {
var panel = JX.$(data.panels[ii]); var panel = data.panels[ii];
if (ii == idx) { var node = JX.$(panel.panelContentID);
JX.DOM.show(panel);
if (panel.panelKey == selected_key) {
JX.DOM.show(node);
} else { } else {
JX.DOM.hide(panel); JX.DOM.hide(node);
} }
} }