azuremonitor: adds macros to slate intellisense

and adds tab as well as enter key for autocomplete
This commit is contained in:
Daniel Lee 2019-01-29 15:02:46 +01:00
parent a1609a8d53
commit 2d3e02d58b
3 changed files with 57 additions and 31 deletions

View File

@ -4,8 +4,6 @@ import Kusto from './kusto';
import React, { Component } from 'react'; import React, { Component } from 'react';
import coreModule from 'app/core/core_module'; import coreModule from 'app/core/core_module';
class Editor extends Component<any, any> { class Editor extends Component<any, any> {
constructor(props) { constructor(props) {
super(props); super(props);

View File

@ -24,27 +24,53 @@ export const FUNCTIONS = [
{ text: 'min', display: 'min()', hint: '' }, { text: 'min', display: 'min()', hint: '' },
{ text: 'max', display: 'max()', hint: '' }, { text: 'max', display: 'max()', hint: '' },
{ text: 'avg', display: 'avg()', hint: '' }, { text: 'avg', display: 'avg()', hint: '' },
{
text: '$__timeFilter',
display: '$__timeFilter()',
hint: 'Macro that uses the selected timerange in Grafana to filter the query.',
},
{
text: '$__escapeMulti',
display: '$__escapeMulti()',
hint: 'Macro to escape multi-value template variables that contain illegal characters.',
},
{ text: '$__contains', display: '$__contains()', hint: 'Macro for multi-value template variables.' },
]; ];
export const KEYWORDS = [ export const KEYWORDS = [
'by', 'on', 'contains', 'notcontains', 'containscs', 'notcontainscs', 'startswith', 'has', 'matches', 'regex', 'true', 'by',
'false', 'and', 'or', 'typeof', 'int', 'string', 'date', 'datetime', 'time', 'long', 'real', 'boolean', 'bool', 'on',
'contains',
'notcontains',
'containscs',
'notcontainscs',
'startswith',
'has',
'matches',
'regex',
'true',
'false',
'and',
'or',
'typeof',
'int',
'string',
'date',
'datetime',
'time',
'long',
'real',
'boolean',
'bool',
// add some more keywords // add some more keywords
'where', 'order' 'where',
'order',
]; ];
// Kusto operators // Kusto operators
// export const OPERATORS = ['+', '-', '*', '/', '>', '<', '==', '<>', '<=', '>=', '~', '!~']; // export const OPERATORS = ['+', '-', '*', '/', '>', '<', '==', '<>', '<=', '>=', '~', '!~'];
export const DURATION = [ export const DURATION = ['SECONDS', 'MINUTES', 'HOURS', 'DAYS', 'WEEKS', 'MONTHS', 'YEARS'];
'SECONDS',
'MINUTES',
'HOURS',
'DAYS',
'WEEKS',
'MONTHS',
'YEARS'
];
const tokenizer = { const tokenizer = {
comment: { comment: {
@ -70,7 +96,7 @@ const tokenizer = {
number: /\b0x[\da-f]+\b|(?:\b\d+\.?\d*|\B\.\d+)(?:e[+-]?\d+)?/i, number: /\b0x[\da-f]+\b|(?:\b\d+\.?\d*|\B\.\d+)(?:e[+-]?\d+)?/i,
operator: /-|\+|\*|\/|>|<|==|<=?|>=?|<>|!~|~|=|\|/, operator: /-|\+|\*|\/|>|<|==|<=?|>=?|<>|!~|~|=|\|/,
punctuation: /[{};(),.:]/, punctuation: /[{};(),.:]/,
variable: /(\[\[(.+?)\]\])|(\$(.+?))\b/ variable: /(\[\[(.+?)\]\])|(\$(.+?))\b/,
}; };
tokenizer['function-context'].inside = { tokenizer['function-context'].inside = {

View File

@ -17,7 +17,6 @@ import ReactDOM from 'react-dom';
import React from 'react'; import React from 'react';
import _ from 'lodash'; import _ from 'lodash';
function flattenSuggestions(s) { function flattenSuggestions(s) {
return s ? s.reduce((acc, g) => acc.concat(g.items), []) : []; return s ? s.reduce((acc, g) => acc.concat(g.items), []) : [];
} }
@ -107,14 +106,14 @@ class QueryField extends React.Component<any, any> {
}); });
window.requestAnimationFrame(this.onTypeahead); window.requestAnimationFrame(this.onTypeahead);
} };
request = (url?) => { request = (url?) => {
if (this.props.request) { if (this.props.request) {
return this.props.request(url); return this.props.request(url);
} }
return fetch(url); return fetch(url);
} };
onChangeQuery = () => { onChangeQuery = () => {
// Send text change to parent // Send text change to parent
@ -122,7 +121,7 @@ class QueryField extends React.Component<any, any> {
if (onQueryChange) { if (onQueryChange) {
onQueryChange(Plain.serialize(this.state.value)); onQueryChange(Plain.serialize(this.state.value));
} }
} };
onKeyDown = (event, change) => { onKeyDown = (event, change) => {
const { typeaheadIndex, suggestions } = this.state; const { typeaheadIndex, suggestions } = this.state;
@ -147,6 +146,7 @@ class QueryField extends React.Component<any, any> {
break; break;
} }
case 'Tab':
case 'Enter': { case 'Enter': {
if (this.menuEl) { if (this.menuEl) {
// Dont blur input // Dont blur input
@ -191,13 +191,15 @@ class QueryField extends React.Component<any, any> {
} }
} }
return undefined; return undefined;
} };
onTypeahead = (change?, item?) => { onTypeahead = (change?, item?) => {
return change || this.state.value.change(); return change || this.state.value.change();
} };
applyTypeahead(change?, suggestion?): { value: object } { return { value: {} }; } applyTypeahead(change?, suggestion?): { value: object } {
return { value: {} };
}
resetTypeahead = () => { resetTypeahead = () => {
this.setState({ this.setState({
@ -206,7 +208,7 @@ class QueryField extends React.Component<any, any> {
typeaheadPrefix: '', typeaheadPrefix: '',
typeaheadContext: null, typeaheadContext: null,
}); });
} };
handleBlur = () => { handleBlur = () => {
const { onBlur } = this.props; const { onBlur } = this.props;
@ -216,14 +218,14 @@ class QueryField extends React.Component<any, any> {
if (onBlur) { if (onBlur) {
onBlur(); onBlur();
} }
} };
handleFocus = () => { handleFocus = () => {
const { onFocus } = this.props; const { onFocus } = this.props;
if (onFocus) { if (onFocus) {
onFocus(); onFocus();
} }
} };
onClickItem = item => { onClickItem = item => {
const { suggestions } = this.state; const { suggestions } = this.state;
@ -241,7 +243,7 @@ class QueryField extends React.Component<any, any> {
// Manually triggering change // Manually triggering change
const change = this.applyTypeahead(this.state.value.change(), suggestion); const change = this.applyTypeahead(this.state.value.change(), suggestion);
this.onChange(change); this.onChange(change);
} };
updateMenu = () => { updateMenu = () => {
const { suggestions } = this.state; const { suggestions } = this.state;
@ -275,11 +277,11 @@ class QueryField extends React.Component<any, any> {
menu.style.left = `${rect.left + scrollX - 2}px`; menu.style.left = `${rect.left + scrollX - 2}px`;
}); });
} }
} };
menuRef = el => { menuRef = el => {
this.menuEl = el; this.menuEl = el;
} };
renderMenu = () => { renderMenu = () => {
const { portalPrefix } = this.props; const { portalPrefix } = this.props;
@ -308,7 +310,7 @@ class QueryField extends React.Component<any, any> {
/> />
</Portal> </Portal>
); );
} };
render() { render() {
return ( return (