-
Notifications
You must be signed in to change notification settings - Fork 8.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Timelion typeahead for argument values #14801
Conversation
I think the bug causing the functional test failures has been fixed in master. |
a77295a
to
cf746f6
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wow, nice work man! This is a solid improvement.
I haven't finished going through everything but I had a couple of more fundamental changes I wanted to share with you before I went any further. Love to hear your thoughts.
const message = JSON.parse(e.message); | ||
const location = message.location; | ||
|
||
if (message.type === 'incompleteFunction') { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe this should be a switch/case now?
} | ||
|
||
return help.suggestions; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was having a hard time following the logic around the conditions within this function. I think we could make this a little easier to follow if we split this up into three functions, and made the consuming code responsible for handling the condition. This will probably be easier to test, too.
return {
hasDynamicSuggestionsForArgument: (functionName, argName) => {
return (customHandlers[functionName] && customHandlers[functionName][argName]);
},
getDynamicSuggestionsForArgument: async (functionName, argName, functionArgs, partialInput = '') => {
return await customHandlers[functionName][argName](partialInput, functionArgs);
},
getStaticSuggestionsForInput: (partialInput = '', staticSuggestions = []) => {
if (partialInput) {
return staticSuggestions.filter(suggestion => {
return suggestion.name.includes(partialInput);
});
}
return staticSuggestions;
},
};
|
||
const activeArg = activeFunc.arguments.find((argument) => { | ||
return inLocation(cursorPosition, argument.location); | ||
}); | ||
// return argument_value suggestions when cursor is inside agrument value | ||
if (activeArg && activeArg.type === 'namedArg' && inLocation(cursorPosition, activeArg.value.location)) { | ||
// TODO - provide argument value suggestions once function list contains required data | ||
return { list: [], location: activeArg.value.location, type: SUGGESTION_TYPE.ARGUMENT_VALUE }; | ||
const valueSuggestions = await getArgValueSuggestions( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This would become:
const {
function: functionName,
arguments: functionArgs,
} = activeFunc;
const {
name: argName,
value: { text: partialInput },
} = activeArg;
let valueSuggestions;
if (hasDynamicSuggestionsForArgument(functionName, argName)) {
valueSuggestions = await getDynamicSuggestionsForArgument(functionName, argName, functionArgs, partialInput);
} else {
const {
suggestions: staticSuggestions,
} = functionHelp.args.find((arg) => {
return arg.name === activeArg.name;
});
valueSuggestions = getStaticSuggestionsForInput(partialInput, staticSuggestions);
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This comment pertains to my last comment at the bottom.
} catch (e) { | ||
// The expression isn't correctly formatted, so JSON.parse threw an error. | ||
return reject(); | ||
const valueSuggestions = await getArgValueSuggestions(message.name, null, argHelp, message.currentFunction, message.currentArgs); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And this becomes:
const {
name: argName,
currentFunction: functionName,
currentArgs: functionArgs,
} = message;
let valueSuggestions = [];
if (hasDynamicSuggestionsForArgument(functionName, argName)) {
valueSuggestions = await getDynamicSuggestionsForArgument(functionName, argName, functionArgs);
} else {
const functionHelp = functionList.find(func => func.name === functionName);
if (functionHelp) {
valueSuggestions = functionHelp.args.find(arg => arg.name === argName);
}
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This comment pertains to my last comment at the bottom.
const newCaretOffset = min + argumentName.length; | ||
setCaretOffset(newCaretOffset); | ||
break; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's a lot of repetition here. I think this becomes a little more maintainable if we extract the repetitive parts. I haven't tested this btw.
const { min, max } = suggestibleFunctionLocation;
let insertedValue;
let insertPositionMinOffset = 0;
switch (scope.suggestions.type) {
case SUGGESTION_TYPE.FUNCTIONS: {
// Position the caret inside of the function parentheses.
insertedValue = `${scope.suggestions.list[suggestionIndex].name}()`;
// Update the expression with the function.
// min advanced one to not replace function '.'
insertPositionMinOffset = 1;
break;
}
case SUGGESTION_TYPE.ARGUMENTS: {
// Position the caret after the '='
insertedValue = `${scope.suggestions.list[suggestionIndex].name}=`;
break;
}
case SUGGESTION_TYPE.ARGUMENT_VALUE: {
// Position the caret after the '='
insertedValue = `${scope.suggestions.list[suggestionIndex].name}`;
break;
}
}
const updatedExpression = insertAtLocation(insertedValue, scope.sheet, min + insertPositionMinOffset, max);
scope.sheet = updatedExpression;
const newCaretOffset = min + insertedValue.length;
setCaretOffset(newCaretOffset);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I had meant to go back and out the duplicated code to clean this switch statement but just forgot about it. Thanks for cleaning it up. Your code block worked great
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM! Had a couple nitpicky suggestions but feel free to disregard if you don't like them.
activeArg.name, | ||
activeArg.value.text, | ||
functionHelp.args.find((arg) => { | ||
const { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It might be nice to destructure the methods in argValueSuggestions
, too.
const {
hasDynamicSuggestionsForArgument,
getDynamicSuggestionsForArgument,
getStaticSuggestionsForInput,
} = argValueSuggestions;
This could make the code on lines 112 through 120 a bit terser.
return { list, location: message.location, type: SUGGESTION_TYPE.FUNCTIONS }; | ||
} | ||
case 'incompleteArgument': { | ||
const { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same suggestion about destructuring argValueSuggestions
applies here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Found a couple more minor things.
@@ -13,7 +13,10 @@ export default new Chainable('fit', { | |||
{ | |||
name: 'mode', | |||
types: ['string'], | |||
help: 'The algorithm to use for fitting the series to the target. One of: ' + _.keys(fitFunctions).join(', ') | |||
help: 'The algorithm to use for fitting the series to the target. One of: ' + _.keys(fitFunctions).join(', '), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can use a template literal here.
@@ -16,7 +16,10 @@ export default new Chainable('trend', { | |||
{ | |||
name: 'mode', | |||
types: ['string'], | |||
help: 'The algorithm to use for generating the trend line. One of: ' + _.keys(validRegressions).join(', ') | |||
help: 'The algorithm to use for generating the trend line. One of: ' + _.keys(validRegressions).join(', '), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here too.
@@ -50,7 +50,10 @@ export default new Chainable('yaxis', { | |||
{ | |||
name: 'units', | |||
types: ['string', 'null'], | |||
help: 'The function to use for formatting y-axis labels. One of: ' + _.values(tickFormatters).join(', ') | |||
help: 'The function to use for formatting y-axis labels. One of: ' + _.values(tickFormatters).join(', '), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here too.
772eea2
to
c99b08c
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
…ngle getSuggetions method
7f92145
to
d833bdc
Compare
* timelion argument value suggestions for legend function * update functions with argument value suggestions * use async/await instead of promise resolve/reject for suggestion generation * lookup value suggestions for es index and timefield arguments * custom handlers for es metric and split arguments * update suggestions unit test * remove duplicate code from insertSuggestion switch * refactor arg_value_suggestions to provide three methods instead of single getSuggetions method * template literal * update es index argument desc to include note about type ahead support
* timelion argument value suggestions for legend function * update functions with argument value suggestions * use async/await instead of promise resolve/reject for suggestion generation * lookup value suggestions for es index and timefield arguments * custom handlers for es metric and split arguments * update suggestions unit test * remove duplicate code from insertSuggestion switch * refactor arg_value_suggestions to provide three methods instead of single getSuggetions method * template literal * update es index argument desc to include note about type ahead support
* timelion argument value suggestions for legend function * update functions with argument value suggestions * use async/await instead of promise resolve/reject for suggestion generation * lookup value suggestions for es index and timefield arguments * custom handlers for es metric and split arguments * update suggestions unit test * remove duplicate code from insertSuggestion switch * refactor arg_value_suggestions to provide three methods instead of single getSuggetions method * template literal * update es index argument desc to include note about type ahead support
* timelion argument value suggestions for legend function * update functions with argument value suggestions * use async/await instead of promise resolve/reject for suggestion generation * lookup value suggestions for es index and timefield arguments * custom handlers for es metric and split arguments * update suggestions unit test * remove duplicate code from insertSuggestion switch * refactor arg_value_suggestions to provide three methods instead of single getSuggetions method * template literal * update es index argument desc to include note about type ahead support
* timelion argument value suggestions for legend function * update functions with argument value suggestions * use async/await instead of promise resolve/reject for suggestion generation * lookup value suggestions for es index and timefield arguments * custom handlers for es metric and split arguments * update suggestions unit test * remove duplicate code from insertSuggestion switch * refactor arg_value_suggestions to provide three methods instead of single getSuggetions method * template literal * update es index argument desc to include note about type ahead support
Adds typeahead support for timelion argument values, #9730