summaryrefslogtreecommitdiffstats
path: root/polygerrit-ui/app/elements/core/gr-search-bar/gr-search-bar.js
diff options
context:
space:
mode:
Diffstat (limited to 'polygerrit-ui/app/elements/core/gr-search-bar/gr-search-bar.js')
-rw-r--r--polygerrit-ui/app/elements/core/gr-search-bar/gr-search-bar.js127
1 files changed, 76 insertions, 51 deletions
diff --git a/polygerrit-ui/app/elements/core/gr-search-bar/gr-search-bar.js b/polygerrit-ui/app/elements/core/gr-search-bar/gr-search-bar.js
index 4452b04880..de015348f7 100644
--- a/polygerrit-ui/app/elements/core/gr-search-bar/gr-search-bar.js
+++ b/polygerrit-ui/app/elements/core/gr-search-bar/gr-search-bar.js
@@ -14,11 +14,12 @@
(function() {
'use strict';
- // Possible static search options for auto complete.
- var SEARCH_OPERATORS = [
+ // Possible static search options for auto complete, without negations.
+ const SEARCH_OPERATORS = [
'added:',
'age:',
'age:1week', // Give an example age
+ 'assignee:',
'author:',
'branch:',
'bug:',
@@ -39,20 +40,26 @@
'has:edit',
'has:star',
'has:stars',
+ 'has:unresolved',
+ 'hashtag:',
'intopic:',
'is:',
'is:abandoned',
+ 'is:assigned',
'is:closed',
- 'is:draft',
+ 'is:ignored',
'is:mergeable',
'is:merged',
'is:open',
'is:owner',
'is:pending',
+ 'is:private',
'is:reviewed',
'is:reviewer',
'is:starred',
+ 'is:submittable',
'is:watched',
+ 'is:wip',
'label:',
'message:',
'owner:',
@@ -71,7 +78,6 @@
'status:',
'status:abandoned',
'status:closed',
- 'status:draft',
'status:merged',
'status:open',
'status:pending',
@@ -80,24 +86,26 @@
'tr:',
];
- var SELF_EXPRESSION = 'self';
+ // All of the ops, with corresponding negations.
+ const SEARCH_OPERATORS_WITH_NEGATIONS =
+ SEARCH_OPERATORS.concat(SEARCH_OPERATORS.map(op => `-${op}`));
- var MAX_AUTOCOMPLETE_RESULTS = 10;
+ const SELF_EXPRESSION = 'self';
+ const ME_EXPRESSION = 'me';
- var TOKENIZE_REGEX = /(?:[^\s"]+|"[^"]*")+\s*/g;
+ const MAX_AUTOCOMPLETE_RESULTS = 10;
+
+ const TOKENIZE_REGEX = /(?:[^\s"]+|"[^"]*")+\s*/g;
Polymer({
is: 'gr-search-bar',
behaviors: [
+ Gerrit.AnonymousNameBehavior,
Gerrit.KeyboardShortcutBehavior,
Gerrit.URLEncodingBehavior,
],
- listeners: {
- 'searchButton.tap': '_preventDefaultAndNavigateToInputVal',
- },
-
keyBindings: {
'/': '_handleForwardSlashKey',
},
@@ -111,22 +119,33 @@
},
keyEventTarget: {
type: Object,
- value: function() { return document.body; },
+ value() { return document.body; },
},
query: {
type: Function,
- value: function() {
+ value() {
return this._getSearchSuggestions.bind(this);
},
},
_inputVal: String,
+ _threshold: {
+ type: Number,
+ value: 1,
+ },
+ _config: Object,
},
- _valueChanged: function(value) {
+ attached() {
+ this.$.restAPI.getConfig().then(cfg => {
+ this._config = cfg;
+ });
+ },
+
+ _valueChanged(value) {
this._inputVal = value;
},
- _handleInputCommit: function(e) {
+ _handleInputCommit(e) {
this._preventDefaultAndNavigateToInputVal(e);
},
@@ -138,9 +157,9 @@
*
* @param {!Event} e
*/
- _preventDefaultAndNavigateToInputVal: function(e) {
+ _preventDefaultAndNavigateToInputVal(e) {
e.preventDefault();
- var target = Polymer.dom(e).rootTarget;
+ const target = Polymer.dom(e).rootTarget;
// If the target is the #searchInput or has a sub-input component, that
// is what holds the focus as opposed to the target from the DOM event.
if (target.$.input) {
@@ -153,6 +172,10 @@
}
},
+ _accountOrAnon(name) {
+ return this.getUserName(this._config, name, false);
+ },
+
/**
* Fetch from the API the predicted accounts.
* @param {string} predicate - The first part of the search term, e.g.
@@ -162,22 +185,26 @@
* @return {!Promise} This returns a promise that resolves to an array of
* strings.
*/
- _fetchAccounts: function(predicate, expression) {
+ _fetchAccounts(predicate, expression) {
if (expression.length === 0) { return Promise.resolve([]); }
return this.$.restAPI.getSuggestedAccounts(
expression,
MAX_AUTOCOMPLETE_RESULTS)
- .then(function(accounts) {
+ .then(accounts => {
if (!accounts) { return []; }
- return accounts.map(function(acct) {
- return predicate + ':"' + acct.name + ' <' + acct.email + '>"';
- });
- }).then(function(accounts) {
+ return accounts.map(acct => acct.email ?
+ `${predicate}:${acct.email}` :
+ `${predicate}:"${this._accountOrAnon(acct)}"`);
+ }).then(accounts => {
// When the expression supplied is a beginning substring of 'self',
// add it as an autocomplete option.
- return SELF_EXPRESSION.indexOf(expression) === 0 ?
- accounts.concat([predicate + ':' + SELF_EXPRESSION]) :
- accounts;
+ if (SELF_EXPRESSION.startsWith(expression)) {
+ return accounts.concat([predicate + ':' + SELF_EXPRESSION]);
+ } else if (ME_EXPRESSION.startsWith(expression)) {
+ return accounts.concat([predicate + ':' + ME_EXPRESSION]);
+ } else {
+ return accounts;
+ }
});
},
@@ -190,15 +217,15 @@
* @return {!Promise} This returns a promise that resolves to an array of
* strings.
*/
- _fetchGroups: function(predicate, expression) {
+ _fetchGroups(predicate, expression) {
if (expression.length === 0) { return Promise.resolve([]); }
return this.$.restAPI.getSuggestedGroups(
expression,
MAX_AUTOCOMPLETE_RESULTS)
- .then(function(groups) {
+ .then(groups => {
if (!groups) { return []; }
- var keys = Object.keys(groups);
- return keys.map(function(key) { return predicate + ':' + key; });
+ const keys = Object.keys(groups);
+ return keys.map(key => predicate + ':' + key);
});
},
@@ -211,14 +238,14 @@
* @return {!Promise} This returns a promise that resolves to an array of
* strings.
*/
- _fetchProjects: function(predicate, expression) {
+ _fetchProjects(predicate, expression) {
return this.$.restAPI.getSuggestedProjects(
expression,
MAX_AUTOCOMPLETE_RESULTS)
- .then(function(projects) {
+ .then(projects => {
if (!projects) { return []; }
- var keys = Object.keys(projects);
- return keys.map(function(key) { return predicate + ':' + key; });
+ const keys = Object.keys(projects);
+ return keys.map(key => predicate + ':' + key);
});
},
@@ -229,11 +256,11 @@
* @return {!Promise} This returns a promise that resolves to an array of
* strings.
*/
- _fetchSuggestions: function(input) {
+ _fetchSuggestions(input) {
// Split the input on colon to get a two part predicate/expression.
- var splitInput = input.split(':');
- var predicate = splitInput[0];
- var expression = splitInput[1] || '';
+ const splitInput = input.split(':');
+ const predicate = splitInput[0];
+ const expression = splitInput[1] || '';
// Switch on the predicate to determine what to autocomplete.
switch (predicate) {
case 'ownerin':
@@ -258,10 +285,8 @@
return this._fetchAccounts(predicate, expression);
default:
- return Promise.resolve(SEARCH_OPERATORS
- .filter(function(operator) {
- return operator.indexOf(input) !== -1;
- }));
+ return Promise.resolve(SEARCH_OPERATORS_WITH_NEGATIONS
+ .filter(operator => operator.includes(input)));
}
},
@@ -271,19 +296,19 @@
* @return {!Promise} This returns a promise that resolves to an array of
* strings.
*/
- _getSearchSuggestions: function(input) {
+ _getSearchSuggestions(input) {
// Allow spaces within quoted terms.
- var tokens = input.match(TOKENIZE_REGEX);
- var trimmedInput = tokens[tokens.length - 1].toLowerCase();
+ const tokens = input.match(TOKENIZE_REGEX);
+ const trimmedInput = tokens[tokens.length - 1].toLowerCase();
return this._fetchSuggestions(trimmedInput)
- .then(function(operators) {
+ .then(operators => {
if (!operators || !operators.length) { return []; }
return operators
// Prioritize results that start with the input.
- .sort(function(a, b) {
- var aContains = a.toLowerCase().indexOf(trimmedInput);
- var bContains = b.toLowerCase().indexOf(trimmedInput);
+ .sort((a, b) => {
+ const aContains = a.toLowerCase().indexOf(trimmedInput);
+ const bContains = b.toLowerCase().indexOf(trimmedInput);
if (aContains === bContains) {
return a.localeCompare(b);
}
@@ -298,7 +323,7 @@
// Return only the first {MAX_AUTOCOMPLETE_RESULTS} results.
.slice(0, MAX_AUTOCOMPLETE_RESULTS - 1)
// Map to an object to play nice with gr-autocomplete.
- .map(function(operator) {
+ .map(operator => {
return {
name: operator,
value: operator,
@@ -307,7 +332,7 @@
});
},
- _handleForwardSlashKey: function(e) {
+ _handleForwardSlashKey(e) {
if (this.shouldSuppressKeyboardShortcut(e) ||
this.modifierPressed(e)) { return; }