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:
parent
9ad9ac9be6
commit
cbe13b3065
7 changed files with 122 additions and 38 deletions
|
@ -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',
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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'));
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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(
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue