@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Fix the "Add Query to Dashboard..." flow from "Use Results" on search result pages

Summary:
Depends on D20413. Ref T13272. When you search for stuff, you can "Use Results > Add to Dashboard" to generate a query panel.

This needs some updating after the recent refactoring. All the changes are pretty straightforward. Swaps a giant `<select />` for a tokenizer with a datasource.

Test Plan: Used the "Use Results > Add to Dashboard" flow to create a panel on a dashboard using a query.

Reviewers: amckinley

Reviewed By: amckinley

Maniphest Tasks: T13272

Differential Revision: https://secure.phabricator.com/D20414

+135 -128
+98 -124
src/applications/dashboard/controller/PhabricatorDashboardQueryPanelInstallController.php
··· 7 7 $viewer = $request->getViewer(); 8 8 9 9 $v_dashboard = null; 10 + $e_dashboard = null; 11 + 10 12 $v_name = null; 11 - $v_column = 0; 12 - $v_engine = $request->getURIData('engineKey'); 13 - $v_query = $request->getURIData('queryKey'); 14 - 15 13 $e_name = true; 16 14 17 - // Validate Engines 18 - $engines = PhabricatorApplicationSearchEngine::getAllEngines(); 19 - foreach ($engines as $name => $engine) { 20 - if (!$engine->canUseInPanelContext()) { 21 - unset($engines[$name]); 22 - } 15 + $v_engine = $request->getStr('engine'); 16 + if (!strlen($v_engine)) { 17 + $v_engine = $request->getURIData('engineKey'); 23 18 } 24 - if (!in_array($v_engine, array_keys($engines))) { 25 - return new Aphront404Response(); 19 + 20 + $v_query = $request->getStr('query'); 21 + if (!strlen($v_query)) { 22 + $v_query = $request->getURIData('queryKey'); 26 23 } 27 24 28 - // Validate Queries 29 - $engine = $engines[$v_engine]; 30 - $engine->setViewer($viewer); 31 - $good_query = false; 32 - if ($engine->isBuiltinQuery($v_query)) { 33 - $good_query = true; 34 - } else { 35 - $saved_query = id(new PhabricatorSavedQueryQuery()) 36 - ->setViewer($viewer) 37 - ->withEngineClassNames(array($v_engine)) 38 - ->withQueryKeys(array($v_query)) 39 - ->executeOne(); 40 - if ($saved_query) { 41 - $good_query = true; 25 + $engines = PhabricatorApplicationSearchEngine::getAllEngines(); 26 + $engine = idx($engines, $v_engine); 27 + if ($engine) { 28 + $engine = id(clone $engine) 29 + ->setViewer($viewer); 30 + 31 + $redirect_uri = $engine->getQueryResultsPageURI($v_query); 32 + 33 + $named_query = idx($engine->loadEnabledNamedQueries(), $v_query); 34 + if ($named_query) { 35 + $v_name = $named_query->getQueryName(); 42 36 } 43 - } 44 - if (!$good_query) { 45 - return new Aphront404Response(); 37 + } else { 38 + $redirect_uri = '/'; 46 39 } 47 40 48 - $named_query = idx($engine->loadEnabledNamedQueries(), $v_query); 49 - if ($named_query) { 50 - $v_name = $named_query->getQueryName(); 51 - } 41 + $errors = array(); 52 42 53 - $errors = array(); 43 + $xaction_name = PhabricatorDashboardPanelNameTransaction::TRANSACTIONTYPE; 44 + $xaction_engine = 45 + PhabricatorDashboardQueryPanelApplicationTransaction::TRANSACTIONTYPE; 46 + $xaction_query = 47 + PhabricatorDashboardQueryPanelQueryTransaction::TRANSACTIONTYPE; 54 48 55 49 if ($request->isFormPost()) { 56 - $v_dashboard = $request->getInt('dashboardID'); 57 50 $v_name = $request->getStr('name'); 58 51 if (!$v_name) { 59 52 $errors[] = pht('You must provide a name for this panel.'); 60 53 $e_name = pht('Required'); 61 54 } 62 55 63 - $dashboard = id(new PhabricatorDashboardQuery()) 64 - ->setViewer($viewer) 65 - ->withIDs(array($v_dashboard)) 66 - ->requireCapabilities( 67 - array( 68 - PhabricatorPolicyCapability::CAN_VIEW, 69 - PhabricatorPolicyCapability::CAN_EDIT, 70 - )) 71 - ->executeOne(); 56 + $v_dashboard = head($request->getArr('dashboardPHIDs')); 57 + if (!$v_dashboard) { 58 + $errors[] = pht('You must select a dashboard.'); 59 + $e_dashboard = pht('Required'); 60 + } else { 61 + $dashboard = id(new PhabricatorDashboardQuery()) 62 + ->setViewer($viewer) 63 + ->withPHIDs(array($v_dashboard)) 64 + ->executeOne(); 65 + if (!$dashboard) { 66 + $errors[] = pht('You must select a valid dashboard.'); 67 + $e_dashboard = pht('Invalid'); 68 + } 72 69 73 - if (!$dashboard) { 74 - $errors[] = pht('Please select a valid dashboard.'); 70 + $can_edit = PhabricatorPolicyFilter::hasCapability( 71 + $viewer, 72 + $dashboard, 73 + PhabricatorPolicyCapability::CAN_EDIT); 74 + if (!$can_edit) { 75 + $errors[] = pht( 76 + 'You must select a dashboard you have permission to edit.'); 77 + } 75 78 } 76 79 77 80 if (!$errors) { 78 - $redirect_uri = "/dashboard/view/{$v_dashboard}/"; 81 + $done_uri = $dashboard->getURI(); 82 + 83 + // First, create a new panel. 79 84 80 85 $panel_type = id(new PhabricatorDashboardQueryPanelType()) 81 86 ->getPanelTypeKey(); 82 - $panel = PhabricatorDashboardPanel::initializeNewPanel($viewer); 83 - $panel->setPanelType($panel_type); 84 - 85 - $field_list = PhabricatorCustomField::getObjectFields( 86 - $panel, 87 - PhabricatorCustomField::ROLE_EDIT); 88 87 89 - $field_list 90 - ->setViewer($viewer) 91 - ->readFieldsFromStorage($panel); 92 - 93 - $panel->requireImplementation()->initializeFieldsFromRequest( 94 - $panel, 95 - $field_list, 96 - $request); 88 + $panel = PhabricatorDashboardPanel::initializeNewPanel($viewer) 89 + ->setPanelType($panel_type); 97 90 98 91 $xactions = array(); 99 92 100 - $xactions[] = id(new PhabricatorDashboardPanelTransaction()) 101 - ->setTransactionType( 102 - PhabricatorDashboardPanelNameTransaction::TRANSACTIONTYPE) 103 - ->setNewValue($v_name); 104 - 105 - $xactions[] = id(new PhabricatorDashboardPanelTransaction()) 106 - ->setTransactionType(PhabricatorTransactions::TYPE_CUSTOMFIELD) 107 - ->setMetadataValue('customfield:key', 'std:dashboard:core:class') 108 - ->setOldValue(null) 93 + $xactions[] = $panel->getApplicationTransactionTemplate() 94 + ->setTransactionType($xaction_engine) 109 95 ->setNewValue($v_engine); 110 96 111 - $xactions[] = id(new PhabricatorDashboardPanelTransaction()) 112 - ->setTransactionType(PhabricatorTransactions::TYPE_CUSTOMFIELD) 113 - ->setMetadataValue('customfield:key', 'std:dashboard:core:key') 114 - ->setOldValue(null) 97 + $xactions[] = $panel->getApplicationTransactionTemplate() 98 + ->setTransactionType($xaction_query) 115 99 ->setNewValue($v_query); 116 100 117 - $editor = id(new PhabricatorDashboardPanelTransactionEditor()) 101 + $xactions[] = $panel->getApplicationTransactionTemplate() 102 + ->setTransactionType($xaction_name) 103 + ->setNewValue($v_name); 104 + 105 + $editor = $panel->getApplicationTransactionEditor() 118 106 ->setActor($viewer) 119 - ->setContinueOnNoEffect(true) 120 107 ->setContentSourceFromRequest($request) 121 108 ->applyTransactions($panel, $xactions); 122 109 123 - PhabricatorDashboardTransactionEditor::addPanelToDashboard( 124 - $viewer, 125 - PhabricatorContentSource::newFromRequest($request), 126 - $panel, 127 - $dashboard, 128 - $request->getInt('column', 0)); 110 + // Now that we've created a panel, add it to the dashboard. 129 111 130 - return id(new AphrontRedirectResponse())->setURI($redirect_uri); 131 - } 132 - } 112 + $xactions = array(); 133 113 134 - // Make this a select for now, as we don't expect someone to have 135 - // edit access to a vast number of dashboards. 136 - // Can add optiongroup if needed down the road. 137 - $dashboards = id(new PhabricatorDashboardQuery()) 138 - ->setViewer($viewer) 139 - ->withStatuses(array( 140 - PhabricatorDashboard::STATUS_ACTIVE, 141 - )) 142 - ->requireCapabilities( 143 - array( 144 - PhabricatorPolicyCapability::CAN_VIEW, 145 - PhabricatorPolicyCapability::CAN_EDIT, 146 - )) 147 - ->execute(); 148 - $options = mpull($dashboards, 'getName', 'getID'); 149 - asort($options); 114 + $ref_list = clone $dashboard->getPanelRefList(); 115 + $ref_list->newPanelRef($panel); 116 + $new_panels = $ref_list->toDictionary(); 117 + 118 + $xactions[] = $dashboard->getApplicationTransactionTemplate() 119 + ->setTransactionType( 120 + PhabricatorDashboardPanelsTransaction::TRANSACTIONTYPE) 121 + ->setNewValue($new_panels); 150 122 151 - $redirect_uri = $engine->getQueryResultsPageURI($v_query); 123 + $editor = $dashboard->getApplicationTransactionEditor() 124 + ->setActor($viewer) 125 + ->setContentSourceFromRequest($request) 126 + ->setContinueOnNoEffect(true) 127 + ->setContinueOnMissingFields(true) 128 + ->applyTransactions($dashboard, $xactions); 152 129 153 - if (!$options) { 154 - $notice = id(new PHUIInfoView()) 155 - ->setSeverity(PHUIInfoView::SEVERITY_NOTICE) 156 - ->appendChild(pht('You do not have access to any dashboards. To '. 157 - 'continue, please create a dashboard first.')); 130 + return id(new AphrontRedirectResponse())->setURI($done_uri); 131 + } 132 + } 158 133 159 - return $this->newDialog() 160 - ->setTitle(pht('No Dashboards')) 161 - ->setWidth(AphrontDialogView::WIDTH_FORM) 162 - ->appendChild($notice) 163 - ->addCancelButton($redirect_uri); 134 + if ($v_dashboard) { 135 + $dashboard_phids = array($v_dashboard); 136 + } else { 137 + $dashboard_phids = array(); 164 138 } 165 139 166 140 $form = id(new AphrontFormView()) 167 - ->setUser($viewer) 168 - ->addHiddenInput('engine', $v_engine) 169 - ->addHiddenInput('query', $v_query) 170 - ->addHiddenInput('column', $v_column) 171 - ->appendChild( 141 + ->setViewer($viewer) 142 + ->appendControl( 172 143 id(new AphrontFormTextControl()) 173 144 ->setLabel(pht('Name')) 174 145 ->setName('name') 175 146 ->setValue($v_name) 176 147 ->setError($e_name)) 177 - ->appendChild( 178 - id(new AphrontFormSelectControl()) 179 - ->setUser($this->getViewer()) 180 - ->setValue($v_dashboard) 181 - ->setName('dashboardID') 182 - ->setOptions($options) 148 + ->appendControl( 149 + id(new AphrontFormTokenizerControl()) 150 + ->setValue($dashboard_phids) 151 + ->setError($e_dashboard) 152 + ->setName('dashboardPHIDs') 153 + ->setLimit(1) 154 + ->setDatasource(new PhabricatorDashboardDatasource()) 183 155 ->setLabel(pht('Dashboard'))); 184 156 185 157 return $this->newDialog() 186 158 ->setTitle(pht('Add Panel to Dashboard')) 187 159 ->setErrors($errors) 188 160 ->setWidth(AphrontDialogView::WIDTH_FORM) 189 - ->appendChild($form->buildLayoutView()) 161 + ->addHiddenInput('engine', $v_engine) 162 + ->addHiddenInput('query', $v_query) 163 + ->appendForm($form) 190 164 ->addCancelButton($redirect_uri) 191 165 ->addSubmitButton(pht('Add Panel')); 192 166
+8 -1
src/applications/dashboard/layoutconfig/PhabricatorDashboardPanelRefList.php
··· 87 87 return array_values(mpull($this->getPanelRefs(), 'toDictionary')); 88 88 } 89 89 90 - public function newPanelRef(PhabricatorDashboardPanel $panel, $column_key) { 90 + public function newPanelRef( 91 + PhabricatorDashboardPanel $panel, 92 + $column_key = null) { 93 + 94 + if ($column_key === null) { 95 + $column_key = head_key($this->columns); 96 + } 97 + 91 98 $ref = id(new PhabricatorDashboardPanelRef()) 92 99 ->setPanelKey($this->newPanelKey()) 93 100 ->setPanelPHID($panel->getPHID())
+2 -3
src/applications/dashboard/storage/PhabricatorDashboardPanel.php
··· 45 45 ) + parent::getConfiguration(); 46 46 } 47 47 48 - public function generatePHID() { 49 - return PhabricatorPHID::generateNewPHID( 50 - PhabricatorDashboardPanelPHIDType::TYPECONST); 48 + public function getPHIDType() { 49 + return PhabricatorDashboardPanelPHIDType::TYPECONST; 51 50 } 52 51 53 52 public function getProperty($key, $default = null) {
+27
src/applications/dashboard/xaction/panel/PhabricatorDashboardQueryPanelApplicationTransaction.php
··· 9 9 return 'class'; 10 10 } 11 11 12 + public function validateTransactions($object, array $xactions) { 13 + $errors = array(); 14 + 15 + $engines = PhabricatorApplicationSearchEngine::getAllEngines(); 16 + 17 + $old_value = $object->getProperty($this->getPropertyKey()); 18 + foreach ($xactions as $xaction) { 19 + $new_value = $xaction->getNewValue(); 20 + 21 + if ($new_value === $old_value) { 22 + continue; 23 + } 24 + 25 + if (!isset($engines[$new_value])) { 26 + $errors[] = $this->newInvalidError( 27 + pht( 28 + 'Application search engine class "%s" is unknown. Query panels '. 29 + 'must use a known search engine class.', 30 + $new_value), 31 + $xaction); 32 + continue; 33 + } 34 + } 35 + 36 + return $errors; 37 + } 38 + 12 39 }