mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-14 02:42:40 +01:00
Rebuild Dashboards on EditEngine: v1 Major Jank Edition
Summary: Depends on D20383. Ref T13272. Fixes T12363. See PHI997. This gets the edit flows for tab panels functional again. They aren't //nice//, and a lot of the workflows are fairly janky: for example, most of them end up with you on the tab panel's page, which isn't useful if you started on a dashboard page. However, these flows were extremely janky before anyway (see T12363) and I suspect this is a net improvement even though it's a bit of a mess. I anticipate cleaning this up bit-by-bit in future diffs. Test Plan: {F6366372} Reviewers: amckinley Reviewed By: amckinley Maniphest Tasks: T13272, T12363 Differential Revision: https://secure.phabricator.com/D20384
This commit is contained in:
parent
fb19310631
commit
a35fda2019
10 changed files with 519 additions and 28 deletions
|
@ -9,7 +9,7 @@ return array(
|
||||||
'names' => array(
|
'names' => array(
|
||||||
'conpherence.pkg.css' => '3c8a0668',
|
'conpherence.pkg.css' => '3c8a0668',
|
||||||
'conpherence.pkg.js' => '020aebcf',
|
'conpherence.pkg.js' => '020aebcf',
|
||||||
'core.pkg.css' => '2d4810eb',
|
'core.pkg.css' => '671b9fae',
|
||||||
'core.pkg.js' => 'c783d8f6',
|
'core.pkg.js' => 'c783d8f6',
|
||||||
'differential.pkg.css' => '8d8360fb',
|
'differential.pkg.css' => '8d8360fb',
|
||||||
'differential.pkg.js' => '67e02996',
|
'differential.pkg.js' => '67e02996',
|
||||||
|
@ -134,7 +134,7 @@ return array(
|
||||||
'rsrc/css/phui/object-item/phui-oi-flush-ui.css' => '490e2e2e',
|
'rsrc/css/phui/object-item/phui-oi-flush-ui.css' => '490e2e2e',
|
||||||
'rsrc/css/phui/object-item/phui-oi-list-view.css' => 'f14f2422',
|
'rsrc/css/phui/object-item/phui-oi-list-view.css' => 'f14f2422',
|
||||||
'rsrc/css/phui/object-item/phui-oi-simple-ui.css' => '6a30fa46',
|
'rsrc/css/phui/object-item/phui-oi-simple-ui.css' => '6a30fa46',
|
||||||
'rsrc/css/phui/phui-action-list.css' => 'c4972757',
|
'rsrc/css/phui/phui-action-list.css' => 'c34af376',
|
||||||
'rsrc/css/phui/phui-action-panel.css' => '6c386cbf',
|
'rsrc/css/phui/phui-action-panel.css' => '6c386cbf',
|
||||||
'rsrc/css/phui/phui-badge.css' => '666e25ad',
|
'rsrc/css/phui/phui-badge.css' => '666e25ad',
|
||||||
'rsrc/css/phui/phui-basic-nav-view.css' => '56ebd66d',
|
'rsrc/css/phui/phui-basic-nav-view.css' => '56ebd66d',
|
||||||
|
@ -757,7 +757,7 @@ return array(
|
||||||
'path-typeahead' => 'ad486db3',
|
'path-typeahead' => 'ad486db3',
|
||||||
'people-picture-menu-item-css' => 'fe8e07cf',
|
'people-picture-menu-item-css' => 'fe8e07cf',
|
||||||
'people-profile-css' => '2ea2daa1',
|
'people-profile-css' => '2ea2daa1',
|
||||||
'phabricator-action-list-view-css' => 'c4972757',
|
'phabricator-action-list-view-css' => 'c34af376',
|
||||||
'phabricator-busy' => '5202e831',
|
'phabricator-busy' => '5202e831',
|
||||||
'phabricator-chatlog-css' => 'abdc76ee',
|
'phabricator-chatlog-css' => 'abdc76ee',
|
||||||
'phabricator-content-source-view-css' => 'cdf0d579',
|
'phabricator-content-source-view-css' => 'cdf0d579',
|
||||||
|
|
|
@ -2942,6 +2942,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorDashboardPanelRenderingEngine' => 'applications/dashboard/engine/PhabricatorDashboardPanelRenderingEngine.php',
|
'PhabricatorDashboardPanelRenderingEngine' => 'applications/dashboard/engine/PhabricatorDashboardPanelRenderingEngine.php',
|
||||||
'PhabricatorDashboardPanelSearchEngine' => 'applications/dashboard/query/PhabricatorDashboardPanelSearchEngine.php',
|
'PhabricatorDashboardPanelSearchEngine' => 'applications/dashboard/query/PhabricatorDashboardPanelSearchEngine.php',
|
||||||
'PhabricatorDashboardPanelStatusTransaction' => 'applications/dashboard/xaction/panel/PhabricatorDashboardPanelStatusTransaction.php',
|
'PhabricatorDashboardPanelStatusTransaction' => 'applications/dashboard/xaction/panel/PhabricatorDashboardPanelStatusTransaction.php',
|
||||||
|
'PhabricatorDashboardPanelTabsController' => 'applications/dashboard/controller/panel/PhabricatorDashboardPanelTabsController.php',
|
||||||
'PhabricatorDashboardPanelTransaction' => 'applications/dashboard/storage/PhabricatorDashboardPanelTransaction.php',
|
'PhabricatorDashboardPanelTransaction' => 'applications/dashboard/storage/PhabricatorDashboardPanelTransaction.php',
|
||||||
'PhabricatorDashboardPanelTransactionEditor' => 'applications/dashboard/editor/PhabricatorDashboardPanelTransactionEditor.php',
|
'PhabricatorDashboardPanelTransactionEditor' => 'applications/dashboard/editor/PhabricatorDashboardPanelTransactionEditor.php',
|
||||||
'PhabricatorDashboardPanelTransactionQuery' => 'applications/dashboard/query/PhabricatorDashboardPanelTransactionQuery.php',
|
'PhabricatorDashboardPanelTransactionQuery' => 'applications/dashboard/query/PhabricatorDashboardPanelTransactionQuery.php',
|
||||||
|
@ -2984,6 +2985,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorDashboardRenderingEngine' => 'applications/dashboard/engine/PhabricatorDashboardRenderingEngine.php',
|
'PhabricatorDashboardRenderingEngine' => 'applications/dashboard/engine/PhabricatorDashboardRenderingEngine.php',
|
||||||
'PhabricatorDashboardSchemaSpec' => 'applications/dashboard/storage/PhabricatorDashboardSchemaSpec.php',
|
'PhabricatorDashboardSchemaSpec' => 'applications/dashboard/storage/PhabricatorDashboardSchemaSpec.php',
|
||||||
'PhabricatorDashboardSearchEngine' => 'applications/dashboard/query/PhabricatorDashboardSearchEngine.php',
|
'PhabricatorDashboardSearchEngine' => 'applications/dashboard/query/PhabricatorDashboardSearchEngine.php',
|
||||||
|
'PhabricatorDashboardTabsPanelTabsTransaction' => 'applications/dashboard/xaction/panel/PhabricatorDashboardTabsPanelTabsTransaction.php',
|
||||||
'PhabricatorDashboardTabsPanelType' => 'applications/dashboard/paneltype/PhabricatorDashboardTabsPanelType.php',
|
'PhabricatorDashboardTabsPanelType' => 'applications/dashboard/paneltype/PhabricatorDashboardTabsPanelType.php',
|
||||||
'PhabricatorDashboardTextPanelTextTransaction' => 'applications/dashboard/xaction/panel/PhabricatorDashboardTextPanelTextTransaction.php',
|
'PhabricatorDashboardTextPanelTextTransaction' => 'applications/dashboard/xaction/panel/PhabricatorDashboardTextPanelTextTransaction.php',
|
||||||
'PhabricatorDashboardTextPanelType' => 'applications/dashboard/paneltype/PhabricatorDashboardTextPanelType.php',
|
'PhabricatorDashboardTextPanelType' => 'applications/dashboard/paneltype/PhabricatorDashboardTextPanelType.php',
|
||||||
|
@ -8920,6 +8922,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorDashboardPanelRenderingEngine' => 'Phobject',
|
'PhabricatorDashboardPanelRenderingEngine' => 'Phobject',
|
||||||
'PhabricatorDashboardPanelSearchEngine' => 'PhabricatorApplicationSearchEngine',
|
'PhabricatorDashboardPanelSearchEngine' => 'PhabricatorApplicationSearchEngine',
|
||||||
'PhabricatorDashboardPanelStatusTransaction' => 'PhabricatorDashboardPanelTransactionType',
|
'PhabricatorDashboardPanelStatusTransaction' => 'PhabricatorDashboardPanelTransactionType',
|
||||||
|
'PhabricatorDashboardPanelTabsController' => 'PhabricatorDashboardController',
|
||||||
'PhabricatorDashboardPanelTransaction' => 'PhabricatorModularTransaction',
|
'PhabricatorDashboardPanelTransaction' => 'PhabricatorModularTransaction',
|
||||||
'PhabricatorDashboardPanelTransactionEditor' => 'PhabricatorApplicationTransactionEditor',
|
'PhabricatorDashboardPanelTransactionEditor' => 'PhabricatorApplicationTransactionEditor',
|
||||||
'PhabricatorDashboardPanelTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
|
'PhabricatorDashboardPanelTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
|
||||||
|
@ -8967,6 +8970,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorDashboardRenderingEngine' => 'Phobject',
|
'PhabricatorDashboardRenderingEngine' => 'Phobject',
|
||||||
'PhabricatorDashboardSchemaSpec' => 'PhabricatorConfigSchemaSpec',
|
'PhabricatorDashboardSchemaSpec' => 'PhabricatorConfigSchemaSpec',
|
||||||
'PhabricatorDashboardSearchEngine' => 'PhabricatorApplicationSearchEngine',
|
'PhabricatorDashboardSearchEngine' => 'PhabricatorApplicationSearchEngine',
|
||||||
|
'PhabricatorDashboardTabsPanelTabsTransaction' => 'PhabricatorDashboardPanelPropertyTransaction',
|
||||||
'PhabricatorDashboardTabsPanelType' => 'PhabricatorDashboardPanelType',
|
'PhabricatorDashboardTabsPanelType' => 'PhabricatorDashboardPanelType',
|
||||||
'PhabricatorDashboardTextPanelTextTransaction' => 'PhabricatorDashboardPanelPropertyTransaction',
|
'PhabricatorDashboardTextPanelTextTransaction' => 'PhabricatorDashboardPanelPropertyTransaction',
|
||||||
'PhabricatorDashboardTextPanelType' => 'PhabricatorDashboardPanelType',
|
'PhabricatorDashboardTextPanelType' => 'PhabricatorDashboardPanelType',
|
||||||
|
|
|
@ -62,6 +62,8 @@ final class PhabricatorDashboardApplication extends PhabricatorApplication {
|
||||||
'render/(?P<id>\d+)/' => 'PhabricatorDashboardPanelRenderController',
|
'render/(?P<id>\d+)/' => 'PhabricatorDashboardPanelRenderController',
|
||||||
'archive/(?P<id>\d+)/'
|
'archive/(?P<id>\d+)/'
|
||||||
=> 'PhabricatorDashboardPanelArchiveController',
|
=> 'PhabricatorDashboardPanelArchiveController',
|
||||||
|
'tabs/(?P<id>\d+)/(?P<op>add|move|remove|rename)/'
|
||||||
|
=> 'PhabricatorDashboardPanelTabsController',
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
'/portal/' => array(
|
'/portal/' => array(
|
||||||
|
|
|
@ -0,0 +1,295 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorDashboardPanelTabsController
|
||||||
|
extends PhabricatorDashboardController {
|
||||||
|
|
||||||
|
public function handleRequest(AphrontRequest $request) {
|
||||||
|
$viewer = $this->getViewer();
|
||||||
|
|
||||||
|
$panel = id(new PhabricatorDashboardPanelQuery())
|
||||||
|
->setViewer($viewer)
|
||||||
|
->withIDs(array($request->getURIData('id')))
|
||||||
|
->requireCapabilities(
|
||||||
|
array(
|
||||||
|
PhabricatorPolicyCapability::CAN_VIEW,
|
||||||
|
PhabricatorPolicyCapability::CAN_EDIT,
|
||||||
|
))
|
||||||
|
->executeOne();
|
||||||
|
if (!$panel) {
|
||||||
|
return new Aphront404Response();
|
||||||
|
}
|
||||||
|
|
||||||
|
$tabs_type = id(new PhabricatorDashboardTabsPanelType())
|
||||||
|
->getPanelTypeKey();
|
||||||
|
|
||||||
|
// This controller may only be used to edit tab panels.
|
||||||
|
$panel_type = $panel->getPanelType();
|
||||||
|
if ($panel_type !== $tabs_type) {
|
||||||
|
return new Aphront404Response();
|
||||||
|
}
|
||||||
|
|
||||||
|
$op = $request->getURIData('op');
|
||||||
|
$after = $request->getStr('after');
|
||||||
|
if (!strlen($after)) {
|
||||||
|
$after = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$target = $request->getStr('target');
|
||||||
|
if (!strlen($target)) {
|
||||||
|
$target = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$impl = $panel->getImplementation();
|
||||||
|
$config = $impl->getPanelConfiguration($panel);
|
||||||
|
|
||||||
|
$cancel_uri = $panel->getURI();
|
||||||
|
|
||||||
|
if ($after !== null) {
|
||||||
|
$found = false;
|
||||||
|
foreach ($config as $key => $spec) {
|
||||||
|
if ((string)$key === $after) {
|
||||||
|
$found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$found) {
|
||||||
|
return $this->newDialog()
|
||||||
|
->setTitle(pht('Adjacent Tab Not Found'))
|
||||||
|
->appendParagraph(
|
||||||
|
pht(
|
||||||
|
'Adjacent tab ("%s") was not found on this panel. It may have '.
|
||||||
|
'been removed.',
|
||||||
|
$after))
|
||||||
|
->addCancelButton($cancel_uri);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($target !== null) {
|
||||||
|
$found = false;
|
||||||
|
foreach ($config as $key => $spec) {
|
||||||
|
if ((string)$key === $target) {
|
||||||
|
$found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$found) {
|
||||||
|
return $this->newDialog()
|
||||||
|
->setTitle(pht('Target Tab Not Found'))
|
||||||
|
->appendParagraph(
|
||||||
|
pht(
|
||||||
|
'Target tab ("%s") was not found on this panel. It may have '.
|
||||||
|
'been removed.',
|
||||||
|
$target))
|
||||||
|
->addCancelButton($cancel_uri);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ($op) {
|
||||||
|
case 'add':
|
||||||
|
return $this->handleAddOperation($panel, $after, $cancel_uri);
|
||||||
|
case 'remove':
|
||||||
|
return $this->handleRemoveOperation($panel, $target, $cancel_uri);
|
||||||
|
case 'move':
|
||||||
|
break;
|
||||||
|
case 'rename':
|
||||||
|
return $this->handleRenameOperation($panel, $target, $cancel_uri);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function handleAddOperation(
|
||||||
|
PhabricatorDashboardPanel $panel,
|
||||||
|
$after,
|
||||||
|
$cancel_uri) {
|
||||||
|
$request = $this->getRequest();
|
||||||
|
$viewer = $this->getViewer();
|
||||||
|
|
||||||
|
$panel_phid = null;
|
||||||
|
$errors = array();
|
||||||
|
if ($request->isFormPost()) {
|
||||||
|
$panel_phid = $request->getArr('panelPHID');
|
||||||
|
$panel_phid = head($panel_phid);
|
||||||
|
|
||||||
|
$add_panel = id(new PhabricatorDashboardPanelQuery())
|
||||||
|
->setViewer($viewer)
|
||||||
|
->withPHIDs(array($panel_phid))
|
||||||
|
->executeOne();
|
||||||
|
if (!$add_panel) {
|
||||||
|
$errors[] = pht('You must select a valid panel.');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$errors) {
|
||||||
|
$add_panel_config = array(
|
||||||
|
'name' => null,
|
||||||
|
'panelID' => $add_panel->getID(),
|
||||||
|
);
|
||||||
|
$add_panel_key = Filesystem::readRandomCharacters(12);
|
||||||
|
|
||||||
|
$impl = $panel->getImplementation();
|
||||||
|
$old_config = $impl->getPanelConfiguration($panel);
|
||||||
|
$new_config = array();
|
||||||
|
if ($after === null) {
|
||||||
|
$new_config = $old_config;
|
||||||
|
$new_config[] = $add_panel_config;
|
||||||
|
} else {
|
||||||
|
foreach ($old_config as $key => $value) {
|
||||||
|
$new_config[$key] = $value;
|
||||||
|
if ((string)$key === $after) {
|
||||||
|
$new_config[$add_panel_key] = $add_panel_config;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$xactions = array();
|
||||||
|
|
||||||
|
$xactions[] = $panel->getApplicationTransactionTemplate()
|
||||||
|
->setTransactionType(
|
||||||
|
PhabricatorDashboardTabsPanelTabsTransaction::TRANSACTIONTYPE)
|
||||||
|
->setNewValue($new_config);
|
||||||
|
|
||||||
|
$editor = id(new PhabricatorDashboardPanelTransactionEditor())
|
||||||
|
->setContentSourceFromRequest($request)
|
||||||
|
->setActor($viewer)
|
||||||
|
->setContinueOnNoEffect(true)
|
||||||
|
->setContinueOnMissingFields(true);
|
||||||
|
|
||||||
|
$editor->applyTransactions($panel, $xactions);
|
||||||
|
|
||||||
|
return id(new AphrontRedirectResponse())->setURI($cancel_uri);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($panel_phid) {
|
||||||
|
$v_panel = array($panel_phid);
|
||||||
|
} else {
|
||||||
|
$v_panel = array();
|
||||||
|
}
|
||||||
|
|
||||||
|
$form = id(new AphrontFormView())
|
||||||
|
->setViewer($viewer)
|
||||||
|
->appendControl(
|
||||||
|
id(new AphrontFormTokenizerControl())
|
||||||
|
->setDatasource(new PhabricatorDashboardPanelDatasource())
|
||||||
|
->setLimit(1)
|
||||||
|
->setName('panelPHID')
|
||||||
|
->setLabel(pht('Panel'))
|
||||||
|
->setValue($v_panel));
|
||||||
|
|
||||||
|
return $this->newDialog()
|
||||||
|
->setTitle(pht('Choose Dashboard Panel'))
|
||||||
|
->setErrors($errors)
|
||||||
|
->setWidth(AphrontDialogView::WIDTH_FORM)
|
||||||
|
->addHiddenInput('after', $after)
|
||||||
|
->appendForm($form)
|
||||||
|
->addCancelButton($cancel_uri)
|
||||||
|
->addSubmitButton(pht('Add Panel'));
|
||||||
|
}
|
||||||
|
|
||||||
|
private function handleRemoveOperation(
|
||||||
|
PhabricatorDashboardPanel $panel,
|
||||||
|
$target,
|
||||||
|
$cancel_uri) {
|
||||||
|
$request = $this->getRequest();
|
||||||
|
$viewer = $this->getViewer();
|
||||||
|
|
||||||
|
$panel_phid = null;
|
||||||
|
$errors = array();
|
||||||
|
if ($request->isFormPost()) {
|
||||||
|
$impl = $panel->getImplementation();
|
||||||
|
$old_config = $impl->getPanelConfiguration($panel);
|
||||||
|
|
||||||
|
$new_config = $this->removePanel($old_config, $target);
|
||||||
|
$this->writePanelConfig($panel, $new_config);
|
||||||
|
|
||||||
|
return id(new AphrontRedirectResponse())->setURI($cancel_uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->newDialog()
|
||||||
|
->setTitle(pht('Remove tab?'))
|
||||||
|
->addHiddenInput('target', $target)
|
||||||
|
->appendParagraph(pht('Really remove this tab?'))
|
||||||
|
->addCancelButton($cancel_uri)
|
||||||
|
->addSubmitButton(pht('Remove Tab'));
|
||||||
|
}
|
||||||
|
|
||||||
|
private function handleRenameOperation(
|
||||||
|
PhabricatorDashboardPanel $panel,
|
||||||
|
$target,
|
||||||
|
$cancel_uri) {
|
||||||
|
$request = $this->getRequest();
|
||||||
|
$viewer = $this->getViewer();
|
||||||
|
|
||||||
|
$impl = $panel->getImplementation();
|
||||||
|
$old_config = $impl->getPanelConfiguration($panel);
|
||||||
|
|
||||||
|
$spec = $old_config[$target];
|
||||||
|
$name = idx($spec, 'name');
|
||||||
|
|
||||||
|
if ($request->isFormPost()) {
|
||||||
|
$name = $request->getStr('name');
|
||||||
|
|
||||||
|
$new_config = $this->renamePanel($old_config, $target, $name);
|
||||||
|
$this->writePanelConfig($panel, $new_config);
|
||||||
|
|
||||||
|
return id(new AphrontRedirectResponse())->setURI($cancel_uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
$form = id(new AphrontFormView())
|
||||||
|
->setViewer($viewer)
|
||||||
|
->appendControl(
|
||||||
|
id(new AphrontFormTextControl())
|
||||||
|
->setValue($name)
|
||||||
|
->setName('name')
|
||||||
|
->setLabel(pht('Tab Name')));
|
||||||
|
|
||||||
|
return $this->newDialog()
|
||||||
|
->setTitle(pht('Rename Panel'))
|
||||||
|
->addHiddenInput('target', $target)
|
||||||
|
->appendForm($form)
|
||||||
|
->addCancelButton($cancel_uri)
|
||||||
|
->addSubmitButton(pht('Rename Tab'));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private function writePanelConfig(
|
||||||
|
PhabricatorDashboardPanel $panel,
|
||||||
|
array $config) {
|
||||||
|
$request = $this->getRequest();
|
||||||
|
$viewer = $this->getViewer();
|
||||||
|
|
||||||
|
$xactions = array();
|
||||||
|
|
||||||
|
$xactions[] = $panel->getApplicationTransactionTemplate()
|
||||||
|
->setTransactionType(
|
||||||
|
PhabricatorDashboardTabsPanelTabsTransaction::TRANSACTIONTYPE)
|
||||||
|
->setNewValue($config);
|
||||||
|
|
||||||
|
$editor = id(new PhabricatorDashboardPanelTransactionEditor())
|
||||||
|
->setContentSourceFromRequest($request)
|
||||||
|
->setActor($viewer)
|
||||||
|
->setContinueOnNoEffect(true)
|
||||||
|
->setContinueOnMissingFields(true);
|
||||||
|
|
||||||
|
return $editor->applyTransactions($panel, $xactions);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function removePanel(array $config, $target) {
|
||||||
|
$result = array();
|
||||||
|
|
||||||
|
foreach ($config as $key => $panel_spec) {
|
||||||
|
if ((string)$key === $target) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$result[$key] = $panel_spec;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function renamePanel(array $config, $target, $name) {
|
||||||
|
$config[$target]['name'] = $name;
|
||||||
|
return $config;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -43,6 +43,10 @@ final class PhabricatorDashboardPanelRenderingEngine extends Phobject {
|
||||||
return $this->panelHandle;
|
return $this->panelHandle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function isEditMode() {
|
||||||
|
return ($this->getHeaderMode() === self::HEADER_MODE_EDIT);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Allow the engine to render the panel via Ajax.
|
* Allow the engine to render the panel via Ajax.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -20,7 +20,6 @@ final class PhabricatorDashboardTabsPanelType
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function newEditEngineFields(PhabricatorDashboardPanel $panel) {
|
protected function newEditEngineFields(PhabricatorDashboardPanel $panel) {
|
||||||
// TODO: Restore this using EditEngine instead of CustomField.
|
|
||||||
return array();
|
return array();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,37 +28,37 @@ final class PhabricatorDashboardTabsPanelType
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getPanelConfiguration(PhabricatorDashboardPanel $panel) {
|
||||||
|
$config = $panel->getProperty('config');
|
||||||
|
|
||||||
|
if (!is_array($config)) {
|
||||||
|
// NOTE: The older version of this panel stored raw JSON.
|
||||||
|
try {
|
||||||
|
$config = phutil_json_decode($config);
|
||||||
|
} catch (PhutilJSONParserException $ex) {
|
||||||
|
$config = array();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $config;
|
||||||
|
}
|
||||||
|
|
||||||
public function renderPanelContent(
|
public function renderPanelContent(
|
||||||
PhabricatorUser $viewer,
|
PhabricatorUser $viewer,
|
||||||
PhabricatorDashboardPanel $panel,
|
PhabricatorDashboardPanel $panel,
|
||||||
PhabricatorDashboardPanelRenderingEngine $engine) {
|
PhabricatorDashboardPanelRenderingEngine $engine) {
|
||||||
|
|
||||||
$config = $panel->getProperty('config');
|
$is_edit = $engine->isEditMode();
|
||||||
if (!is_array($config)) {
|
$config = $this->getPanelConfiguration($panel);
|
||||||
// NOTE: The older version of this panel stored raw JSON.
|
|
||||||
$config = phutil_json_decode($config);
|
|
||||||
}
|
|
||||||
|
|
||||||
$list = id(new PHUIListView())
|
$list = id(new PHUIListView())
|
||||||
->setType(PHUIListView::NAVBAR_LIST);
|
->setType(PHUIListView::NAVBAR_LIST);
|
||||||
|
|
||||||
$selected = 0;
|
|
||||||
|
|
||||||
$node_ids = array();
|
$node_ids = array();
|
||||||
foreach ($config as $idx => $tab_spec) {
|
foreach ($config as $idx => $tab_spec) {
|
||||||
$node_ids[$idx] = celerity_generate_unique_node_id();
|
$node_ids[$idx] = celerity_generate_unique_node_id();
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($config as $idx => $tab_spec) {
|
|
||||||
$list->addMenuItem(
|
|
||||||
id(new PHUIListItemView())
|
|
||||||
->setHref('#')
|
|
||||||
->setSelected($idx == $selected)
|
|
||||||
->addSigil('dashboard-tab-panel-tab')
|
|
||||||
->setMetadata(array('idx' => $idx))
|
|
||||||
->setName(idx($tab_spec, 'name', pht('Nameless Tab'))));
|
|
||||||
}
|
|
||||||
|
|
||||||
$ids = ipull($config, 'panelID');
|
$ids = ipull($config, 'panelID');
|
||||||
if ($ids) {
|
if ($ids) {
|
||||||
$panels = id(new PhabricatorDashboardPanelQuery())
|
$panels = id(new PhabricatorDashboardPanelQuery())
|
||||||
|
@ -70,6 +69,135 @@ final class PhabricatorDashboardTabsPanelType
|
||||||
$panels = array();
|
$panels = array();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$id = $panel->getID();
|
||||||
|
|
||||||
|
$add_uri = urisprintf('/dashboard/panel/tabs/%d/add/', $id);
|
||||||
|
$add_uri = new PhutilURI($add_uri);
|
||||||
|
|
||||||
|
$remove_uri = urisprintf('/dashboard/panel/tabs/%d/remove/', $id);
|
||||||
|
$remove_uri = new PhutilURI($remove_uri);
|
||||||
|
|
||||||
|
$rename_uri = urisprintf('/dashboard/panel/tabs/%d/rename/', $id);
|
||||||
|
$rename_uri = new PhutilURI($rename_uri);
|
||||||
|
|
||||||
|
$selected = 0;
|
||||||
|
|
||||||
|
$last_idx = null;
|
||||||
|
foreach ($config as $idx => $tab_spec) {
|
||||||
|
$panel_id = idx($tab_spec, 'panelID');
|
||||||
|
$subpanel = idx($panels, $panel_id);
|
||||||
|
|
||||||
|
$name = idx($tab_spec, 'name');
|
||||||
|
if (!strlen($name)) {
|
||||||
|
if ($subpanel) {
|
||||||
|
$name = $subpanel->getName();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!strlen($name)) {
|
||||||
|
$name = pht('Unnamed Tab');
|
||||||
|
}
|
||||||
|
|
||||||
|
$tab_view = id(new PHUIListItemView())
|
||||||
|
->setHref('#')
|
||||||
|
->setSelected($idx == $selected)
|
||||||
|
->addSigil('dashboard-tab-panel-tab')
|
||||||
|
->setMetadata(array('idx' => $idx))
|
||||||
|
->setName($name);
|
||||||
|
|
||||||
|
if ($is_edit) {
|
||||||
|
$dropdown_menu = id(new PhabricatorActionListView())
|
||||||
|
->setViewer($viewer);
|
||||||
|
|
||||||
|
$remove_tab_uri = id(clone $remove_uri)
|
||||||
|
->replaceQueryParam('target', $idx);
|
||||||
|
|
||||||
|
$rename_tab_uri = id(clone $rename_uri)
|
||||||
|
->replaceQueryParam('target', $idx);
|
||||||
|
|
||||||
|
if ($subpanel) {
|
||||||
|
$details_uri = $subpanel->getURI();
|
||||||
|
} else {
|
||||||
|
$details_uri = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$edit_uri = urisprintf(
|
||||||
|
'/dashboard/panel/edit/%d/',
|
||||||
|
$panel_id);
|
||||||
|
if ($subpanel) {
|
||||||
|
$can_edit = PhabricatorPolicyFilter::hasCapability(
|
||||||
|
$viewer,
|
||||||
|
$subpanel,
|
||||||
|
PhabricatorPolicyCapability::CAN_EDIT);
|
||||||
|
} else {
|
||||||
|
$can_edit = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$dropdown_menu->addAction(
|
||||||
|
id(new PhabricatorActionView())
|
||||||
|
->setName(pht('Rename Tab'))
|
||||||
|
->setIcon('fa-pencil')
|
||||||
|
->setHref($rename_tab_uri)
|
||||||
|
->setWorkflow(true));
|
||||||
|
|
||||||
|
$dropdown_menu->addAction(
|
||||||
|
id(new PhabricatorActionView())
|
||||||
|
->setName(pht('Remove Tab'))
|
||||||
|
->setIcon('fa-times')
|
||||||
|
->setHref($remove_tab_uri)
|
||||||
|
->setWorkflow(true));
|
||||||
|
|
||||||
|
$dropdown_menu->addAction(
|
||||||
|
id(new PhabricatorActionView())
|
||||||
|
->setType(PhabricatorActionView::TYPE_DIVIDER));
|
||||||
|
|
||||||
|
$dropdown_menu->addAction(
|
||||||
|
id(new PhabricatorActionView())
|
||||||
|
->setName(pht('Edit Panel'))
|
||||||
|
->setIcon('fa-pencil')
|
||||||
|
->setHref($edit_uri)
|
||||||
|
->setWorkflow(true)
|
||||||
|
->setDisabled(!$can_edit));
|
||||||
|
|
||||||
|
$dropdown_menu->addAction(
|
||||||
|
id(new PhabricatorActionView())
|
||||||
|
->setName(pht('View Panel Details'))
|
||||||
|
->setIcon('fa-window-maximize')
|
||||||
|
->setHref($details_uri)
|
||||||
|
->setDisabled(!$subpanel));
|
||||||
|
|
||||||
|
$tab_view->setDropdownMenu($dropdown_menu);
|
||||||
|
}
|
||||||
|
|
||||||
|
$list->addMenuItem($tab_view);
|
||||||
|
|
||||||
|
$last_idx = $idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($is_edit) {
|
||||||
|
$actions = id(new PhabricatorActionListView())
|
||||||
|
->setViewer($viewer);
|
||||||
|
|
||||||
|
$add_last_uri = clone $add_uri;
|
||||||
|
if ($last_idx) {
|
||||||
|
$add_last_uri->replaceQueryParam('after', $last_idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
$actions->addAction(
|
||||||
|
id(new PhabricatorActionView())
|
||||||
|
->setName(pht('Add Existing Panel'))
|
||||||
|
->setIcon('fa-window-maximize')
|
||||||
|
->setHref($add_last_uri)
|
||||||
|
->setWorkflow(true));
|
||||||
|
|
||||||
|
$list->addMenuItem(
|
||||||
|
id(new PHUIListItemView())
|
||||||
|
->setHref('#')
|
||||||
|
->setSelected(false)
|
||||||
|
->setName(pht('Add Tab...'))
|
||||||
|
->setDropdownMenu($actions));
|
||||||
|
}
|
||||||
|
|
||||||
$parent_phids = $engine->getParentPanelPHIDs();
|
$parent_phids = $engine->getParentPanelPHIDs();
|
||||||
$parent_phids[] = $panel->getPHID();
|
$parent_phids[] = $panel->getPHID();
|
||||||
|
|
||||||
|
@ -83,15 +211,15 @@ final class PhabricatorDashboardTabsPanelType
|
||||||
$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');
|
||||||
$panel = idx($panels, $panel_id);
|
$subpanel = idx($panels, $panel_id);
|
||||||
|
|
||||||
if ($panel) {
|
if ($subpanel) {
|
||||||
$panel_content = id(new PhabricatorDashboardPanelRenderingEngine())
|
$panel_content = id(new PhabricatorDashboardPanelRenderingEngine())
|
||||||
->setViewer($viewer)
|
->setViewer($viewer)
|
||||||
->setEnableAsyncRendering(true)
|
->setEnableAsyncRendering(true)
|
||||||
->setParentPanelPHIDs($parent_phids)
|
->setParentPanelPHIDs($parent_phids)
|
||||||
->setPanel($panel)
|
->setPanel($subpanel)
|
||||||
->setPanelPHID($panel->getPHID())
|
->setPanelPHID($subpanel->getPHID())
|
||||||
->setHeaderMode($no_headers)
|
->setHeaderMode($no_headers)
|
||||||
->setMovable(false)
|
->setMovable(false)
|
||||||
->renderPanel();
|
->renderPanel();
|
||||||
|
@ -108,6 +236,28 @@ final class PhabricatorDashboardTabsPanelType
|
||||||
$panel_content);
|
$panel_content);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!$content) {
|
||||||
|
if ($is_edit) {
|
||||||
|
$message = pht(
|
||||||
|
'This tab panel does not have any tabs yet. Use "Add Tab" to '.
|
||||||
|
'create or place a tab.');
|
||||||
|
} else {
|
||||||
|
$message = pht(
|
||||||
|
'This tab panel does not have any tabs yet.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$content = id(new PHUIInfoView())
|
||||||
|
->setSeverity(PHUIInfoView::SEVERITY_NODATA)
|
||||||
|
->setErrors(
|
||||||
|
array(
|
||||||
|
$message,
|
||||||
|
));
|
||||||
|
|
||||||
|
$content = id(new PHUIBoxView())
|
||||||
|
->addClass('mlt mlb')
|
||||||
|
->appendChild($content);
|
||||||
|
}
|
||||||
|
|
||||||
Javelin::initBehavior('dashboard-tab-panel');
|
Javelin::initBehavior('dashboard-tab-panel');
|
||||||
|
|
||||||
return javelin_tag(
|
return javelin_tag(
|
||||||
|
|
|
@ -48,13 +48,13 @@ final class PhabricatorDashboardPanelDatasource
|
||||||
$type_text = nonempty($panel->getPanelType(), pht('Unknown Type'));
|
$type_text = nonempty($panel->getPanelType(), pht('Unknown Type'));
|
||||||
$icon = 'fa-question';
|
$icon = 'fa-question';
|
||||||
}
|
}
|
||||||
$id = $panel->getID();
|
$phid = $panel->getPHID();
|
||||||
$monogram = $panel->getMonogram();
|
$monogram = $panel->getMonogram();
|
||||||
$properties = $panel->getProperties();
|
$properties = $panel->getProperties();
|
||||||
|
|
||||||
$result = id(new PhabricatorTypeaheadResult())
|
$result = id(new PhabricatorTypeaheadResult())
|
||||||
->setName($monogram.' '.$panel->getName())
|
->setName($monogram.' '.$panel->getName())
|
||||||
->setPHID($id)
|
->setPHID($phid)
|
||||||
->setIcon($icon)
|
->setIcon($icon)
|
||||||
->addAttribute($type_text);
|
->addAttribute($type_text);
|
||||||
|
|
||||||
|
@ -66,7 +66,7 @@ final class PhabricatorDashboardPanelDatasource
|
||||||
$result->setClosed(pht('Archived'));
|
$result->setClosed(pht('Archived'));
|
||||||
}
|
}
|
||||||
|
|
||||||
$results[$id] = $result;
|
$results[$phid] = $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $results;
|
return $results;
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorDashboardTabsPanelTabsTransaction
|
||||||
|
extends PhabricatorDashboardPanelPropertyTransaction {
|
||||||
|
|
||||||
|
const TRANSACTIONTYPE = 'tabs.tabs';
|
||||||
|
|
||||||
|
protected function getPropertyKey() {
|
||||||
|
return 'config';
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -35,6 +35,7 @@ final class PHUIListItemView extends AphrontTagView {
|
||||||
private $actionIconHref;
|
private $actionIconHref;
|
||||||
private $count;
|
private $count;
|
||||||
private $rel;
|
private $rel;
|
||||||
|
private $hasDropdown;
|
||||||
|
|
||||||
public function setOpenInNewWindow($open_in_new_window) {
|
public function setOpenInNewWindow($open_in_new_window) {
|
||||||
$this->openInNewWindow = $open_in_new_window;
|
$this->openInNewWindow = $open_in_new_window;
|
||||||
|
@ -68,6 +69,7 @@ final class PHUIListItemView extends AphrontTagView {
|
||||||
|
|
||||||
$this->addSigil('phui-dropdown-menu');
|
$this->addSigil('phui-dropdown-menu');
|
||||||
$this->setMetadata($actions->getDropdownMenuMetadata());
|
$this->setMetadata($actions->getDropdownMenuMetadata());
|
||||||
|
$this->hasDropdown = true;
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
@ -235,6 +237,10 @@ final class PHUIListItemView extends AphrontTagView {
|
||||||
$classes[] = 'phui-list-item-has-action-icon';
|
$classes[] = 'phui-list-item-has-action-icon';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($this->hasDropdown) {
|
||||||
|
$classes[] = 'dropdown';
|
||||||
|
}
|
||||||
|
|
||||||
return array(
|
return array(
|
||||||
'class' => implode(' ', $classes),
|
'class' => implode(' ', $classes),
|
||||||
);
|
);
|
||||||
|
@ -363,6 +369,12 @@ final class PHUIListItemView extends AphrontTagView {
|
||||||
$this->count);
|
$this->count);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($this->hasDropdown) {
|
||||||
|
$caret = phutil_tag('span', array('class' => 'caret'), '');
|
||||||
|
} else {
|
||||||
|
$caret = null;
|
||||||
|
}
|
||||||
|
|
||||||
$icons = $this->getIcons();
|
$icons = $this->getIcons();
|
||||||
|
|
||||||
$list_item = javelin_tag(
|
$list_item = javelin_tag(
|
||||||
|
@ -381,6 +393,7 @@ final class PHUIListItemView extends AphrontTagView {
|
||||||
$icons,
|
$icons,
|
||||||
$this->renderChildren(),
|
$this->renderChildren(),
|
||||||
$name,
|
$name,
|
||||||
|
$caret,
|
||||||
$count,
|
$count,
|
||||||
));
|
));
|
||||||
|
|
||||||
|
|
|
@ -213,3 +213,14 @@
|
||||||
.phabricator-action-view-item .phui-icon-view {
|
.phabricator-action-view-item .phui-icon-view {
|
||||||
color: {$sky};
|
color: {$sky};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.phui-list-item-view.dropdown .phui-list-item-href {
|
||||||
|
padding-right: 28px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.phui-list-item-view .caret {
|
||||||
|
position: absolute;
|
||||||
|
top: 6px;
|
||||||
|
right: 12px;
|
||||||
|
border-top: 7px solid {$greytext};
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue