mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-26 00:32:42 +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(
|
||||
'conpherence.pkg.css' => '3c8a0668',
|
||||
'conpherence.pkg.js' => '020aebcf',
|
||||
'core.pkg.css' => '2d4810eb',
|
||||
'core.pkg.css' => '671b9fae',
|
||||
'core.pkg.js' => 'c783d8f6',
|
||||
'differential.pkg.css' => '8d8360fb',
|
||||
'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-list-view.css' => 'f14f2422',
|
||||
'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-badge.css' => '666e25ad',
|
||||
'rsrc/css/phui/phui-basic-nav-view.css' => '56ebd66d',
|
||||
|
@ -757,7 +757,7 @@ return array(
|
|||
'path-typeahead' => 'ad486db3',
|
||||
'people-picture-menu-item-css' => 'fe8e07cf',
|
||||
'people-profile-css' => '2ea2daa1',
|
||||
'phabricator-action-list-view-css' => 'c4972757',
|
||||
'phabricator-action-list-view-css' => 'c34af376',
|
||||
'phabricator-busy' => '5202e831',
|
||||
'phabricator-chatlog-css' => 'abdc76ee',
|
||||
'phabricator-content-source-view-css' => 'cdf0d579',
|
||||
|
|
|
@ -2942,6 +2942,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorDashboardPanelRenderingEngine' => 'applications/dashboard/engine/PhabricatorDashboardPanelRenderingEngine.php',
|
||||
'PhabricatorDashboardPanelSearchEngine' => 'applications/dashboard/query/PhabricatorDashboardPanelSearchEngine.php',
|
||||
'PhabricatorDashboardPanelStatusTransaction' => 'applications/dashboard/xaction/panel/PhabricatorDashboardPanelStatusTransaction.php',
|
||||
'PhabricatorDashboardPanelTabsController' => 'applications/dashboard/controller/panel/PhabricatorDashboardPanelTabsController.php',
|
||||
'PhabricatorDashboardPanelTransaction' => 'applications/dashboard/storage/PhabricatorDashboardPanelTransaction.php',
|
||||
'PhabricatorDashboardPanelTransactionEditor' => 'applications/dashboard/editor/PhabricatorDashboardPanelTransactionEditor.php',
|
||||
'PhabricatorDashboardPanelTransactionQuery' => 'applications/dashboard/query/PhabricatorDashboardPanelTransactionQuery.php',
|
||||
|
@ -2984,6 +2985,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorDashboardRenderingEngine' => 'applications/dashboard/engine/PhabricatorDashboardRenderingEngine.php',
|
||||
'PhabricatorDashboardSchemaSpec' => 'applications/dashboard/storage/PhabricatorDashboardSchemaSpec.php',
|
||||
'PhabricatorDashboardSearchEngine' => 'applications/dashboard/query/PhabricatorDashboardSearchEngine.php',
|
||||
'PhabricatorDashboardTabsPanelTabsTransaction' => 'applications/dashboard/xaction/panel/PhabricatorDashboardTabsPanelTabsTransaction.php',
|
||||
'PhabricatorDashboardTabsPanelType' => 'applications/dashboard/paneltype/PhabricatorDashboardTabsPanelType.php',
|
||||
'PhabricatorDashboardTextPanelTextTransaction' => 'applications/dashboard/xaction/panel/PhabricatorDashboardTextPanelTextTransaction.php',
|
||||
'PhabricatorDashboardTextPanelType' => 'applications/dashboard/paneltype/PhabricatorDashboardTextPanelType.php',
|
||||
|
@ -8920,6 +8922,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorDashboardPanelRenderingEngine' => 'Phobject',
|
||||
'PhabricatorDashboardPanelSearchEngine' => 'PhabricatorApplicationSearchEngine',
|
||||
'PhabricatorDashboardPanelStatusTransaction' => 'PhabricatorDashboardPanelTransactionType',
|
||||
'PhabricatorDashboardPanelTabsController' => 'PhabricatorDashboardController',
|
||||
'PhabricatorDashboardPanelTransaction' => 'PhabricatorModularTransaction',
|
||||
'PhabricatorDashboardPanelTransactionEditor' => 'PhabricatorApplicationTransactionEditor',
|
||||
'PhabricatorDashboardPanelTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
|
||||
|
@ -8967,6 +8970,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorDashboardRenderingEngine' => 'Phobject',
|
||||
'PhabricatorDashboardSchemaSpec' => 'PhabricatorConfigSchemaSpec',
|
||||
'PhabricatorDashboardSearchEngine' => 'PhabricatorApplicationSearchEngine',
|
||||
'PhabricatorDashboardTabsPanelTabsTransaction' => 'PhabricatorDashboardPanelPropertyTransaction',
|
||||
'PhabricatorDashboardTabsPanelType' => 'PhabricatorDashboardPanelType',
|
||||
'PhabricatorDashboardTextPanelTextTransaction' => 'PhabricatorDashboardPanelPropertyTransaction',
|
||||
'PhabricatorDashboardTextPanelType' => 'PhabricatorDashboardPanelType',
|
||||
|
|
|
@ -62,6 +62,8 @@ final class PhabricatorDashboardApplication extends PhabricatorApplication {
|
|||
'render/(?P<id>\d+)/' => 'PhabricatorDashboardPanelRenderController',
|
||||
'archive/(?P<id>\d+)/'
|
||||
=> 'PhabricatorDashboardPanelArchiveController',
|
||||
'tabs/(?P<id>\d+)/(?P<op>add|move|remove|rename)/'
|
||||
=> 'PhabricatorDashboardPanelTabsController',
|
||||
),
|
||||
),
|
||||
'/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;
|
||||
}
|
||||
|
||||
public function isEditMode() {
|
||||
return ($this->getHeaderMode() === self::HEADER_MODE_EDIT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow the engine to render the panel via Ajax.
|
||||
*/
|
||||
|
|
|
@ -20,7 +20,6 @@ final class PhabricatorDashboardTabsPanelType
|
|||
}
|
||||
|
||||
protected function newEditEngineFields(PhabricatorDashboardPanel $panel) {
|
||||
// TODO: Restore this using EditEngine instead of CustomField.
|
||||
return array();
|
||||
}
|
||||
|
||||
|
@ -29,37 +28,37 @@ final class PhabricatorDashboardTabsPanelType
|
|||
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(
|
||||
PhabricatorUser $viewer,
|
||||
PhabricatorDashboardPanel $panel,
|
||||
PhabricatorDashboardPanelRenderingEngine $engine) {
|
||||
|
||||
$config = $panel->getProperty('config');
|
||||
if (!is_array($config)) {
|
||||
// NOTE: The older version of this panel stored raw JSON.
|
||||
$config = phutil_json_decode($config);
|
||||
}
|
||||
$is_edit = $engine->isEditMode();
|
||||
$config = $this->getPanelConfiguration($panel);
|
||||
|
||||
$list = id(new PHUIListView())
|
||||
->setType(PHUIListView::NAVBAR_LIST);
|
||||
|
||||
$selected = 0;
|
||||
|
||||
$node_ids = array();
|
||||
foreach ($config as $idx => $tab_spec) {
|
||||
$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');
|
||||
if ($ids) {
|
||||
$panels = id(new PhabricatorDashboardPanelQuery())
|
||||
|
@ -70,6 +69,135 @@ final class PhabricatorDashboardTabsPanelType
|
|||
$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[] = $panel->getPHID();
|
||||
|
||||
|
@ -83,15 +211,15 @@ final class PhabricatorDashboardTabsPanelType
|
|||
$no_headers = PhabricatorDashboardPanelRenderingEngine::HEADER_MODE_NONE;
|
||||
foreach ($config as $idx => $tab_spec) {
|
||||
$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())
|
||||
->setViewer($viewer)
|
||||
->setEnableAsyncRendering(true)
|
||||
->setParentPanelPHIDs($parent_phids)
|
||||
->setPanel($panel)
|
||||
->setPanelPHID($panel->getPHID())
|
||||
->setPanel($subpanel)
|
||||
->setPanelPHID($subpanel->getPHID())
|
||||
->setHeaderMode($no_headers)
|
||||
->setMovable(false)
|
||||
->renderPanel();
|
||||
|
@ -108,6 +236,28 @@ final class PhabricatorDashboardTabsPanelType
|
|||
$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');
|
||||
|
||||
return javelin_tag(
|
||||
|
|
|
@ -48,13 +48,13 @@ final class PhabricatorDashboardPanelDatasource
|
|||
$type_text = nonempty($panel->getPanelType(), pht('Unknown Type'));
|
||||
$icon = 'fa-question';
|
||||
}
|
||||
$id = $panel->getID();
|
||||
$phid = $panel->getPHID();
|
||||
$monogram = $panel->getMonogram();
|
||||
$properties = $panel->getProperties();
|
||||
|
||||
$result = id(new PhabricatorTypeaheadResult())
|
||||
->setName($monogram.' '.$panel->getName())
|
||||
->setPHID($id)
|
||||
->setPHID($phid)
|
||||
->setIcon($icon)
|
||||
->addAttribute($type_text);
|
||||
|
||||
|
@ -66,7 +66,7 @@ final class PhabricatorDashboardPanelDatasource
|
|||
$result->setClosed(pht('Archived'));
|
||||
}
|
||||
|
||||
$results[$id] = $result;
|
||||
$results[$phid] = $result;
|
||||
}
|
||||
|
||||
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 $count;
|
||||
private $rel;
|
||||
private $hasDropdown;
|
||||
|
||||
public function setOpenInNewWindow($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->setMetadata($actions->getDropdownMenuMetadata());
|
||||
$this->hasDropdown = true;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
@ -235,6 +237,10 @@ final class PHUIListItemView extends AphrontTagView {
|
|||
$classes[] = 'phui-list-item-has-action-icon';
|
||||
}
|
||||
|
||||
if ($this->hasDropdown) {
|
||||
$classes[] = 'dropdown';
|
||||
}
|
||||
|
||||
return array(
|
||||
'class' => implode(' ', $classes),
|
||||
);
|
||||
|
@ -363,6 +369,12 @@ final class PHUIListItemView extends AphrontTagView {
|
|||
$this->count);
|
||||
}
|
||||
|
||||
if ($this->hasDropdown) {
|
||||
$caret = phutil_tag('span', array('class' => 'caret'), '');
|
||||
} else {
|
||||
$caret = null;
|
||||
}
|
||||
|
||||
$icons = $this->getIcons();
|
||||
|
||||
$list_item = javelin_tag(
|
||||
|
@ -381,6 +393,7 @@ final class PHUIListItemView extends AphrontTagView {
|
|||
$icons,
|
||||
$this->renderChildren(),
|
||||
$name,
|
||||
$caret,
|
||||
$count,
|
||||
));
|
||||
|
||||
|
|
|
@ -213,3 +213,14 @@
|
|||
.phabricator-action-view-item .phui-icon-view {
|
||||
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