From 2921bad1ff082066416890e00edd6a0a8f4c834c Mon Sep 17 00:00:00 2001 From: Chad Little Date: Mon, 20 Mar 2017 14:15:16 -0700 Subject: [PATCH] Add an action to adding Panels from ApplicationSearch Summary: Ref T5307. This adds an additional action to Use Results for creating a panel from the query. Test Plan: Navigate to Maniphest, select dropdown for Use Results. Try any of the following: - Try to set a panel without a name (fail) - Muck up query or engine (fail) - Set a fake Dashboard ID (fail) Give panel a name and select a dashboard I have edit permissions to, get taken to dashboard. Reviewers: epriestley Subscribers: Korvin Maniphest Tasks: T5307 Differential Revision: https://secure.phabricator.com/D17516 --- src/__phutil_library_map__.php | 2 + .../PhabricatorDashboardApplication.php | 2 + ...orDashboardQueryPanelInstallController.php | 159 ++++++++++++++++++ ...PhabricatorApplicationSearchController.php | 36 +++- 4 files changed, 193 insertions(+), 6 deletions(-) create mode 100644 src/applications/dashboard/controller/PhabricatorDashboardQueryPanelInstallController.php diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 29bf2e418f..645a9ee6b2 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -2530,6 +2530,7 @@ phutil_register_library_map(array( 'PhabricatorDashboardProfileController' => 'applications/dashboard/controller/PhabricatorDashboardProfileController.php', 'PhabricatorDashboardProfileMenuItem' => 'applications/search/menuitem/PhabricatorDashboardProfileMenuItem.php', 'PhabricatorDashboardQuery' => 'applications/dashboard/query/PhabricatorDashboardQuery.php', + 'PhabricatorDashboardQueryPanelInstallController' => 'applications/dashboard/controller/PhabricatorDashboardQueryPanelInstallController.php', 'PhabricatorDashboardQueryPanelType' => 'applications/dashboard/paneltype/PhabricatorDashboardQueryPanelType.php', 'PhabricatorDashboardRemarkupRule' => 'applications/dashboard/remarkup/PhabricatorDashboardRemarkupRule.php', 'PhabricatorDashboardRemovePanelController' => 'applications/dashboard/controller/PhabricatorDashboardRemovePanelController.php', @@ -7610,6 +7611,7 @@ phutil_register_library_map(array( 'PhabricatorDashboardProfileController' => 'PhabricatorController', 'PhabricatorDashboardProfileMenuItem' => 'PhabricatorProfileMenuItem', 'PhabricatorDashboardQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', + 'PhabricatorDashboardQueryPanelInstallController' => 'PhabricatorDashboardController', 'PhabricatorDashboardQueryPanelType' => 'PhabricatorDashboardPanelType', 'PhabricatorDashboardRemarkupRule' => 'PhabricatorObjectRemarkupRule', 'PhabricatorDashboardRemovePanelController' => 'PhabricatorDashboardController', diff --git a/src/applications/dashboard/application/PhabricatorDashboardApplication.php b/src/applications/dashboard/application/PhabricatorDashboardApplication.php index c0ce2ff09e..29024cbcb8 100644 --- a/src/applications/dashboard/application/PhabricatorDashboardApplication.php +++ b/src/applications/dashboard/application/PhabricatorDashboardApplication.php @@ -36,6 +36,8 @@ final class PhabricatorDashboardApplication extends PhabricatorApplication { 'removepanel/(?P\d+)/' => 'PhabricatorDashboardRemovePanelController', 'panel/' => array( + 'install/(?P[^/]+)/(?:(?P[^/]+)/)?' => + 'PhabricatorDashboardQueryPanelInstallController', '(?:query/(?P[^/]+)/)?' => 'PhabricatorDashboardPanelListController', 'create/' => 'PhabricatorDashboardPanelEditController', diff --git a/src/applications/dashboard/controller/PhabricatorDashboardQueryPanelInstallController.php b/src/applications/dashboard/controller/PhabricatorDashboardQueryPanelInstallController.php new file mode 100644 index 0000000000..6d0d8c2e74 --- /dev/null +++ b/src/applications/dashboard/controller/PhabricatorDashboardQueryPanelInstallController.php @@ -0,0 +1,159 @@ +getViewer(); + + $v_dashboard = null; + $v_name = null; + $v_column = 0; + $v_engine = $request->getURIData('engineKey'); + $v_query = $request->getURIData('queryKey'); + + // Validate Engines + $engines = PhabricatorApplicationSearchEngine::getAllEngines(); + foreach ($engines as $name => $engine) { + if (!$engine->canUseInPanelContext()) { + unset($engines[$name]); + } + } + if (!in_array($v_engine, array_keys($engines))) { + return new Aphront404Response(); + } + + // Validate Queries + $engine = $engines[$v_engine]; + $engine->setViewer($viewer); + $queries = array_keys($engine->loadEnabledNamedQueries()); + if (!in_array($v_query, $queries)) { + return new Aphront404Response(); + } + + $errors = array(); + + if ($request->isFormPost()) { + $v_dashboard = $request->getInt('dashboardID'); + $v_name = $request->getStr('name'); + if (!$v_name) { + $errors[] = pht('You must provide a name for this panel.'); + } + + $dashboard = id(new PhabricatorDashboardQuery()) + ->setViewer($viewer) + ->withIDs(array($v_dashboard)) + ->requireCapabilities( + array( + PhabricatorPolicyCapability::CAN_VIEW, + PhabricatorPolicyCapability::CAN_EDIT, + )) + ->executeOne(); + + if (!$dashboard) { + $errors[] = pht('Please select a valid dashboard.'); + } + + if (!$errors) { + $redirect_uri = "/dashboard/arrange/{$v_dashboard}/"; + + $panel_type = id(new PhabricatorDashboardQueryPanelType()) + ->getPanelTypeKey(); + $panel = PhabricatorDashboardPanel::initializeNewPanel($viewer); + $panel->setPanelType($panel_type); + + $field_list = PhabricatorCustomField::getObjectFields( + $panel, + PhabricatorCustomField::ROLE_EDIT); + + $field_list + ->setViewer($viewer) + ->readFieldsFromStorage($panel); + + $panel->requireImplementation()->initializeFieldsFromRequest( + $panel, + $field_list, + $request); + + $xactions = array(); + + $xactions[] = id(new PhabricatorDashboardPanelTransaction()) + ->setTransactionType(PhabricatorDashboardPanelTransaction::TYPE_NAME) + ->setNewValue($v_name); + + $xactions[] = id(new PhabricatorDashboardPanelTransaction()) + ->setTransactionType(PhabricatorTransactions::TYPE_CUSTOMFIELD) + ->setMetadataValue('customfield:key', 'std:dashboard:core:class') + ->setOldValue(null) + ->setNewValue($v_engine); + + $xactions[] = id(new PhabricatorDashboardPanelTransaction()) + ->setTransactionType(PhabricatorTransactions::TYPE_CUSTOMFIELD) + ->setMetadataValue('customfield:key', 'std:dashboard:core:key') + ->setOldValue(null) + ->setNewValue($v_query); + + $editor = id(new PhabricatorDashboardPanelTransactionEditor()) + ->setActor($viewer) + ->setContinueOnNoEffect(true) + ->setContentSourceFromRequest($request) + ->applyTransactions($panel, $xactions); + + PhabricatorDashboardTransactionEditor::addPanelToDashboard( + $viewer, + PhabricatorContentSource::newFromRequest($request), + $panel, + $dashboard, + $request->getInt('column', 0)); + + return id(new AphrontRedirectResponse())->setURI($redirect_uri); + } + } + + // Make this a select for now, as we don't expect someone to have + // edit access to a vast number of dashboards. + // Can add optiongroup if needed down the road. + $dashboards = id(new PhabricatorDashboardQuery()) + ->setViewer($viewer) + ->withStatuses(array( + PhabricatorDashboard::STATUS_ACTIVE, + )) + ->requireCapabilities( + array( + PhabricatorPolicyCapability::CAN_VIEW, + PhabricatorPolicyCapability::CAN_EDIT, + )) + ->execute(); + $options = mpull($dashboards, 'getName', 'getID'); + asort($options); + + $redirect_uri = '#'; // ?? + + $form = id(new AphrontFormView()) + ->setUser($viewer) + ->addHiddenInput('engine', $v_engine) + ->addHiddenInput('query', $v_query) + ->addHiddenInput('column', $v_column) + ->appendChild( + id(new AphrontFormTextControl()) + ->setLabel(pht('Name')) + ->setName('name') + ->setValue($v_name)) + ->appendChild( + id(new AphrontFormSelectControl()) + ->setUser($this->getViewer()) + ->setValue($v_dashboard) + ->setName('dashboardID') + ->setOptions($options) + ->setLabel(pht('Dashboard'))); + + return $this->newDialog() + ->setTitle(pht('Add Panel to Dashboard')) + ->setErrors($errors) + ->setWidth(AphrontDialogView::WIDTH_FORM) + ->appendChild($form->buildLayoutView()) + ->addCancelButton($redirect_uri) + ->addSubmitButton(pht('Add Panel')); + } + +} diff --git a/src/applications/search/controller/PhabricatorApplicationSearchController.php b/src/applications/search/controller/PhabricatorApplicationSearchController.php index faca9991ea..dd3508e6bb 100644 --- a/src/applications/search/controller/PhabricatorApplicationSearchController.php +++ b/src/applications/search/controller/PhabricatorApplicationSearchController.php @@ -555,8 +555,9 @@ final class PhabricatorApplicationSearchController ->setTag('a') ->setHref('#') ->setText(pht('Use Results...')) - ->setIcon('fa-road') - ->setDropdownMenu($action_list); + ->setIcon('fa-bars') + ->setDropdownMenu($action_list) + ->addClass('dropdown'); } private function newOverflowingView() { @@ -600,9 +601,32 @@ final class PhabricatorApplicationSearchController private function newBuiltinUseActions() { $actions = array(); + $request = $this->getRequest(); + $viewer = $request->getUser(); $is_dev = PhabricatorEnv::getEnvConfig('phabricator.developer-mode'); + $engine = $this->getSearchEngine(); + $engine_class = get_class($engine); + $query_key = $this->getQueryKey(); + if (!$query_key) { + $query_key = head_key($engine->loadEnabledNamedQueries()); + } + + $can_use = $engine->canUseInPanelContext(); + $is_installed = PhabricatorApplication::isClassInstalledForViewer( + 'PhabricatorDashboardApplication', + $viewer); + + if ($can_use && $is_installed) { + $dashboard_uri = '/dashboard/install/'; + $actions[] = id(new PhabricatorActionView()) + ->setIcon('fa-dashboard') + ->setName(pht('Add to Dasbhoard')) + ->setWorkflow(true) + ->setHref("/dashboard/panel/install/{$engine_class}/{$query_key}/"); + } + if ($is_dev) { $engine = $this->getSearchEngine(); $nux_uri = $engine->getQueryBaseURI(); @@ -610,8 +634,8 @@ final class PhabricatorApplicationSearchController ->setQueryParam('nux', true); $actions[] = id(new PhabricatorActionView()) - ->setIcon('fa-bug') - ->setName(pht('Developer: Show New User State')) + ->setIcon('fa-user-plus') + ->setName(pht('DEV: New User State')) ->setHref($nux_uri); } @@ -620,8 +644,8 @@ final class PhabricatorApplicationSearchController ->setQueryParam('overheated', true); $actions[] = id(new PhabricatorActionView()) - ->setIcon('fa-bug') - ->setName(pht('Developer: Show Overheated State')) + ->setIcon('fa-fire') + ->setName(pht('DEV: Overheated State')) ->setHref($overheated_uri); }