Page MenuHomePhabricator

D18422.id44365.diff
No OneTemporary

D18422.id44365.diff

diff --git a/resources/sql/autopatches/20170814.search.01.qconfig.sql b/resources/sql/autopatches/20170814.search.01.qconfig.sql
new file mode 100644
--- /dev/null
+++ b/resources/sql/autopatches/20170814.search.01.qconfig.sql
@@ -0,0 +1,9 @@
+CREATE TABLE {$NAMESPACE}_search.search_namedqueryconfig (
+ id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
+ engineClassName VARCHAR(128) NOT NULL COLLATE {$COLLATE_TEXT},
+ scopePHID VARBINARY(64) NOT NULL,
+ properties LONGTEXT NOT NULL COLLATE {$COLLATE_TEXT},
+ dateCreated INT UNSIGNED NOT NULL,
+ dateModified INT UNSIGNED NOT NULL,
+ UNIQUE KEY `key_scope` (engineClassName, scopePHID)
+) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT};
diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php
--- a/src/__phutil_library_map__.php
+++ b/src/__phutil_library_map__.php
@@ -3189,6 +3189,8 @@
'PhabricatorMySQLSearchHost' => 'infrastructure/cluster/search/PhabricatorMySQLSearchHost.php',
'PhabricatorMySQLSetupCheck' => 'applications/config/check/PhabricatorMySQLSetupCheck.php',
'PhabricatorNamedQuery' => 'applications/search/storage/PhabricatorNamedQuery.php',
+ 'PhabricatorNamedQueryConfig' => 'applications/search/storage/PhabricatorNamedQueryConfig.php',
+ 'PhabricatorNamedQueryConfigQuery' => 'applications/search/query/PhabricatorNamedQueryConfigQuery.php',
'PhabricatorNamedQueryQuery' => 'applications/search/query/PhabricatorNamedQueryQuery.php',
'PhabricatorNavigationRemarkupRule' => 'infrastructure/markup/rule/PhabricatorNavigationRemarkupRule.php',
'PhabricatorNeverTriggerClock' => 'infrastructure/daemon/workers/clock/PhabricatorNeverTriggerClock.php',
@@ -3908,6 +3910,7 @@
'PhabricatorSearchDatasourceField' => 'applications/search/field/PhabricatorSearchDatasourceField.php',
'PhabricatorSearchDateControlField' => 'applications/search/field/PhabricatorSearchDateControlField.php',
'PhabricatorSearchDateField' => 'applications/search/field/PhabricatorSearchDateField.php',
+ 'PhabricatorSearchDefaultController' => 'applications/search/controller/PhabricatorSearchDefaultController.php',
'PhabricatorSearchDeleteController' => 'applications/search/controller/PhabricatorSearchDeleteController.php',
'PhabricatorSearchDocument' => 'applications/search/storage/document/PhabricatorSearchDocument.php',
'PhabricatorSearchDocumentField' => 'applications/search/storage/document/PhabricatorSearchDocumentField.php',
@@ -8552,6 +8555,11 @@
'PhabricatorSearchDAO',
'PhabricatorPolicyInterface',
),
+ 'PhabricatorNamedQueryConfig' => array(
+ 'PhabricatorSearchDAO',
+ 'PhabricatorPolicyInterface',
+ ),
+ 'PhabricatorNamedQueryConfigQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
'PhabricatorNamedQueryQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
'PhabricatorNavigationRemarkupRule' => 'PhutilRemarkupRule',
'PhabricatorNeverTriggerClock' => 'PhabricatorTriggerClock',
@@ -9448,6 +9456,7 @@
'PhabricatorSearchDatasourceField' => 'PhabricatorSearchTokenizerField',
'PhabricatorSearchDateControlField' => 'PhabricatorSearchField',
'PhabricatorSearchDateField' => 'PhabricatorSearchField',
+ 'PhabricatorSearchDefaultController' => 'PhabricatorSearchBaseController',
'PhabricatorSearchDeleteController' => 'PhabricatorSearchBaseController',
'PhabricatorSearchDocument' => 'PhabricatorSearchDAO',
'PhabricatorSearchDocumentField' => 'PhabricatorSearchDAO',
diff --git a/src/applications/search/application/PhabricatorSearchApplication.php b/src/applications/search/application/PhabricatorSearchApplication.php
--- a/src/applications/search/application/PhabricatorSearchApplication.php
+++ b/src/applications/search/application/PhabricatorSearchApplication.php
@@ -34,6 +34,8 @@
'hovercard/'
=> 'PhabricatorSearchHovercardController',
'edit/(?P<queryKey>[^/]+)/' => 'PhabricatorSearchEditController',
+ 'default/(?P<queryKey>[^/]+)/(?P<engine>[^/]+)/'
+ => 'PhabricatorSearchDefaultController',
'delete/(?P<queryKey>[^/]+)/(?P<engine>[^/]+)/'
=> 'PhabricatorSearchDeleteController',
'order/(?P<engine>[^/]+)/' => 'PhabricatorSearchOrderController',
diff --git a/src/applications/search/controller/PhabricatorApplicationSearchController.php b/src/applications/search/controller/PhabricatorApplicationSearchController.php
--- a/src/applications/search/controller/PhabricatorApplicationSearchController.php
+++ b/src/applications/search/controller/PhabricatorApplicationSearchController.php
@@ -127,7 +127,7 @@
if (!$found_query_data) {
// Otherwise, there's no query data so just run the user's default
// query for this application.
- $query_key = head_key($engine->loadEnabledNamedQueries());
+ $query_key = $engine->getDefaultQueryKey();
}
}
@@ -400,6 +400,8 @@
'orderURI' => '/search/order/'.get_class($engine).'/',
));
+ $default_key = $engine->getDefaultQueryKey();
+
foreach ($named_queries as $named_query) {
$class = get_class($engine);
$key = $named_query->getQueryKey();
@@ -410,28 +412,64 @@
if ($named_query->getIsBuiltin() && $named_query->getIsDisabled()) {
$icon = 'fa-plus';
+ $disable_name = pht('Enable');
} else {
$icon = 'fa-times';
+ if ($named_query->getIsBuiltin()) {
+ $disable_name = pht('Disable');
+ } else {
+ $disable_name = pht('Delete');
+ }
}
$item->addAction(
id(new PHUIListItemView())
->setIcon($icon)
->setHref('/search/delete/'.$key.'/'.$class.'/')
+ ->setRenderNameAsTooltip(true)
+ ->setName($disable_name)
->setWorkflow(true));
+ $default_disabled = $named_query->getIsDisabled();
+ $default_icon = 'fa-thumb-tack';
+
+ if ($default_key === $key) {
+ $default_color = 'green';
+ } else {
+ $default_color = null;
+ }
+
+ $item->addAction(
+ id(new PHUIListItemView())
+ ->setIcon("{$default_icon} {$default_color}")
+ ->setHref('/search/default/'.$key.'/'.$class.'/')
+ ->setRenderNameAsTooltip(true)
+ ->setName(pht('Make Default'))
+ ->setWorkflow(true)
+ ->setDisabled($default_disabled));
+
if ($named_query->getIsBuiltin()) {
- if ($named_query->getIsDisabled()) {
- $item->addIcon('fa-times lightgreytext', pht('Disabled'));
- $item->setDisabled(true);
- } else {
- $item->addIcon('fa-lock lightgreytext', pht('Builtin'));
- }
+ $edit_icon = 'fa-lock lightgreytext';
+ $edit_disabled = true;
+ $edit_name = pht('Builtin');
+ $edit_href = null;
} else {
- $item->addAction(
- id(new PHUIListItemView())
- ->setIcon('fa-pencil')
- ->setHref('/search/edit/'.$key.'/'));
+ $edit_icon = 'fa-pencil';
+ $edit_disabled = false;
+ $edit_name = pht('Edit');
+ $edit_href = '/search/edit/'.$key.'/';
+ }
+
+ $item->addAction(
+ id(new PHUIListItemView())
+ ->setIcon($edit_icon)
+ ->setHref($edit_href)
+ ->setRenderNameAsTooltip(true)
+ ->setName($edit_name)
+ ->setDisabled($edit_disabled));
+
+ if ($named_query->getIsDisabled()) {
+ $item->setDisabled(true);
}
$item->setGrippable(true);
@@ -610,7 +648,7 @@
$engine_class = get_class($engine);
$query_key = $this->getQueryKey();
if (!$query_key) {
- $query_key = head_key($engine->loadEnabledNamedQueries());
+ $query_key = $engine->getDefaultQueryKey();
}
$can_use = $engine->canUseInPanelContext();
diff --git a/src/applications/search/controller/PhabricatorSearchDefaultController.php b/src/applications/search/controller/PhabricatorSearchDefaultController.php
new file mode 100644
--- /dev/null
+++ b/src/applications/search/controller/PhabricatorSearchDefaultController.php
@@ -0,0 +1,81 @@
+<?php
+
+final class PhabricatorSearchDefaultController
+ extends PhabricatorSearchBaseController {
+
+ public function handleRequest(AphrontRequest $request) {
+ $viewer = $this->getViewer();
+ $engine_class = $request->getURIData('engine');
+
+ $base_class = 'PhabricatorApplicationSearchEngine';
+ if (!is_subclass_of($engine_class, $base_class)) {
+ return new Aphront400Response();
+ }
+
+ $engine = newv($engine_class, array());
+ $engine->setViewer($viewer);
+
+ $key = $request->getURIData('queryKey');
+
+ $named_query = id(new PhabricatorNamedQueryQuery())
+ ->setViewer($viewer)
+ ->withEngineClassNames(array($engine_class))
+ ->withQueryKeys(array($key))
+ ->withUserPHIDs(array($viewer->getPHID()))
+ ->executeOne();
+
+ if (!$named_query && $engine->isBuiltinQuery($key)) {
+ $named_query = $engine->getBuiltinQuery($key);
+ }
+
+ if (!$named_query) {
+ return new Aphront404Response();
+ }
+
+ $return_uri = $engine->getQueryManagementURI();
+
+ $builtin = null;
+ if ($engine->isBuiltinQuery($key)) {
+ $builtin = $engine->getBuiltinQuery($key);
+ }
+
+ if ($request->isFormPost()) {
+ $config = id(new PhabricatorNamedQueryConfigQuery())
+ ->setViewer($viewer)
+ ->withEngineClassNames(array($engine_class))
+ ->withScopePHIDs(array($viewer->getPHID()))
+ ->executeOne();
+ if (!$config) {
+ $config = PhabricatorNamedQueryConfig::initializeNewQueryConfig()
+ ->setEngineClassName($engine_class)
+ ->setScopePHID($viewer->getPHID());
+ }
+
+ $config->setConfigProperty(
+ PhabricatorNamedQueryConfig::PROPERTY_PINNED,
+ $key);
+
+ $config->save();
+
+ return id(new AphrontRedirectResponse())->setURI($return_uri);
+ }
+
+ if ($named_query->getIsBuiltin()) {
+ $query_name = $builtin->getQueryName();
+ } else {
+ $query_name = $named_query->getQueryName();
+ }
+
+ $title = pht('Set Default Query');
+ $body = pht(
+ 'This query will become your default query in the current application.');
+ $button = pht('Set Default Query');
+
+ return $this->newDialog()
+ ->setTitle($title)
+ ->appendChild($body)
+ ->addCancelButton($return_uri)
+ ->addSubmitButton($button);
+ }
+
+}
diff --git a/src/applications/search/controller/PhabricatorSearchEditController.php b/src/applications/search/controller/PhabricatorSearchEditController.php
--- a/src/applications/search/controller/PhabricatorSearchEditController.php
+++ b/src/applications/search/controller/PhabricatorSearchEditController.php
@@ -10,7 +10,6 @@
->setViewer($viewer)
->withQueryKeys(array($request->getURIData('queryKey')))
->executeOne();
-
if (!$saved_query) {
return new Aphront404Response();
}
diff --git a/src/applications/search/engine/PhabricatorApplicationSearchEngine.php b/src/applications/search/engine/PhabricatorApplicationSearchEngine.php
--- a/src/applications/search/engine/PhabricatorApplicationSearchEngine.php
+++ b/src/applications/search/engine/PhabricatorApplicationSearchEngine.php
@@ -511,6 +511,34 @@
return $named_queries;
}
+ public function getDefaultQueryKey() {
+ $viewer = $this->requireViewer();
+
+ $configs = id(new PhabricatorNamedQueryConfigQuery())
+ ->setViewer($viewer)
+ ->withEngineClassNames(array(get_class($this)))
+ ->withScopePHIDs(
+ array(
+ $viewer->getPHID(),
+ PhabricatorNamedQueryConfig::SCOPE_GLOBAL,
+ ))
+ ->execute();
+ $configs = msortv($configs, 'getStrengthSortVector');
+
+ $key_pinned = PhabricatorNamedQueryConfig::PROPERTY_PINNED;
+ $map = $this->loadEnabledNamedQueries();
+ foreach ($configs as $config) {
+ $pinned = $config->getConfigProperty($key_pinned);
+ if (!isset($map[$pinned])) {
+ continue;
+ }
+
+ return $pinned;
+ }
+
+ return head_key($map);
+ }
+
protected function setQueryProjects(
PhabricatorCursorPagedPolicyAwareQuery $query,
PhabricatorSavedQuery $saved) {
diff --git a/src/applications/search/query/PhabricatorNamedQueryConfigQuery.php b/src/applications/search/query/PhabricatorNamedQueryConfigQuery.php
new file mode 100644
--- /dev/null
+++ b/src/applications/search/query/PhabricatorNamedQueryConfigQuery.php
@@ -0,0 +1,64 @@
+<?php
+
+final class PhabricatorNamedQueryConfigQuery
+ extends PhabricatorCursorPagedPolicyAwareQuery {
+
+ private $ids;
+ private $engineClassNames;
+ private $scopePHIDs;
+
+ public function withIDs(array $ids) {
+ $this->ids = $ids;
+ return $this;
+ }
+
+ public function withScopePHIDs(array $scope_phids) {
+ $this->scopePHIDs = $scope_phids;
+ return $this;
+ }
+
+ public function withEngineClassNames(array $engine_class_names) {
+ $this->engineClassNames = $engine_class_names;
+ return $this;
+ }
+
+ public function newResultObject() {
+ return new PhabricatorNamedQueryConfig();
+ }
+
+ protected function loadPage() {
+ return $this->loadStandardPage($this->newResultObject());
+ }
+
+ protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) {
+ $where = parent::buildWhereClauseParts($conn);
+
+ if ($this->ids !== null) {
+ $where[] = qsprintf(
+ $conn,
+ 'id IN (%Ld)',
+ $this->ids);
+ }
+
+ if ($this->engineClassNames !== null) {
+ $where[] = qsprintf(
+ $conn,
+ 'engineClassName IN (%Ls)',
+ $this->engineClassNames);
+ }
+
+ if ($this->scopePHIDs !== null) {
+ $where[] = qsprintf(
+ $conn,
+ 'scopePHID IN (%Ls)',
+ $this->scopePHIDs);
+ }
+
+ return $where;
+ }
+
+ public function getQueryApplicationClass() {
+ return 'PhabricatorSearchApplication';
+ }
+
+}
diff --git a/src/applications/search/storage/PhabricatorNamedQueryConfig.php b/src/applications/search/storage/PhabricatorNamedQueryConfig.php
new file mode 100644
--- /dev/null
+++ b/src/applications/search/storage/PhabricatorNamedQueryConfig.php
@@ -0,0 +1,92 @@
+<?php
+
+final class PhabricatorNamedQueryConfig
+ extends PhabricatorSearchDAO
+ implements PhabricatorPolicyInterface {
+
+ protected $engineClassName;
+ protected $scopePHID;
+ protected $properties = array();
+
+ const SCOPE_GLOBAL = 'scope.global';
+
+ const PROPERTY_PINNED = 'pinned';
+
+ protected function getConfiguration() {
+ return array(
+ self::CONFIG_SERIALIZATION => array(
+ 'properties' => self::SERIALIZATION_JSON,
+ ),
+ self::CONFIG_COLUMN_SCHEMA => array(
+ 'engineClassName' => 'text128',
+ ),
+ self::CONFIG_KEY_SCHEMA => array(
+ 'key_scope' => array(
+ 'columns' => array('engineClassName', 'scopePHID'),
+ 'unique' => true,
+ ),
+ ),
+ ) + parent::getConfiguration();
+ }
+
+ public static function initializeNewQueryConfig() {
+ return new self();
+ }
+
+ public function isGlobal() {
+ return ($this->getScopePHID() == self::SCOPE_GLOBAL);
+ }
+
+ public function getConfigProperty($key, $default = null) {
+ return idx($this->properties, $key, $default);
+ }
+
+ public function setConfigProperty($key, $value) {
+ $this->properties[$key] = $value;
+ return $this;
+ }
+
+ public function getStrengthSortVector() {
+ // Apply personal preferences before global preferences.
+ if (!$this->isGlobal()) {
+ $phase = 0;
+ } else {
+ $phase = 1;
+ }
+
+ return id(new PhutilSortVector())
+ ->addInt($phase)
+ ->addInt($this->getID());
+ }
+
+
+/* -( PhabricatorPolicyInterface )----------------------------------------- */
+
+
+ public function getCapabilities() {
+ return array(
+ PhabricatorPolicyCapability::CAN_VIEW,
+ );
+ }
+
+ public function getPolicy($capability) {
+ return PhabricatorPolicies::POLICY_NOONE;
+ }
+
+ public function hasAutomaticCapability($capability, PhabricatorUser $viewer) {
+ if ($this->isGlobal()) {
+ return true;
+ }
+
+ if ($viewer->getPHID() == $this->getScopePHID()) {
+ return true;
+ }
+
+ return false;
+ }
+
+ public function describeAutomaticCapability($capability) {
+ return null;
+ }
+
+}

File Metadata

Mime Type
text/plain
Expires
Wed, Dec 25, 6:36 PM (2 h, 33 m)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
6927404
Default Alt Text
D18422.id44365.diff (16 KB)

Event Timeline