mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 17:59:23 -04:00
Console cleanup (#19654)
* refactoring to class style and moving components to own files * making top level components fetch sensitive to HTTP verb * fixing issue with _ endpoints getting mistaken as index names for autocomplete possibilities:wq: * removing stray console log * removing console log * PR feedback * accounting for _all in isNotAnIndexName
This commit is contained in:
parent
aba92631a3
commit
831b9f83fd
28 changed files with 1191 additions and 908 deletions
|
@ -25,7 +25,7 @@ import {
|
|||
} from './kb';
|
||||
import utils from './utils';
|
||||
import { populateContext } from './autocomplete/engine';
|
||||
import { URL_PATH_END_MARKER } from './autocomplete/url_pattern_matcher';
|
||||
import { URL_PATH_END_MARKER } from './autocomplete/components';
|
||||
import _ from 'lodash';
|
||||
import ace from 'brace';
|
||||
import 'brace/ext/language_tools';
|
||||
|
@ -529,7 +529,10 @@ export default function (editor) {
|
|||
context.token = ret.token;
|
||||
context.otherTokenValues = ret.otherTokenValues;
|
||||
context.urlTokenPath = ret.urlTokenPath;
|
||||
populateContext(ret.urlTokenPath, context, editor, true, getTopLevelUrlCompleteComponents());
|
||||
const components = getTopLevelUrlCompleteComponents(context.method);
|
||||
populateContext(ret.urlTokenPath, context, editor, true, components);
|
||||
|
||||
|
||||
context.autoCompleteSet = addMetaToTermsList(context.autoCompleteSet, 'endpoint');
|
||||
}
|
||||
|
||||
|
@ -544,7 +547,7 @@ export default function (editor) {
|
|||
return context;
|
||||
}
|
||||
|
||||
populateContext(ret.urlTokenPath, context, editor, false, getTopLevelUrlCompleteComponents());
|
||||
populateContext(ret.urlTokenPath, context, editor, false, getTopLevelUrlCompleteComponents(context.method));
|
||||
|
||||
if (!context.endpoint) {
|
||||
console.log('couldn\'t resolve an endpoint.');
|
||||
|
@ -563,7 +566,7 @@ export default function (editor) {
|
|||
}
|
||||
|
||||
populateContext(tokenPath, context, editor, true,
|
||||
context.endpoint.paramsAutocomplete.getTopLevelComponents());
|
||||
context.endpoint.paramsAutocomplete.getTopLevelComponents(context.method));
|
||||
return context;
|
||||
}
|
||||
|
||||
|
@ -579,7 +582,7 @@ export default function (editor) {
|
|||
return context;
|
||||
}
|
||||
|
||||
populateContext(ret.urlTokenPath, context, editor, false, getTopLevelUrlCompleteComponents());
|
||||
populateContext(ret.urlTokenPath, context, editor, false, getTopLevelUrlCompleteComponents(context.method));
|
||||
|
||||
context.bodyTokenPath = ret.bodyTokenPath;
|
||||
if (!ret.bodyTokenPath) { // zero length tokenPath is true
|
||||
|
@ -741,6 +744,10 @@ export default function (editor) {
|
|||
if (t.type === 'url.part' || t.type === 'url.param' || t.type === 'url.value') {
|
||||
// we are on the same line as cursor and dealing with a url. Current token is not part of the context
|
||||
t = tokenIter.stepBackward();
|
||||
// This will force method parsing
|
||||
while (t.type === 'whitespace') {
|
||||
t = tokenIter.stepBackward();
|
||||
}
|
||||
}
|
||||
bodyTokenPath = null; // no not on a body line.
|
||||
}
|
||||
|
|
|
@ -18,225 +18,20 @@
|
|||
*/
|
||||
|
||||
const _ = require('lodash');
|
||||
const engine = require('./engine');
|
||||
import { WalkingState, walkTokenPath, wrapComponentWithDefaults } from './engine';
|
||||
import {
|
||||
ConstantComponent,
|
||||
SharedComponent,
|
||||
ObjectComponent,
|
||||
ConditionalProxy,
|
||||
GlobalOnlyComponent,
|
||||
} from './components';
|
||||
|
||||
function CompilingContext(endpointId, parametrizedComponentFactories) {
|
||||
this.parametrizedComponentFactories = parametrizedComponentFactories;
|
||||
this.endpointId = endpointId;
|
||||
}
|
||||
|
||||
function getTemplate(description) {
|
||||
if (description.__template) {
|
||||
return description.__template;
|
||||
}
|
||||
else if (description.__one_of) {
|
||||
return getTemplate(description.__one_of[0]);
|
||||
}
|
||||
else if (description.__any_of) {
|
||||
return [];
|
||||
}
|
||||
else if (description.__scope_link) {
|
||||
// assume an object for now.
|
||||
return {};
|
||||
}
|
||||
else if (Array.isArray(description)) {
|
||||
if (description.length === 1) {
|
||||
if (_.isObject(description[0])) {
|
||||
// shortcut to save typing
|
||||
const innerTemplate = getTemplate(description[0]);
|
||||
|
||||
return innerTemplate != null ? [innerTemplate] : [];
|
||||
}
|
||||
}
|
||||
return [];
|
||||
}
|
||||
else if (_.isObject(description)) {
|
||||
return {};
|
||||
}
|
||||
else if (_.isString(description) && !/^\{.*\}$/.test(description)) {
|
||||
return description;
|
||||
}
|
||||
else {
|
||||
return description;
|
||||
}
|
||||
}
|
||||
|
||||
function getOptions(description) {
|
||||
const options = {};
|
||||
const template = getTemplate(description);
|
||||
|
||||
if (!_.isUndefined(template)) {
|
||||
options.template = template;
|
||||
}
|
||||
return options;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param description a json dict describing the endpoint
|
||||
* @param compilingContext
|
||||
*/
|
||||
function compileDescription(description, compilingContext) {
|
||||
if (Array.isArray(description)) {
|
||||
return [compileList(description, compilingContext)];
|
||||
}
|
||||
else if (_.isObject(description)) {
|
||||
// test for objects list as arrays are also objects
|
||||
if (description.__scope_link) {
|
||||
return [new ScopeResolver(description.__scope_link, compilingContext)];
|
||||
}
|
||||
if (description.__any_of) {
|
||||
return [compileList(description.__any_of, compilingContext)];
|
||||
}
|
||||
if (description.__one_of) {
|
||||
return _.flatten(_.map(description.__one_of, function (d) {
|
||||
return compileDescription(d, compilingContext);
|
||||
}));
|
||||
}
|
||||
const obj = compileObject(description, compilingContext);
|
||||
if (description.__condition) {
|
||||
return [compileCondition(description.__condition, obj, compilingContext)];
|
||||
} else {
|
||||
return [obj];
|
||||
}
|
||||
}
|
||||
else if (_.isString(description) && /^\{.*\}$/.test(description)) {
|
||||
return [compileParametrizedValue(description, compilingContext)];
|
||||
}
|
||||
else {
|
||||
return [new engine.ConstantComponent(description)];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function compileParametrizedValue(value, compilingContext, template) {
|
||||
value = value.substr(1, value.length - 2).toLowerCase();
|
||||
let component = compilingContext.parametrizedComponentFactories[value];
|
||||
if (!component) {
|
||||
throw new Error('no factory found for \'' + value + '\'');
|
||||
}
|
||||
component = component(value, null, template);
|
||||
if (!_.isUndefined(template)) {
|
||||
component = engine.wrapComponentWithDefaults(component, { template: template });
|
||||
}
|
||||
return component;
|
||||
|
||||
}
|
||||
|
||||
function compileObject(objDescription, compilingContext) {
|
||||
const objectC = new engine.ConstantComponent('{');
|
||||
const constants = [];
|
||||
const patterns = [];
|
||||
_.each(objDescription, function (desc, key) {
|
||||
if (key.indexOf('__') === 0) {
|
||||
// meta key
|
||||
return;
|
||||
}
|
||||
|
||||
const options = getOptions(desc);
|
||||
let component;
|
||||
if (/^\{.*\}$/.test(key)) {
|
||||
component = compileParametrizedValue(key, compilingContext, options.template);
|
||||
patterns.push(component);
|
||||
}
|
||||
else if (key === '*') {
|
||||
component = new engine.SharedComponent(key);
|
||||
patterns.push(component);
|
||||
}
|
||||
else {
|
||||
options.name = key;
|
||||
component = new engine.ConstantComponent(key, null, [options]);
|
||||
constants.push(component);
|
||||
}
|
||||
_.map(compileDescription(desc, compilingContext), function (subComponent) {
|
||||
component.addComponent(subComponent);
|
||||
});
|
||||
});
|
||||
objectC.addComponent(new ObjectComponent('inner', constants, patterns));
|
||||
return objectC;
|
||||
}
|
||||
|
||||
function compileList(listRule, compilingContext) {
|
||||
const listC = new engine.ConstantComponent('[');
|
||||
_.each(listRule, function (desc) {
|
||||
_.each(compileDescription(desc, compilingContext), function (component) {
|
||||
listC.addComponent(component);
|
||||
});
|
||||
});
|
||||
return listC;
|
||||
}
|
||||
|
||||
/** takes a compiled object and wraps in a {@link ConditionalProxy }*/
|
||||
function compileCondition(description, compiledObject) {
|
||||
if (description.lines_regex) {
|
||||
return new ConditionalProxy(function (context, editor) {
|
||||
const lines = editor.getSession().getLines(context.requestStartRow, editor.getCursorPosition().row).join('\n');
|
||||
return new RegExp(description.lines_regex, 'm').test(lines);
|
||||
}, compiledObject);
|
||||
} else {
|
||||
throw 'unknown condition type - got: ' + JSON.stringify(description);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param constants list of components that represent constant keys
|
||||
* @param patternsAndWildCards list of components that represent patterns and should be matched only if
|
||||
* there is no constant matches
|
||||
*/
|
||||
function ObjectComponent(name, constants, patternsAndWildCards) {
|
||||
engine.AutocompleteComponent.call(this, name);
|
||||
this.constants = constants;
|
||||
this.patternsAndWildCards = patternsAndWildCards;
|
||||
}
|
||||
|
||||
ObjectComponent.prototype = _.create(
|
||||
engine.AutocompleteComponent.prototype,
|
||||
{ 'constructor': ObjectComponent });
|
||||
|
||||
|
||||
(function (cls) {
|
||||
cls.getTerms = function (context, editor) {
|
||||
const options = [];
|
||||
_.each(this.constants, function (component) {
|
||||
options.push.apply(options, component.getTerms(context, editor));
|
||||
});
|
||||
_.each(this.patternsAndWildCards, function (component) {
|
||||
options.push.apply(options, component.getTerms(context, editor));
|
||||
});
|
||||
return options;
|
||||
};
|
||||
|
||||
cls.match = function (token, context, editor) {
|
||||
const result = {
|
||||
next: []
|
||||
};
|
||||
_.each(this.constants, function (component) {
|
||||
const componentResult = component.match(token, context, editor);
|
||||
if (componentResult && componentResult.next) {
|
||||
result.next.push.apply(result.next, componentResult.next);
|
||||
}
|
||||
});
|
||||
|
||||
// try to link to GLOBAL rules
|
||||
const globalRules = context.globalComponentResolver(token, false);
|
||||
if (globalRules) {
|
||||
result.next.push.apply(result.next, globalRules);
|
||||
}
|
||||
|
||||
if (result.next.length) {
|
||||
return result;
|
||||
}
|
||||
_.each(this.patternsAndWildCards, function (component) {
|
||||
const componentResult = component.match(token, context, editor);
|
||||
if (componentResult && componentResult.next) {
|
||||
result.next.push.apply(result.next, componentResult.next);
|
||||
}
|
||||
});
|
||||
|
||||
return result;
|
||||
|
||||
};
|
||||
}(ObjectComponent.prototype));
|
||||
|
||||
/**
|
||||
* An object to resolve scope links (syntax endpoint.path1.path2)
|
||||
* @param link the link either string (endpoint.path1.path2, or .path1.path2) or a function (context,editor)
|
||||
|
@ -248,29 +43,31 @@ ObjectComponent.prototype = _.create(
|
|||
* For this to work we expect the context to include a method context.endpointComponentResolver(endpoint)
|
||||
* which should return the top level components for the given endpoint
|
||||
*/
|
||||
function ScopeResolver(link, compilingContext) {
|
||||
engine.SharedComponent.call(this, '__scope_link', null);
|
||||
if (_.isString(link) && link[0] === '.') {
|
||||
// relative link, inject current endpoint
|
||||
if (link === '.') {
|
||||
link = compilingContext.endpointId;
|
||||
}
|
||||
else {
|
||||
link = compilingContext.endpointId + link;
|
||||
}
|
||||
}
|
||||
this.link = link;
|
||||
this.compilingContext = compilingContext;
|
||||
|
||||
|
||||
function resolvePathToComponents(tokenPath, context, editor, components) {
|
||||
const walkStates = walkTokenPath(tokenPath, [new WalkingState('ROOT', components, [])], context, editor);
|
||||
const result = [].concat.apply([], _.pluck(walkStates, 'components'));
|
||||
return result;
|
||||
}
|
||||
|
||||
ScopeResolver.prototype = _.create(
|
||||
engine.SharedComponent.prototype,
|
||||
{ 'constructor': ScopeResolver });
|
||||
class ScopeResolver extends SharedComponent {
|
||||
constructor(link, compilingContext) {
|
||||
super('__scope_link');
|
||||
if (_.isString(link) && link[0] === '.') {
|
||||
// relative link, inject current endpoint
|
||||
if (link === '.') {
|
||||
link = compilingContext.endpointId;
|
||||
}
|
||||
else {
|
||||
link = compilingContext.endpointId + link;
|
||||
}
|
||||
}
|
||||
this.link = link;
|
||||
this.compilingContext = compilingContext;
|
||||
}
|
||||
|
||||
|
||||
(function (cls) {
|
||||
|
||||
cls.resolveLinkToComponents = function (context, editor) {
|
||||
resolveLinkToComponents(context, editor) {
|
||||
if (_.isFunction(this.link)) {
|
||||
const desc = this.link(context, editor);
|
||||
return compileDescription(desc, this.compilingContext);
|
||||
|
@ -300,19 +97,19 @@ ScopeResolver.prototype = _.create(
|
|||
catch (e) {
|
||||
throw new Error('failed to resolve link [' + this.link + ']: ' + e);
|
||||
}
|
||||
return engine.resolvePathToComponents(path, context, editor, components);
|
||||
};
|
||||
return resolvePathToComponents(path, context, editor, components);
|
||||
}
|
||||
|
||||
cls.getTerms = function (context, editor) {
|
||||
getTerms(context, editor) {
|
||||
const options = [];
|
||||
const components = this.resolveLinkToComponents(context, editor);
|
||||
_.each(components, function (component) {
|
||||
options.push.apply(options, component.getTerms(context, editor));
|
||||
});
|
||||
return options;
|
||||
};
|
||||
}
|
||||
|
||||
cls.match = function (token, context, editor) {
|
||||
match(token, context, editor) {
|
||||
const result = {
|
||||
next: []
|
||||
};
|
||||
|
@ -326,78 +123,154 @@ ScopeResolver.prototype = _.create(
|
|||
});
|
||||
|
||||
return result;
|
||||
};
|
||||
}(ScopeResolver.prototype));
|
||||
}
|
||||
}
|
||||
function getTemplate(description) {
|
||||
if (description.__template) {
|
||||
return description.__template;
|
||||
} else if (description.__one_of) {
|
||||
return getTemplate(description.__one_of[0]);
|
||||
} else if (description.__any_of) {
|
||||
return [];
|
||||
} else if (description.__scope_link) {
|
||||
// assume an object for now.
|
||||
return {};
|
||||
} else if (Array.isArray(description)) {
|
||||
if (description.length === 1) {
|
||||
if (_.isObject(description[0])) {
|
||||
// shortcut to save typing
|
||||
const innerTemplate = getTemplate(description[0]);
|
||||
|
||||
|
||||
function ConditionalProxy(predicate, delegate) {
|
||||
engine.SharedComponent.call(this, '__condition', null);
|
||||
this.predicate = predicate;
|
||||
this.delegate = delegate;
|
||||
return innerTemplate != null ? [innerTemplate] : [];
|
||||
}
|
||||
}
|
||||
return [];
|
||||
} else if (_.isObject(description)) {
|
||||
return {};
|
||||
} else if (_.isString(description) && !/^\{.*\}$/.test(description)) {
|
||||
return description;
|
||||
} else {
|
||||
return description;
|
||||
}
|
||||
}
|
||||
|
||||
ConditionalProxy.prototype = _.create(
|
||||
engine.SharedComponent.prototype,
|
||||
{ 'constructor': ConditionalProxy });
|
||||
function getOptions(description) {
|
||||
const options = {};
|
||||
const template = getTemplate(description);
|
||||
|
||||
|
||||
(function (cls) {
|
||||
|
||||
cls.getTerms = function (context, editor) {
|
||||
if (this.predicate(context, editor)) {
|
||||
return this.delegate.getTerms(context, editor);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
cls.match = function (token, context, editor) {
|
||||
if (this.predicate(context, editor)) {
|
||||
return this.delegate.match(token, context, editor);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
}(ConditionalProxy.prototype));
|
||||
|
||||
|
||||
function GlobalOnlyComponent(name) {
|
||||
engine.AutocompleteComponent.call(this, name);
|
||||
if (!_.isUndefined(template)) {
|
||||
options.template = template;
|
||||
}
|
||||
return options;
|
||||
}
|
||||
|
||||
GlobalOnlyComponent.prototype = _.create(
|
||||
engine.AutocompleteComponent.prototype,
|
||||
{ 'constructor': ObjectComponent });
|
||||
/**
|
||||
* @param description a json dict describing the endpoint
|
||||
* @param compilingContext
|
||||
*/
|
||||
function compileDescription(description, compilingContext) {
|
||||
if (Array.isArray(description)) {
|
||||
return [compileList(description, compilingContext)];
|
||||
} else if (_.isObject(description)) {
|
||||
// test for objects list as arrays are also objects
|
||||
if (description.__scope_link) {
|
||||
return [new ScopeResolver(description.__scope_link, compilingContext)];
|
||||
}
|
||||
if (description.__any_of) {
|
||||
return [compileList(description.__any_of, compilingContext)];
|
||||
}
|
||||
if (description.__one_of) {
|
||||
return _.flatten(
|
||||
_.map(description.__one_of, function (d) {
|
||||
return compileDescription(d, compilingContext);
|
||||
})
|
||||
);
|
||||
}
|
||||
const obj = compileObject(description, compilingContext);
|
||||
if (description.__condition) {
|
||||
return [compileCondition(description.__condition, obj, compilingContext)];
|
||||
} else {
|
||||
return [obj];
|
||||
}
|
||||
} else if (_.isString(description) && /^\{.*\}$/.test(description)) {
|
||||
return [compileParametrizedValue(description, compilingContext)];
|
||||
} else {
|
||||
return [new ConstantComponent(description)];
|
||||
}
|
||||
}
|
||||
|
||||
function compileParametrizedValue(value, compilingContext, template) {
|
||||
value = value.substr(1, value.length - 2).toLowerCase();
|
||||
let component = compilingContext.parametrizedComponentFactories[value];
|
||||
if (!component) {
|
||||
throw new Error('no factory found for \'' + value + '\'');
|
||||
}
|
||||
component = component(value, null, template);
|
||||
if (!_.isUndefined(template)) {
|
||||
component = wrapComponentWithDefaults(component, { template: template });
|
||||
}
|
||||
return component;
|
||||
}
|
||||
|
||||
(function (cls) {
|
||||
|
||||
cls.getTerms = function () {
|
||||
return null;
|
||||
};
|
||||
|
||||
cls.match = function (token, context) {
|
||||
const result = {
|
||||
next: []
|
||||
};
|
||||
|
||||
// try to link to GLOBAL rules
|
||||
const globalRules = context.globalComponentResolver(token, false);
|
||||
if (globalRules) {
|
||||
result.next.push.apply(result.next, globalRules);
|
||||
function compileObject(objDescription, compilingContext) {
|
||||
const objectC = new ConstantComponent('{');
|
||||
const constants = [];
|
||||
const patterns = [];
|
||||
_.each(objDescription, function (desc, key) {
|
||||
if (key.indexOf('__') === 0) {
|
||||
// meta key
|
||||
return;
|
||||
}
|
||||
|
||||
if (result.next.length) {
|
||||
return result;
|
||||
const options = getOptions(desc);
|
||||
let component;
|
||||
if (/^\{.*\}$/.test(key)) {
|
||||
component = compileParametrizedValue(
|
||||
key,
|
||||
compilingContext,
|
||||
options.template
|
||||
);
|
||||
patterns.push(component);
|
||||
} else if (key === '*') {
|
||||
component = new SharedComponent(key);
|
||||
patterns.push(component);
|
||||
} else {
|
||||
options.name = key;
|
||||
component = new ConstantComponent(key, null, [options]);
|
||||
constants.push(component);
|
||||
}
|
||||
// just loop back to us
|
||||
result.next = [this];
|
||||
_.map(compileDescription(desc, compilingContext), function (subComponent) {
|
||||
component.addComponent(subComponent);
|
||||
});
|
||||
});
|
||||
objectC.addComponent(new ObjectComponent('inner', constants, patterns));
|
||||
return objectC;
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
};
|
||||
}(GlobalOnlyComponent.prototype));
|
||||
function compileList(listRule, compilingContext) {
|
||||
const listC = new ConstantComponent('[');
|
||||
_.each(listRule, function (desc) {
|
||||
_.each(compileDescription(desc, compilingContext), function (component) {
|
||||
listC.addComponent(component);
|
||||
});
|
||||
});
|
||||
return listC;
|
||||
}
|
||||
|
||||
/** takes a compiled object and wraps in a {@link ConditionalProxy }*/
|
||||
function compileCondition(description, compiledObject) {
|
||||
if (description.lines_regex) {
|
||||
return new ConditionalProxy(function (context, editor) {
|
||||
const lines = editor
|
||||
.getSession()
|
||||
.getLines(context.requestStartRow, editor.getCursorPosition().row)
|
||||
.join('\n');
|
||||
return new RegExp(description.lines_regex, 'm').test(lines);
|
||||
}, compiledObject);
|
||||
} else {
|
||||
throw 'unknown condition type - got: ' + JSON.stringify(description);
|
||||
}
|
||||
}
|
||||
|
||||
// a list of component that match anything but give auto complete suggestions based on global API entries.
|
||||
export function globalsOnlyAutocompleteComponents() {
|
||||
|
@ -412,11 +285,18 @@ export function globalsOnlyAutocompleteComponents() {
|
|||
* @param parametrizedComponentFactories a dict of the following structure
|
||||
* that will be used as a fall back for pattern keys (i.e.: {type} ,resolved without the $s)
|
||||
* {
|
||||
* TYPE: function (part, parent, endpoint) {
|
||||
* return new SharedComponent(part, parent)
|
||||
* }
|
||||
* }
|
||||
* TYPE: function (part, parent, endpoint) {
|
||||
* return new SharedComponent(part, parent)
|
||||
* }
|
||||
* }
|
||||
*/
|
||||
export function compileBodyDescription(endpointId, description, parametrizedComponentFactories) {
|
||||
return compileDescription(description, new CompilingContext(endpointId, parametrizedComponentFactories));
|
||||
export function compileBodyDescription(
|
||||
endpointId,
|
||||
description,
|
||||
parametrizedComponentFactories
|
||||
) {
|
||||
return compileDescription(
|
||||
description,
|
||||
new CompilingContext(endpointId, parametrizedComponentFactories)
|
||||
);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import _ from 'lodash';
|
||||
import { SharedComponent } from './shared_component';
|
||||
export const URL_PATH_END_MARKER = '__url_path_end__';
|
||||
|
||||
export class AcceptEndpointComponent extends SharedComponent {
|
||||
constructor(endpoint, parent) {
|
||||
super(endpoint.id, parent);
|
||||
this.endpoint = endpoint;
|
||||
}
|
||||
match(token, context, editor) {
|
||||
if (token !== URL_PATH_END_MARKER) {
|
||||
return null;
|
||||
}
|
||||
if (this.endpoint.methods && -1 === _.indexOf(this.endpoint.methods, context.method)) {
|
||||
return null;
|
||||
}
|
||||
const r = super.match(token, context, editor);
|
||||
r.context_values = r.context_values || {};
|
||||
r.context_values.endpoint = this.endpoint;
|
||||
if (_.isNumber(this.endpoint.priority)) {
|
||||
r.priority = this.endpoint.priority;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
export class AutocompleteComponent {
|
||||
constructor(name) {
|
||||
this.name = name;
|
||||
}
|
||||
/** called to get the possible suggestions for tokens, when this object is at the end of
|
||||
* the resolving chain (and thus can suggest possible continuation paths)
|
||||
*/
|
||||
getTerms() {
|
||||
return [];
|
||||
}
|
||||
/*
|
||||
if the current matcher matches this term, this method should return an object with the following keys
|
||||
{
|
||||
context_values: {
|
||||
values extract from term that should be added to the context
|
||||
}
|
||||
next: AutocompleteComponent(s) to use next
|
||||
priority: optional priority to solve collisions between multiple paths. Min value is used across entire chain
|
||||
}
|
||||
*/
|
||||
match() {
|
||||
return {
|
||||
next: this.next,
|
||||
};
|
||||
}
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import { SharedComponent } from './shared_component';
|
||||
export class ConditionalProxy extends SharedComponent {
|
||||
constructor(predicate, delegate) {
|
||||
super('__condition');
|
||||
this.predicate = predicate;
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
getTerms(context, editor) {
|
||||
if (this.predicate(context, editor)) {
|
||||
return this.delegate.getTerms(context, editor);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
match(token, context, editor) {
|
||||
if (this.predicate(context, editor)) {
|
||||
return this.delegate.match(token, context, editor);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import _ from 'lodash';
|
||||
import { SharedComponent } from './shared_component';
|
||||
export class ConstantComponent extends SharedComponent {
|
||||
constructor(name, parent, options) {
|
||||
super(name, parent);
|
||||
if (_.isString(options)) {
|
||||
options = [options];
|
||||
}
|
||||
this.options = options || [name];
|
||||
}
|
||||
getTerms() {
|
||||
return this.options;
|
||||
}
|
||||
|
||||
addOption(options) {
|
||||
if (!Array.isArray(options)) {
|
||||
options = [options];
|
||||
}
|
||||
|
||||
[].push.apply(this.options, options);
|
||||
this.options = _.uniq(this.options);
|
||||
}
|
||||
match(token, context, editor) {
|
||||
if (token !== this.name) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return super.match(token, context, editor);
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import _ from 'lodash';
|
||||
import mappings from '../../mappings';
|
||||
import { ListComponent } from './list_component';
|
||||
|
||||
function FieldGenerator(context) {
|
||||
return _.map(mappings.getFields(context.indices, context.types), function (field) {
|
||||
return { name: field.name, meta: field.type };
|
||||
});
|
||||
}
|
||||
|
||||
export class FieldAutocompleteComponent extends ListComponent {
|
||||
constructor(name, parent, multiValued) {
|
||||
super(name, FieldGenerator, parent, multiValued);
|
||||
}
|
||||
validateTokens(tokens) {
|
||||
if (!this.multiValued && tokens.length > 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return !_.find(tokens, function (token) {
|
||||
return token.match(/[^\w.?*]/);
|
||||
});
|
||||
}
|
||||
|
||||
getDefaultTermMeta() {
|
||||
return 'field';
|
||||
}
|
||||
|
||||
getContextKey() {
|
||||
return 'fields';
|
||||
}
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import { SharedComponent } from './shared_component';
|
||||
export class GlobalOnlyComponent extends SharedComponent {
|
||||
getTerms() {
|
||||
return null;
|
||||
}
|
||||
|
||||
match(token, context) {
|
||||
const result = {
|
||||
next: []
|
||||
};
|
||||
|
||||
// try to link to GLOBAL rules
|
||||
const globalRules = context.globalComponentResolver(token, false);
|
||||
if (globalRules) {
|
||||
result.next.push.apply(result.next, globalRules);
|
||||
}
|
||||
|
||||
if (result.next.length) {
|
||||
return result;
|
||||
}
|
||||
// just loop back to us
|
||||
result.next = [this];
|
||||
|
||||
return result;
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import _ from 'lodash';
|
||||
import { SharedComponent } from './shared_component';
|
||||
export class IdAutocompleteComponent extends SharedComponent {
|
||||
constructor(name, parent, multi) {
|
||||
super(name, parent);
|
||||
this.multi_match = multi;
|
||||
}
|
||||
match(token, context, editor) {
|
||||
if (!token) {
|
||||
return null;
|
||||
}
|
||||
if (!this.multi_match && Array.isArray(token)) {
|
||||
return null;
|
||||
}
|
||||
token = Array.isArray(token) ? token : [token];
|
||||
if (_.find(token, function (t) {
|
||||
return t.match(/[\/,]/);
|
||||
})) {
|
||||
return null;
|
||||
}
|
||||
const r = super.match(token, context, editor);
|
||||
r.context_values = r.context_values || {};
|
||||
r.context_values.id = token;
|
||||
return r;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
export { AutocompleteComponent } from './autocomplete_component';
|
||||
export { SharedComponent } from './shared_component';
|
||||
export { ConstantComponent } from './constant_component';
|
||||
export { ListComponent } from './list_component';
|
||||
export { SimpleParamComponent } from './simple_param_component';
|
||||
export { ConditionalProxy } from './conditional_proxy';
|
||||
export { GlobalOnlyComponent } from './global_only_component';
|
||||
export { ObjectComponent } from './object_component';
|
||||
export { AcceptEndpointComponent, URL_PATH_END_MARKER } from './accept_endpoint_component';
|
||||
export { UrlPatternMatcher } from './url_pattern_matcher';
|
||||
export { IndexAutocompleteComponent } from './index_autocomplete_component';
|
||||
export { FieldAutocompleteComponent } from './field_autocomplete_component';
|
||||
export { TypeAutocompleteComponent } from './type_autocomplete_component';
|
||||
export { IdAutocompleteComponent } from './id_autocomplete_component';
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import _ from 'lodash';
|
||||
import mappings from '../../mappings';
|
||||
import { ListComponent } from './list_component';
|
||||
function nonValidIndexType(token) {
|
||||
return !(token === '_all' || token[0] !== '_');
|
||||
}
|
||||
export class IndexAutocompleteComponent extends ListComponent {
|
||||
constructor(name, parent, multiValued) {
|
||||
super(name, mappings.getIndices, parent, multiValued);
|
||||
}
|
||||
validateTokens(tokens) {
|
||||
if (!this.multiValued && tokens.length > 1) {
|
||||
return false;
|
||||
}
|
||||
return !_.find(tokens, nonValidIndexType);
|
||||
}
|
||||
|
||||
getDefaultTermMeta() {
|
||||
return 'index';
|
||||
}
|
||||
|
||||
getContextKey() {
|
||||
return 'indices';
|
||||
}
|
||||
}
|
|
@ -0,0 +1,94 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import _ from 'lodash';
|
||||
import { SharedComponent } from './shared_component';
|
||||
/** A component that suggests one of the give options, but accepts anything */
|
||||
export class ListComponent extends SharedComponent {
|
||||
constructor(name, list, parent, multiValued, allowNonValidValues) {
|
||||
super(name, parent);
|
||||
this.listGenerator = Array.isArray(list) ? function () {
|
||||
return list;
|
||||
} : list;
|
||||
this.multiValued = _.isUndefined(multiValued) ? true : multiValued;
|
||||
this.allowNonValidValues = _.isUndefined(allowNonValidValues) ? false : allowNonValidValues;
|
||||
}
|
||||
getTerms(context, editor) {
|
||||
if (!this.multiValued && context.otherTokenValues) {
|
||||
// already have a value -> no suggestions
|
||||
return [];
|
||||
}
|
||||
let alreadySet = context.otherTokenValues || [];
|
||||
if (_.isString(alreadySet)) {
|
||||
alreadySet = [alreadySet];
|
||||
}
|
||||
let ret = _.difference(this.listGenerator(context, editor), alreadySet);
|
||||
|
||||
if (this.getDefaultTermMeta()) {
|
||||
const meta = this.getDefaultTermMeta();
|
||||
ret = _.map(ret, function (term) {
|
||||
if (_.isString(term)) {
|
||||
term = { 'name': term };
|
||||
}
|
||||
return _.defaults(term, { meta: meta });
|
||||
});
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
validateTokens(tokens) {
|
||||
if (!this.multiValued && tokens.length > 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// verify we have all tokens
|
||||
const list = this.listGenerator();
|
||||
const notFound = _.any(tokens, function (token) {
|
||||
return list.indexOf(token) === -1;
|
||||
});
|
||||
|
||||
if (notFound) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
getContextKey() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
getDefaultTermMeta() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
match(token, context, editor) {
|
||||
if (!Array.isArray(token)) {
|
||||
token = [token];
|
||||
}
|
||||
if (!this.allowNonValidValues && !this.validateTokens(token, context, editor)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const result = super.match(token, context, editor);
|
||||
result.context_values = result.context_values || {};
|
||||
result.context_values[this.getContextKey()] = token;
|
||||
return result;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import _ from 'lodash';
|
||||
import { SharedComponent } from '.';
|
||||
/**
|
||||
* @param constants list of components that represent constant keys
|
||||
* @param patternsAndWildCards list of components that represent patterns and should be matched only if
|
||||
* there is no constant matches
|
||||
*/
|
||||
export class ObjectComponent extends SharedComponent {
|
||||
constructor(name, constants, patternsAndWildCards) {
|
||||
super(name);
|
||||
this.constants = constants;
|
||||
this.patternsAndWildCards = patternsAndWildCards;
|
||||
}
|
||||
getTerms(context, editor) {
|
||||
const options = [];
|
||||
_.each(this.constants, function (component) {
|
||||
options.push.apply(options, component.getTerms(context, editor));
|
||||
});
|
||||
_.each(this.patternsAndWildCards, function (component) {
|
||||
options.push.apply(options, component.getTerms(context, editor));
|
||||
});
|
||||
return options;
|
||||
}
|
||||
|
||||
match(token, context, editor) {
|
||||
const result = {
|
||||
next: []
|
||||
};
|
||||
_.each(this.constants, function (component) {
|
||||
const componentResult = component.match(token, context, editor);
|
||||
if (componentResult && componentResult.next) {
|
||||
result.next.push.apply(result.next, componentResult.next);
|
||||
}
|
||||
});
|
||||
|
||||
// try to link to GLOBAL rules
|
||||
const globalRules = context.globalComponentResolver(token, false);
|
||||
if (globalRules) {
|
||||
result.next.push.apply(result.next, globalRules);
|
||||
}
|
||||
|
||||
if (result.next.length) {
|
||||
return result;
|
||||
}
|
||||
_.each(this.patternsAndWildCards, function (component) {
|
||||
const componentResult = component.match(token, context, editor);
|
||||
if (componentResult && componentResult.next) {
|
||||
result.next.push.apply(result.next, componentResult.next);
|
||||
}
|
||||
});
|
||||
|
||||
return result;
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import _ from 'lodash';
|
||||
import { AutocompleteComponent } from './autocomplete_component';
|
||||
export class SharedComponent extends AutocompleteComponent {
|
||||
constructor(name, parent) {
|
||||
super(name);
|
||||
this._nextDict = {};
|
||||
if (parent) {
|
||||
parent.addComponent(this);
|
||||
}
|
||||
// for debugging purposes
|
||||
this._parent = parent;
|
||||
}
|
||||
/* return the first component with a given name */
|
||||
getComponent(name) {
|
||||
return (this._nextDict[name] || [undefined])[0];
|
||||
}
|
||||
|
||||
addComponent(component) {
|
||||
const current = this._nextDict[component.name] || [];
|
||||
current.push(component);
|
||||
this._nextDict[component.name] = current;
|
||||
this.next = [].concat.apply([], _.values(this._nextDict));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import { SharedComponent } from './shared_component';
|
||||
export class SimpleParamComponent extends SharedComponent {
|
||||
constructor(name, parent) {
|
||||
super(name, parent);
|
||||
}
|
||||
match(token, context, editor) {
|
||||
const result = super.match(token, context, editor);
|
||||
result.context_values = result.context_values || {};
|
||||
result.context_values[this.name] = token;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import _ from 'lodash';
|
||||
import { ListComponent } from './list_component';
|
||||
import mappings from '../../mappings';
|
||||
function TypeGenerator(context) {
|
||||
return mappings.getTypes(context.indices);
|
||||
}
|
||||
function nonValidIndexType(token) {
|
||||
return !(token === '_all' || token[0] !== '_');
|
||||
}
|
||||
export class TypeAutocompleteComponent extends ListComponent {
|
||||
constructor(name, parent, multiValued) {
|
||||
super(name, TypeGenerator, parent, multiValued);
|
||||
}
|
||||
validateTokens(tokens) {
|
||||
if (!this.multiValued && tokens.length > 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return !_.find(tokens, nonValidIndexType);
|
||||
}
|
||||
|
||||
getDefaultTermMeta() {
|
||||
return 'type';
|
||||
}
|
||||
|
||||
getContextKey() {
|
||||
return 'types';
|
||||
}
|
||||
}
|
|
@ -0,0 +1,136 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import _ from 'lodash';
|
||||
import {
|
||||
SharedComponent,
|
||||
ConstantComponent,
|
||||
AcceptEndpointComponent,
|
||||
ListComponent,
|
||||
SimpleParamComponent,
|
||||
} from '.';
|
||||
|
||||
/**
|
||||
* @param parametrizedComponentFactories a dict of the following structure
|
||||
* that will be used as a fall back for pattern parameters (i.e.: {indices})
|
||||
* {
|
||||
* indices: function (part, parent) {
|
||||
* return new SharedComponent(part, parent)
|
||||
* }
|
||||
* }
|
||||
* @constructor
|
||||
*/
|
||||
export class UrlPatternMatcher {
|
||||
// This is not really a component, just a handy container to make iteration logic simpler
|
||||
constructor(parametrizedComponentFactories) {
|
||||
// We'll group endpoints by the methods which are attached to them,
|
||||
//to avoid suggesting endpoints that are incompatible with the
|
||||
//method that the user has entered.
|
||||
['HEAD', 'GET', 'PUT', 'POST', 'DELETE'].forEach((method) => {
|
||||
this[method] = {
|
||||
rootComponent: new SharedComponent('ROOT'),
|
||||
parametrizedComponentFactories: parametrizedComponentFactories || {}
|
||||
};
|
||||
});
|
||||
}
|
||||
addEndpoint(pattern, endpoint) {
|
||||
endpoint.methods.forEach((method) => {
|
||||
let c;
|
||||
let activeComponent = this[method].rootComponent;
|
||||
const endpointComponents = endpoint.url_components || {};
|
||||
const partList = pattern.split('/');
|
||||
_.each(
|
||||
partList,
|
||||
function (part, partIndex) {
|
||||
if (part.search(/^{.+}$/) >= 0) {
|
||||
part = part.substr(1, part.length - 2);
|
||||
if (activeComponent.getComponent(part)) {
|
||||
// we already have something for this, reuse
|
||||
activeComponent = activeComponent.getComponent(part);
|
||||
return;
|
||||
}
|
||||
// a new path, resolve.
|
||||
|
||||
if ((c = endpointComponents[part])) {
|
||||
// endpoint specific. Support list
|
||||
if (Array.isArray(c)) {
|
||||
c = new ListComponent(part, c, activeComponent);
|
||||
} else if (_.isObject(c) && c.type === 'list') {
|
||||
c = new ListComponent(
|
||||
part,
|
||||
c.list,
|
||||
activeComponent,
|
||||
c.multiValued,
|
||||
c.allow_non_valid
|
||||
);
|
||||
} else {
|
||||
console.warn(
|
||||
'incorrectly configured url component ',
|
||||
part,
|
||||
' in endpoint',
|
||||
endpoint
|
||||
);
|
||||
c = new SharedComponent(part);
|
||||
}
|
||||
} else if ((c = this[method].parametrizedComponentFactories[part])) {
|
||||
// c is a f
|
||||
c = c(part, activeComponent);
|
||||
} else {
|
||||
// just accept whatever with not suggestions
|
||||
c = new SimpleParamComponent(part, activeComponent);
|
||||
}
|
||||
|
||||
activeComponent = c;
|
||||
} else {
|
||||
// not pattern
|
||||
let lookAhead = part;
|
||||
let s;
|
||||
|
||||
for (partIndex++; partIndex < partList.length; partIndex++) {
|
||||
s = partList[partIndex];
|
||||
if (s.indexOf('{') >= 0) {
|
||||
break;
|
||||
}
|
||||
lookAhead += '/' + s;
|
||||
}
|
||||
|
||||
if (activeComponent.getComponent(part)) {
|
||||
// we already have something for this, reuse
|
||||
activeComponent = activeComponent.getComponent(part);
|
||||
activeComponent.addOption(lookAhead);
|
||||
} else {
|
||||
c = new ConstantComponent(part, activeComponent, lookAhead);
|
||||
activeComponent = c;
|
||||
}
|
||||
}
|
||||
},
|
||||
this
|
||||
);
|
||||
// mark end of endpoint path
|
||||
new AcceptEndpointComponent(endpoint, activeComponent);
|
||||
});
|
||||
}
|
||||
|
||||
getTopLevelComponents = function (method) {
|
||||
const methodRoot = this[method];
|
||||
if (!methodRoot) {
|
||||
return [];
|
||||
}
|
||||
return methodRoot.rootComponent.next;
|
||||
};
|
||||
}
|
|
@ -19,205 +19,10 @@
|
|||
|
||||
const _ = require('lodash');
|
||||
|
||||
export function AutocompleteComponent(name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/** called to get the possible suggestions for tokens, when this object is at the end of
|
||||
* the resolving chain (and thus can suggest possible continuation paths)
|
||||
*/
|
||||
AutocompleteComponent.prototype.getTerms = function () {
|
||||
return [];
|
||||
};
|
||||
|
||||
/*
|
||||
if the current matcher matches this term, this method should return an object with the following keys
|
||||
{
|
||||
context_values: {
|
||||
values extract from term that should be added to the context
|
||||
}
|
||||
next: AutocompleteComponent(s) to use next
|
||||
priority: optional priority to solve collisions between multiple paths. Min value is used across entire chain
|
||||
}
|
||||
*/
|
||||
AutocompleteComponent.prototype.match = function () {
|
||||
return {
|
||||
next: this.next
|
||||
};
|
||||
};
|
||||
|
||||
function SharedComponent(name, parent) {
|
||||
AutocompleteComponent.call(this, name);
|
||||
this._nextDict = {};
|
||||
if (parent) {
|
||||
parent.addComponent(this);
|
||||
}
|
||||
// for debugging purposes
|
||||
this._parent = parent;
|
||||
}
|
||||
|
||||
SharedComponent.prototype = _.create(
|
||||
AutocompleteComponent.prototype,
|
||||
{ 'constructor': SharedComponent });
|
||||
|
||||
(function (cls) {
|
||||
/* return the first component with a given name */
|
||||
cls.getComponent = function (name) {
|
||||
return (this._nextDict[name] || [undefined])[0];
|
||||
};
|
||||
|
||||
cls.addComponent = function (component) {
|
||||
const current = this._nextDict[component.name] || [];
|
||||
current.push(component);
|
||||
this._nextDict[component.name] = current;
|
||||
this.next = [].concat.apply([], _.values(this._nextDict));
|
||||
};
|
||||
|
||||
}(SharedComponent.prototype));
|
||||
|
||||
/** A component that suggests one of the give options, but accepts anything */
|
||||
function ListComponent(name, list, parent, multiValued, allowNonValidValues) {
|
||||
SharedComponent.call(this, name, parent);
|
||||
this.listGenerator = Array.isArray(list) ? function () {
|
||||
return list;
|
||||
} : list;
|
||||
this.multiValued = _.isUndefined(multiValued) ? true : multiValued;
|
||||
this.allowNonValidValues = _.isUndefined(allowNonValidValues) ? false : allowNonValidValues;
|
||||
}
|
||||
|
||||
ListComponent.prototype = _.create(SharedComponent.prototype, { 'constructor': ListComponent });
|
||||
|
||||
|
||||
(function (cls) {
|
||||
cls.getTerms = function (context, editor) {
|
||||
if (!this.multiValued && context.otherTokenValues) {
|
||||
// already have a value -> no suggestions
|
||||
return [];
|
||||
}
|
||||
let alreadySet = context.otherTokenValues || [];
|
||||
if (_.isString(alreadySet)) {
|
||||
alreadySet = [alreadySet];
|
||||
}
|
||||
let ret = _.difference(this.listGenerator(context, editor), alreadySet);
|
||||
|
||||
if (this.getDefaultTermMeta()) {
|
||||
const meta = this.getDefaultTermMeta();
|
||||
ret = _.map(ret, function (term) {
|
||||
if (_.isString(term)) {
|
||||
term = { 'name': term };
|
||||
}
|
||||
return _.defaults(term, { meta: meta });
|
||||
});
|
||||
}
|
||||
|
||||
return ret;
|
||||
};
|
||||
|
||||
cls.validateTokens = function (tokens) {
|
||||
if (!this.multiValued && tokens.length > 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// verify we have all tokens
|
||||
const list = this.listGenerator();
|
||||
const notFound = _.any(tokens, function (token) {
|
||||
return list.indexOf(token) === -1;
|
||||
});
|
||||
|
||||
if (notFound) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
cls.getContextKey = function () {
|
||||
return this.name;
|
||||
};
|
||||
|
||||
cls.getDefaultTermMeta = function () {
|
||||
return this.name;
|
||||
};
|
||||
|
||||
cls.match = function (token, context, editor) {
|
||||
if (!Array.isArray(token)) {
|
||||
token = [token];
|
||||
}
|
||||
if (!this.allowNonValidValues && !this.validateTokens(token, context, editor)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const result = Object.getPrototypeOf(cls).match.call(this, token, context, editor);
|
||||
result.context_values = result.context_values || {};
|
||||
result.context_values[this.getContextKey()] = token;
|
||||
return result;
|
||||
};
|
||||
}(ListComponent.prototype));
|
||||
|
||||
function SimpleParamComponent(name, parent) {
|
||||
SharedComponent.call(this, name, parent);
|
||||
}
|
||||
|
||||
SimpleParamComponent.prototype = _.create(SharedComponent.prototype, { 'constructor': SimpleParamComponent });
|
||||
|
||||
(function (cls) {
|
||||
cls.match = function (token, context, editor) {
|
||||
const result = Object.getPrototypeOf(cls).match.call(this, token, context, editor);
|
||||
result.context_values = result.context_values || {};
|
||||
result.context_values[this.name] = token;
|
||||
return result;
|
||||
};
|
||||
|
||||
}(SimpleParamComponent.prototype));
|
||||
|
||||
function ConstantComponent(name, parent, options) {
|
||||
SharedComponent.call(this, name, parent);
|
||||
if (_.isString(options)) {
|
||||
options = [options];
|
||||
}
|
||||
this.options = options || [name];
|
||||
}
|
||||
|
||||
ConstantComponent.prototype = _.create(SharedComponent.prototype, { 'constructor': ConstantComponent });
|
||||
|
||||
export { SharedComponent, ListComponent, SimpleParamComponent, ConstantComponent };
|
||||
|
||||
(function (cls) {
|
||||
cls.getTerms = function () {
|
||||
return this.options;
|
||||
};
|
||||
|
||||
cls.addOption = function (options) {
|
||||
if (!Array.isArray(options)) {
|
||||
options = [options];
|
||||
}
|
||||
|
||||
[].push.apply(this.options, options);
|
||||
this.options = _.uniq(this.options);
|
||||
};
|
||||
cls.match = function (token, context, editor) {
|
||||
if (token !== this.name) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return Object.getPrototypeOf(cls).match.call(this, token, context, editor);
|
||||
|
||||
};
|
||||
}(ConstantComponent.prototype));
|
||||
|
||||
export function wrapComponentWithDefaults(component, defaults) {
|
||||
function Wrapper() {
|
||||
|
||||
}
|
||||
|
||||
Wrapper.prototype = {};
|
||||
for (const key in component) {
|
||||
if (_.isFunction(component[key])) {
|
||||
Wrapper.prototype[key] = _.bindKey(component, key);
|
||||
}
|
||||
}
|
||||
|
||||
Wrapper.prototype.getTerms = function (context, editor) {
|
||||
let result = component.getTerms(context, editor);
|
||||
const originalGetTerms = component.getTerms;
|
||||
component.getTerms = function (context, editor) {
|
||||
let result = originalGetTerms.call(component, context, editor);
|
||||
if (!result) {
|
||||
return result;
|
||||
}
|
||||
|
@ -229,7 +34,7 @@ export function wrapComponentWithDefaults(component, defaults) {
|
|||
}, this);
|
||||
return result;
|
||||
};
|
||||
return new Wrapper();
|
||||
return component;
|
||||
}
|
||||
|
||||
const tracer = function () {
|
||||
|
@ -254,7 +59,7 @@ function passThroughContext(context, extensionList) {
|
|||
return result;
|
||||
}
|
||||
|
||||
function WalkingState(parentName, components, contextExtensionList, depth, priority) {
|
||||
export function WalkingState(parentName, components, contextExtensionList, depth, priority) {
|
||||
this.parentName = parentName;
|
||||
this.components = components;
|
||||
this.contextExtensionList = contextExtensionList;
|
||||
|
@ -263,7 +68,7 @@ function WalkingState(parentName, components, contextExtensionList, depth, prior
|
|||
}
|
||||
|
||||
|
||||
function walkTokenPath(tokenPath, walkingStates, context, editor) {
|
||||
export function walkTokenPath(tokenPath, walkingStates, context, editor) {
|
||||
if (!tokenPath || tokenPath.length === 0) {
|
||||
return walkingStates;
|
||||
}
|
||||
|
@ -321,12 +126,6 @@ function walkTokenPath(tokenPath, walkingStates, context, editor) {
|
|||
return walkTokenPath(tokenPath.slice(1), nextWalkingStates, context, editor);
|
||||
}
|
||||
|
||||
export function resolvePathToComponents(tokenPath, context, editor, components) {
|
||||
const walkStates = walkTokenPath(tokenPath, [new WalkingState('ROOT', components, [])], context, editor);
|
||||
const result = [].concat.apply([], _.pluck(walkStates, 'components'));
|
||||
return result;
|
||||
}
|
||||
|
||||
export function populateContext(tokenPath, context, editor, includeAutoComplete, components) {
|
||||
|
||||
let walkStates = walkTokenPath(tokenPath, [new WalkingState('ROOT', components, [])], context, editor);
|
||||
|
|
|
@ -18,17 +18,14 @@
|
|||
*/
|
||||
|
||||
const _ = require('lodash');
|
||||
const engine = require('./engine');
|
||||
import { ConstantComponent, ListComponent, SharedComponent } from './components';
|
||||
|
||||
export function ParamComponent(name, parent, description) {
|
||||
engine.ConstantComponent.call(this, name, parent);
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
ParamComponent.prototype = _.create(engine.ConstantComponent.prototype, { 'constructor': ParamComponent });
|
||||
|
||||
(function (cls) {
|
||||
cls.getTerms = function () {
|
||||
export class ParamComponent extends ConstantComponent {
|
||||
constructor(name, parent, description) {
|
||||
super(name, parent);
|
||||
this.description = description;
|
||||
}
|
||||
getTerms() {
|
||||
const t = { name: this.name };
|
||||
if (this.description === '__flag__') {
|
||||
t.meta = 'flag';
|
||||
|
@ -38,38 +35,33 @@ ParamComponent.prototype = _.create(engine.ConstantComponent.prototype, { 'const
|
|||
t.insertValue = this.name + '=';
|
||||
}
|
||||
return [t];
|
||||
};
|
||||
|
||||
}(ParamComponent.prototype));
|
||||
|
||||
export function UrlParams(description, defaults) {
|
||||
// This is not really a component, just a handy container to make iteration logic simpler
|
||||
this.rootComponent = new engine.SharedComponent('ROOT');
|
||||
if (_.isUndefined(defaults)) {
|
||||
defaults = {
|
||||
'pretty': '__flag__',
|
||||
'format': ['json', 'yaml'],
|
||||
'filter_path': '',
|
||||
};
|
||||
}
|
||||
description = _.clone(description || {});
|
||||
_.defaults(description, defaults);
|
||||
_.each(description, function (pDescription, param) {
|
||||
const component = new ParamComponent(param, this.rootComponent, pDescription);
|
||||
if (Array.isArray(pDescription)) {
|
||||
new engine.ListComponent(param, pDescription, component);
|
||||
}
|
||||
else if (pDescription === '__flag__') {
|
||||
new engine.ListComponent(param, ['true', 'false'], component);
|
||||
}
|
||||
}, this);
|
||||
|
||||
}
|
||||
|
||||
(function (cls) {
|
||||
|
||||
cls.getTopLevelComponents = function () {
|
||||
export class UrlParams {
|
||||
constructor(description, defaults) {
|
||||
// This is not really a component, just a handy container to make iteration logic simpler
|
||||
this.rootComponent = new SharedComponent('ROOT');
|
||||
if (_.isUndefined(defaults)) {
|
||||
defaults = {
|
||||
'pretty': '__flag__',
|
||||
'format': ['json', 'yaml'],
|
||||
'filter_path': '',
|
||||
};
|
||||
}
|
||||
description = _.clone(description || {});
|
||||
_.defaults(description, defaults);
|
||||
_.each(description, function (pDescription, param) {
|
||||
const component = new ParamComponent(param, this.rootComponent, pDescription);
|
||||
if (Array.isArray(pDescription)) {
|
||||
new ListComponent(param, pDescription, component);
|
||||
}
|
||||
else if (pDescription === '__flag__') {
|
||||
new ListComponent(param, ['true', 'false'], component);
|
||||
}
|
||||
}, this);
|
||||
}
|
||||
getTopLevelComponents() {
|
||||
return this.rootComponent.next;
|
||||
};
|
||||
|
||||
}(UrlParams.prototype));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,141 +0,0 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
const _ = require('lodash');
|
||||
const engine = require('./engine');
|
||||
|
||||
export const URL_PATH_END_MARKER = '__url_path_end__';
|
||||
|
||||
function AcceptEndpointComponent(endpoint, parent) {
|
||||
engine.SharedComponent.call(this, endpoint.id, parent);
|
||||
this.endpoint = endpoint;
|
||||
}
|
||||
|
||||
AcceptEndpointComponent.prototype = _.create(engine.SharedComponent.prototype, { 'constructor': AcceptEndpointComponent });
|
||||
|
||||
(function (cls) {
|
||||
|
||||
cls.match = function (token, context, editor) {
|
||||
if (token !== URL_PATH_END_MARKER) {
|
||||
return null;
|
||||
}
|
||||
if (this.endpoint.methods && -1 === _.indexOf(this.endpoint.methods, context.method)) {
|
||||
return null;
|
||||
}
|
||||
const r = Object.getPrototypeOf(cls).match.call(this, token, context, editor);
|
||||
r.context_values = r.context_values || {};
|
||||
r.context_values.endpoint = this.endpoint;
|
||||
if (_.isNumber(this.endpoint.priority)) {
|
||||
r.priority = this.endpoint.priority;
|
||||
}
|
||||
return r;
|
||||
};
|
||||
}(AcceptEndpointComponent.prototype));
|
||||
|
||||
|
||||
/**
|
||||
* @param parametrizedComponentFactories a dict of the following structure
|
||||
* that will be used as a fall back for pattern parameters (i.e.: {indices})
|
||||
* {
|
||||
* indices: function (part, parent) {
|
||||
* return new SharedComponent(part, parent)
|
||||
* }
|
||||
* }
|
||||
* @constructor
|
||||
*/
|
||||
export function UrlPatternMatcher(parametrizedComponentFactories) {
|
||||
// This is not really a component, just a handy container to make iteration logic simpler
|
||||
this.rootComponent = new engine.SharedComponent('ROOT');
|
||||
this.parametrizedComponentFactories = parametrizedComponentFactories || {};
|
||||
}
|
||||
|
||||
(function (cls) {
|
||||
cls.addEndpoint = function (pattern, endpoint) {
|
||||
let c;
|
||||
let activeComponent = this.rootComponent;
|
||||
const endpointComponents = endpoint.url_components || {};
|
||||
const partList = pattern.split('/');
|
||||
_.each(partList, function (part, partIndex) {
|
||||
if (part.search(/^{.+}$/) >= 0) {
|
||||
part = part.substr(1, part.length - 2);
|
||||
if (activeComponent.getComponent(part)) {
|
||||
// we already have something for this, reuse
|
||||
activeComponent = activeComponent.getComponent(part);
|
||||
return;
|
||||
}
|
||||
// a new path, resolve.
|
||||
|
||||
if ((c = endpointComponents[part])) {
|
||||
// endpoint specific. Support list
|
||||
if (Array.isArray(c)) {
|
||||
c = new engine.ListComponent(part, c, activeComponent);
|
||||
}
|
||||
else if (_.isObject(c) && c.type === 'list') {
|
||||
c = new engine.ListComponent(part, c.list, activeComponent, c.multiValued, c.allow_non_valid);
|
||||
}
|
||||
else {
|
||||
console.warn('incorrectly configured url component ', part, ' in endpoint', endpoint);
|
||||
c = new engine.SharedComponent(part);
|
||||
}
|
||||
}
|
||||
else if ((c = this.parametrizedComponentFactories[part])) {
|
||||
// c is a f
|
||||
c = c(part, activeComponent);
|
||||
}
|
||||
else {
|
||||
// just accept whatever with not suggestions
|
||||
c = new engine.SimpleParamComponent(part, activeComponent);
|
||||
}
|
||||
|
||||
activeComponent = c;
|
||||
}
|
||||
else {
|
||||
// not pattern
|
||||
let lookAhead = part;
|
||||
let s;
|
||||
|
||||
for (partIndex++; partIndex < partList.length; partIndex++) {
|
||||
s = partList[partIndex];
|
||||
if (s.indexOf('{') >= 0) {
|
||||
break;
|
||||
}
|
||||
lookAhead += '/' + s;
|
||||
|
||||
}
|
||||
|
||||
if (activeComponent.getComponent(part)) {
|
||||
// we already have something for this, reuse
|
||||
activeComponent = activeComponent.getComponent(part);
|
||||
activeComponent.addOption(lookAhead);
|
||||
}
|
||||
else {
|
||||
c = new engine.ConstantComponent(part, activeComponent, lookAhead);
|
||||
activeComponent = c;
|
||||
}
|
||||
}
|
||||
}, this);
|
||||
// mark end of endpoint path
|
||||
new AcceptEndpointComponent(endpoint, activeComponent);
|
||||
};
|
||||
|
||||
cls.getTopLevelComponents = function () {
|
||||
return this.rootComponent.next;
|
||||
};
|
||||
|
||||
}(UrlPatternMatcher.prototype));
|
|
@ -16,173 +16,66 @@
|
|||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import {
|
||||
TypeAutocompleteComponent,
|
||||
IdAutocompleteComponent,
|
||||
IndexAutocompleteComponent,
|
||||
FieldAutocompleteComponent,
|
||||
ListComponent
|
||||
} from './autocomplete/components';
|
||||
|
||||
const $ = require('jquery');
|
||||
const _ = require('lodash');
|
||||
const mappings = require('./mappings');
|
||||
const Api = require('./kb/api');
|
||||
const autocompleteEngine = require('./autocomplete/engine');
|
||||
import $ from 'jquery';
|
||||
import _ from 'lodash';
|
||||
|
||||
import Api from './kb/api';
|
||||
|
||||
let ACTIVE_API = new Api();
|
||||
|
||||
function nonValidIndexType(token) {
|
||||
return !(token === '_all' || token[0] !== '_');
|
||||
}
|
||||
|
||||
function IndexAutocompleteComponent(name, parent, multiValued) {
|
||||
autocompleteEngine.ListComponent.call(this, name, mappings.getIndices, parent, multiValued);
|
||||
}
|
||||
|
||||
IndexAutocompleteComponent.prototype = _.create(
|
||||
autocompleteEngine.ListComponent.prototype,
|
||||
{ 'constructor': IndexAutocompleteComponent });
|
||||
|
||||
(function (cls) {
|
||||
cls.validateTokens = function (tokens) {
|
||||
if (!this.multiValued && tokens.length > 1) {
|
||||
return false;
|
||||
}
|
||||
return !_.find(tokens, nonValidIndexType);
|
||||
};
|
||||
|
||||
cls.getDefaultTermMeta = function () {
|
||||
return 'index';
|
||||
};
|
||||
|
||||
cls.getContextKey = function () {
|
||||
return 'indices';
|
||||
};
|
||||
}(IndexAutocompleteComponent.prototype));
|
||||
|
||||
|
||||
function TypeGenerator(context) {
|
||||
return mappings.getTypes(context.indices);
|
||||
}
|
||||
|
||||
function TypeAutocompleteComponent(name, parent, multiValued) {
|
||||
autocompleteEngine.ListComponent.call(this, name, TypeGenerator, parent, multiValued);
|
||||
}
|
||||
|
||||
TypeAutocompleteComponent.prototype = _.create(
|
||||
autocompleteEngine.ListComponent.prototype,
|
||||
{ 'constructor': TypeAutocompleteComponent });
|
||||
|
||||
(function (cls) {
|
||||
cls.validateTokens = function (tokens) {
|
||||
if (!this.multiValued && tokens.length > 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return !_.find(tokens, nonValidIndexType);
|
||||
};
|
||||
|
||||
cls.getDefaultTermMeta = function () {
|
||||
return 'type';
|
||||
};
|
||||
|
||||
cls.getContextKey = function () {
|
||||
return 'types';
|
||||
};
|
||||
}(TypeAutocompleteComponent.prototype));
|
||||
|
||||
function FieldGenerator(context) {
|
||||
return _.map(mappings.getFields(context.indices, context.types), function (field) {
|
||||
return { name: field.name, meta: field.type };
|
||||
});
|
||||
}
|
||||
|
||||
function FieldAutocompleteComponent(name, parent, multiValued) {
|
||||
autocompleteEngine.ListComponent.call(this, name, FieldGenerator, parent, multiValued);
|
||||
}
|
||||
|
||||
FieldAutocompleteComponent.prototype = _.create(
|
||||
autocompleteEngine.ListComponent.prototype,
|
||||
{ 'constructor': FieldAutocompleteComponent });
|
||||
|
||||
(function (cls) {
|
||||
cls.validateTokens = function (tokens) {
|
||||
if (!this.multiValued && tokens.length > 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return !_.find(tokens, function (token) {
|
||||
return token.match(/[^\w.?*]/);
|
||||
});
|
||||
};
|
||||
|
||||
cls.getDefaultTermMeta = function () {
|
||||
return 'field';
|
||||
};
|
||||
|
||||
cls.getContextKey = function () {
|
||||
return 'fields';
|
||||
};
|
||||
}(FieldAutocompleteComponent.prototype));
|
||||
|
||||
|
||||
function IdAutocompleteComponent(name, parent, multi) {
|
||||
autocompleteEngine.SharedComponent.call(this, name, parent);
|
||||
this.multi_match = multi;
|
||||
}
|
||||
|
||||
IdAutocompleteComponent.prototype = _.create(
|
||||
autocompleteEngine.SharedComponent.prototype,
|
||||
{ 'constructor': IdAutocompleteComponent });
|
||||
|
||||
(function (cls) {
|
||||
cls.match = function (token, context, editor) {
|
||||
if (!token) {
|
||||
return null;
|
||||
}
|
||||
if (!this.multi_match && Array.isArray(token)) {
|
||||
return null;
|
||||
}
|
||||
token = Array.isArray(token) ? token : [token];
|
||||
if (_.find(token, function (t) {
|
||||
return t.match(/[\/,]/);
|
||||
})) {
|
||||
return null;
|
||||
}
|
||||
const r = Object.getPrototypeOf(cls).match.call(this, token, context, editor);
|
||||
r.context_values = r.context_values || {};
|
||||
r.context_values.id = token;
|
||||
return r;
|
||||
};
|
||||
}(IdAutocompleteComponent.prototype));
|
||||
const isNotAnIndexName = name => name[0] === '_' && name !== '_all';
|
||||
|
||||
const parametrizedComponentFactories = {
|
||||
|
||||
'index': function (name, parent) {
|
||||
index: function (name, parent) {
|
||||
if (isNotAnIndexName(name)) return;
|
||||
return new IndexAutocompleteComponent(name, parent, false);
|
||||
},
|
||||
'indices': function (name, parent) {
|
||||
indices: function (name, parent) {
|
||||
if (isNotAnIndexName(name)) return;
|
||||
return new IndexAutocompleteComponent(name, parent, true);
|
||||
},
|
||||
'type': function (name, parent) {
|
||||
type: function (name, parent) {
|
||||
return new TypeAutocompleteComponent(name, parent, false);
|
||||
},
|
||||
'types': function (name, parent) {
|
||||
types: function (name, parent) {
|
||||
return new TypeAutocompleteComponent(name, parent, true);
|
||||
},
|
||||
'id': function (name, parent) {
|
||||
id: function (name, parent) {
|
||||
return new IdAutocompleteComponent(name, parent);
|
||||
},
|
||||
'ids': function (name, parent) {
|
||||
ids: function (name, parent) {
|
||||
return new IdAutocompleteComponent(name, parent, true);
|
||||
},
|
||||
'fields': function (name, parent) {
|
||||
fields: function (name, parent) {
|
||||
return new FieldAutocompleteComponent(name, parent, true);
|
||||
},
|
||||
'field': function (name, parent) {
|
||||
field: function (name, parent) {
|
||||
return new FieldAutocompleteComponent(name, parent, false);
|
||||
},
|
||||
'nodes': function (name, parent) {
|
||||
return new autocompleteEngine.ListComponent(name, ['_local', '_master', 'data:true', 'data:false',
|
||||
'master:true', 'master:false'], parent);
|
||||
nodes: function (name, parent) {
|
||||
return new ListComponent(
|
||||
name,
|
||||
[
|
||||
'_local',
|
||||
'_master',
|
||||
'data:true',
|
||||
'data:false',
|
||||
'master:true',
|
||||
'master:false',
|
||||
],
|
||||
parent
|
||||
);
|
||||
},
|
||||
node: function (name, parent) {
|
||||
return new ListComponent(name, [], parent, false);
|
||||
},
|
||||
'node': function (name, parent) {
|
||||
return new autocompleteEngine.ListComponent(name, [], parent, false);
|
||||
}
|
||||
};
|
||||
|
||||
export function getUnmatchedEndpointComponents() {
|
||||
|
@ -201,18 +94,27 @@ export function getEndpointBodyCompleteComponents(endpoint) {
|
|||
return desc.bodyAutocompleteRootComponents;
|
||||
}
|
||||
|
||||
export function getTopLevelUrlCompleteComponents() {
|
||||
return ACTIVE_API.getTopLevelUrlCompleteComponents();
|
||||
export function getTopLevelUrlCompleteComponents(method) {
|
||||
return ACTIVE_API.getTopLevelUrlCompleteComponents(method);
|
||||
}
|
||||
|
||||
export function getGlobalAutocompleteComponents(term, throwOnMissing) {
|
||||
return ACTIVE_API.getGlobalAutocompleteComponents(term, throwOnMissing);
|
||||
}
|
||||
|
||||
function loadApisFromJson(json, urlParametrizedComponentFactories, bodyParametrizedComponentFactories) {
|
||||
urlParametrizedComponentFactories = urlParametrizedComponentFactories || parametrizedComponentFactories;
|
||||
bodyParametrizedComponentFactories = bodyParametrizedComponentFactories || urlParametrizedComponentFactories;
|
||||
const api = new Api(urlParametrizedComponentFactories, bodyParametrizedComponentFactories);
|
||||
function loadApisFromJson(
|
||||
json,
|
||||
urlParametrizedComponentFactories,
|
||||
bodyParametrizedComponentFactories
|
||||
) {
|
||||
urlParametrizedComponentFactories =
|
||||
urlParametrizedComponentFactories || parametrizedComponentFactories;
|
||||
bodyParametrizedComponentFactories =
|
||||
bodyParametrizedComponentFactories || urlParametrizedComponentFactories;
|
||||
const api = new Api(
|
||||
urlParametrizedComponentFactories,
|
||||
bodyParametrizedComponentFactories
|
||||
);
|
||||
const names = [];
|
||||
_.each(json, function (apiJson, name) {
|
||||
names.unshift(name);
|
||||
|
@ -230,18 +132,21 @@ function loadApisFromJson(json, urlParametrizedComponentFactories, bodyParametri
|
|||
export function setActiveApi(api) {
|
||||
if (_.isString(api)) {
|
||||
$.ajax({
|
||||
url: '../api/console/api_server?sense_version=' + encodeURIComponent('@@SENSE_VERSION') + '&apis=' + encodeURIComponent(api),
|
||||
url:
|
||||
'../api/console/api_server?sense_version=' +
|
||||
encodeURIComponent('@@SENSE_VERSION') +
|
||||
'&apis=' +
|
||||
encodeURIComponent(api),
|
||||
dataType: 'json', // disable automatic guessing
|
||||
}
|
||||
).then(
|
||||
}).then(
|
||||
function (data) {
|
||||
setActiveApi(loadApisFromJson(data));
|
||||
},
|
||||
function (jqXHR) {
|
||||
console.log('failed to load API \'' + api + '\': ' + jqXHR.responseText);
|
||||
});
|
||||
}
|
||||
);
|
||||
return;
|
||||
|
||||
}
|
||||
console.log('setting active api to [' + api.name + ']');
|
||||
|
||||
|
@ -251,5 +156,5 @@ export function setActiveApi(api) {
|
|||
setActiveApi('es_6_0');
|
||||
|
||||
export const _test = {
|
||||
loadApisFromJson: loadApisFromJson
|
||||
loadApisFromJson: loadApisFromJson,
|
||||
};
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
*/
|
||||
|
||||
const _ = require('lodash');
|
||||
import { UrlPatternMatcher } from '../autocomplete/url_pattern_matcher';
|
||||
import { UrlPatternMatcher } from '../autocomplete/components';
|
||||
import { UrlParams } from '../autocomplete/url_params';
|
||||
import { globalsOnlyAutocompleteComponents, compileBodyDescription } from '../autocomplete/body_completer';
|
||||
|
||||
|
@ -78,8 +78,8 @@ function Api(urlParametrizedComponentFactories, bodyParametrizedComponentFactori
|
|||
};
|
||||
|
||||
|
||||
cls.getTopLevelUrlCompleteComponents = function () {
|
||||
return this.urlPatternMatcher.getTopLevelComponents();
|
||||
cls.getTopLevelUrlCompleteComponents = function (method) {
|
||||
return this.urlPatternMatcher.getTopLevelComponents(method);
|
||||
};
|
||||
|
||||
cls.getUnmatchedEndpointComponents = function () {
|
||||
|
|
|
@ -50,7 +50,6 @@ describe('Integration', () => {
|
|||
});
|
||||
|
||||
function processContextTest(data, mapping, kbSchemes, requestLine, testToRun) {
|
||||
|
||||
test(testToRun.name, async function (done) {
|
||||
let rowOffset = 0; // add one for the extra method line
|
||||
let editorValue = data;
|
||||
|
@ -70,19 +69,18 @@ describe('Integration', () => {
|
|||
const json = {};
|
||||
json[test.name] = kbSchemes || {};
|
||||
const testApi = kb._test.loadApisFromJson(json);
|
||||
//if (kbSchemes) {
|
||||
if (kbSchemes) {
|
||||
// if (kbSchemes.globals) {
|
||||
// $.each(kbSchemes.globals, function (parent, rules) {
|
||||
// testApi.addGlobalAutocompleteRules(parent, rules);
|
||||
// });
|
||||
// }
|
||||
// if (kbSchemes.endpoints) {
|
||||
// $.each(kbSchemes.endpoints, function (endpoint, scheme) {
|
||||
// _.defaults(scheme, {methods: null}); // disable method testing unless specified in test
|
||||
// testApi.addEndpointDescription(endpoint, scheme);
|
||||
// });
|
||||
// }
|
||||
//}
|
||||
if (kbSchemes.endpoints) {
|
||||
$.each(kbSchemes.endpoints, function (endpoint, scheme) {
|
||||
testApi.addEndpointDescription(endpoint, scheme);
|
||||
});
|
||||
}
|
||||
}
|
||||
kb.setActiveApi(testApi);
|
||||
const { cursor } = testToRun;
|
||||
const { row, column } = cursor;
|
||||
|
@ -1021,16 +1019,19 @@ describe('Integration', () => {
|
|||
search_type: ['count', 'query_then_fetch'],
|
||||
scroll: '10m',
|
||||
},
|
||||
methods: ['GET'],
|
||||
data_autocomplete_rules: {},
|
||||
},
|
||||
'_cluster/stats': {
|
||||
patterns: ['_cluster/stats'],
|
||||
indices_mode: 'none',
|
||||
data_autocomplete_rules: {},
|
||||
methods: ['GET'],
|
||||
},
|
||||
'_cluster/nodes/stats': {
|
||||
patterns: ['_cluster/nodes/stats'],
|
||||
data_autocomplete_rules: {},
|
||||
methods: ['GET'],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
@ -1131,7 +1132,7 @@ describe('Integration', () => {
|
|||
|
||||
contextTests(null, MAPPING, CLUSTER_KB, 'GET cl', [
|
||||
{
|
||||
name: 'Endpoints by subpart',
|
||||
name: 'Endpoints by subpart GET',
|
||||
cursor: { row: 0, column: 6 },
|
||||
autoCompleteSet: [
|
||||
{ name: '_cluster/nodes/stats', meta: 'endpoint' },
|
||||
|
@ -1143,20 +1144,15 @@ describe('Integration', () => {
|
|||
prefixToAdd: '',
|
||||
suffixToAdd: '',
|
||||
initialValue: 'cl',
|
||||
method: 'GET'
|
||||
},
|
||||
]);
|
||||
|
||||
contextTests(null, MAPPING, CLUSTER_KB, 'POST cl', [
|
||||
{
|
||||
name: 'Endpoints by subpart',
|
||||
name: 'Endpoints by subpart POST',
|
||||
cursor: { row: 0, column: 7 },
|
||||
autoCompleteSet: [
|
||||
{ name: '_cluster/nodes/stats', meta: 'endpoint' },
|
||||
{ name: '_cluster/stats', meta: 'endpoint' },
|
||||
{ name: '_search', meta: 'endpoint' },
|
||||
{ name: 'index1', meta: 'index' },
|
||||
{ name: 'index2', meta: 'index' },
|
||||
],
|
||||
no_context: true,
|
||||
prefixToAdd: '',
|
||||
suffixToAdd: '',
|
||||
initialValue: 'cl',
|
||||
|
|
|
@ -78,7 +78,7 @@ describe('Knowledge base', () => {
|
|||
context,
|
||||
null,
|
||||
expectedContext.autoCompleteSet,
|
||||
kb.getTopLevelUrlCompleteComponents()
|
||||
kb.getTopLevelUrlCompleteComponents('GET')
|
||||
);
|
||||
|
||||
// override context to just check on id
|
||||
|
|
|
@ -24,8 +24,10 @@ const _ = require('lodash');
|
|||
import {
|
||||
URL_PATH_END_MARKER,
|
||||
UrlPatternMatcher,
|
||||
} from '../../src/autocomplete/url_pattern_matcher';
|
||||
import { populateContext, ListComponent } from '../../src/autocomplete/engine';
|
||||
ListComponent
|
||||
} from '../../src/autocomplete/components';
|
||||
|
||||
import { populateContext } from '../../src/autocomplete/engine';
|
||||
|
||||
describe('Url autocomplete', () => {
|
||||
function patternsTest(
|
||||
|
@ -84,7 +86,7 @@ describe('Url autocomplete', () => {
|
|||
context,
|
||||
null,
|
||||
expectedContext.autoCompleteSet,
|
||||
patternMatcher.getTopLevelComponents()
|
||||
patternMatcher.getTopLevelComponents(context.method)
|
||||
);
|
||||
|
||||
// override context to just check on id
|
||||
|
@ -111,17 +113,19 @@ describe('Url autocomplete', () => {
|
|||
const endpoints = {
|
||||
'1': {
|
||||
patterns: ['a/b'],
|
||||
methods: ['GET']
|
||||
},
|
||||
};
|
||||
patternsTest('simple single path - completion', endpoints, 'a/b$', {
|
||||
endpoint: '1',
|
||||
method: 'GET'
|
||||
});
|
||||
|
||||
patternsTest(
|
||||
'simple single path - completion, with auto complete',
|
||||
endpoints,
|
||||
'a/b',
|
||||
{ autoCompleteSet: [] }
|
||||
{ method: 'GET', autoCompleteSet: [] }
|
||||
);
|
||||
|
||||
patternsTest(
|
||||
|
@ -135,14 +139,14 @@ describe('Url autocomplete', () => {
|
|||
'simple single path - partial, with auto complete',
|
||||
endpoints,
|
||||
'a',
|
||||
{ autoCompleteSet: ['b'] }
|
||||
{ method: 'GET', autoCompleteSet: ['b'] }
|
||||
);
|
||||
|
||||
patternsTest(
|
||||
'simple single path - partial, with auto complete',
|
||||
endpoints,
|
||||
[],
|
||||
{ autoCompleteSet: ['a/b'] }
|
||||
{ method: 'GET', autoCompleteSet: ['a/b'] }
|
||||
);
|
||||
|
||||
patternsTest('simple single path - different path', endpoints, 'a/c', {});
|
||||
|
@ -152,56 +156,61 @@ describe('Url autocomplete', () => {
|
|||
const endpoints = {
|
||||
'1': {
|
||||
patterns: ['a/b', 'a/b/{p}'],
|
||||
methods: ['GET']
|
||||
},
|
||||
'2': {
|
||||
patterns: ['a/c'],
|
||||
methods: ['GET']
|
||||
},
|
||||
};
|
||||
patternsTest('shared path - completion 1', endpoints, 'a/b$', {
|
||||
endpoint: '1',
|
||||
method: 'GET'
|
||||
});
|
||||
|
||||
patternsTest('shared path - completion 2', endpoints, 'a/c$', {
|
||||
endpoint: '2',
|
||||
method: 'GET'
|
||||
});
|
||||
|
||||
patternsTest(
|
||||
'shared path - completion 1 with param',
|
||||
endpoints,
|
||||
'a/b/v$',
|
||||
{ endpoint: '1', p: 'v' }
|
||||
{ method: 'GET', endpoint: '1', p: 'v' }
|
||||
);
|
||||
|
||||
patternsTest('shared path - partial, with auto complete', endpoints, 'a', {
|
||||
autoCompleteSet: ['b', 'c'],
|
||||
method: 'GET',
|
||||
});
|
||||
|
||||
patternsTest(
|
||||
'shared path - partial, with auto complete of param, no options',
|
||||
endpoints,
|
||||
'a/b',
|
||||
{ autoCompleteSet: [] }
|
||||
{ method: 'GET', autoCompleteSet: [] }
|
||||
);
|
||||
|
||||
patternsTest(
|
||||
'shared path - partial, without auto complete',
|
||||
endpoints,
|
||||
'a',
|
||||
{}
|
||||
{ method: 'GET', }
|
||||
);
|
||||
|
||||
patternsTest(
|
||||
'shared path - different path - with auto complete',
|
||||
endpoints,
|
||||
'a/e',
|
||||
{ autoCompleteSet: [] }
|
||||
{ method: 'GET', autoCompleteSet: [] }
|
||||
);
|
||||
|
||||
patternsTest(
|
||||
'shared path - different path - without auto complete',
|
||||
endpoints,
|
||||
'a/e',
|
||||
{}
|
||||
{ method: 'GET', }
|
||||
);
|
||||
}());
|
||||
|
||||
|
@ -212,51 +221,57 @@ describe('Url autocomplete', () => {
|
|||
url_components: {
|
||||
p: ['a', 'b'],
|
||||
},
|
||||
methods: [ 'GET' ]
|
||||
},
|
||||
'2': {
|
||||
patterns: ['a/c'],
|
||||
methods: [ 'GET' ]
|
||||
},
|
||||
};
|
||||
patternsTest('option testing - completion 1', endpoints, 'a/a$', {
|
||||
method: 'GET',
|
||||
endpoint: '1',
|
||||
p: ['a'],
|
||||
});
|
||||
|
||||
patternsTest('option testing - completion 2', endpoints, 'a/b$', {
|
||||
method: 'GET',
|
||||
endpoint: '1',
|
||||
p: ['b'],
|
||||
});
|
||||
|
||||
patternsTest('option testing - completion 3', endpoints, 'a/b,a$', {
|
||||
method: 'GET',
|
||||
endpoint: '1',
|
||||
p: ['b', 'a'],
|
||||
});
|
||||
|
||||
patternsTest('option testing - completion 4', endpoints, 'a/c$', {
|
||||
method: 'GET',
|
||||
endpoint: '2',
|
||||
});
|
||||
|
||||
patternsTest('option testing - completion 5', endpoints, 'a/d$', {});
|
||||
patternsTest('option testing - completion 5', endpoints, 'a/d$', { method: 'GET', });
|
||||
|
||||
patternsTest(
|
||||
'option testing - partial, with auto complete',
|
||||
endpoints,
|
||||
'a',
|
||||
{ autoCompleteSet: [t('a', 'p'), t('b', 'p'), 'c'] }
|
||||
{ method: 'GET', autoCompleteSet: [t('a', 'p'), t('b', 'p'), 'c'] }
|
||||
);
|
||||
|
||||
patternsTest(
|
||||
'option testing - partial, without auto complete',
|
||||
endpoints,
|
||||
'a',
|
||||
{}
|
||||
{ method: 'GET', }
|
||||
);
|
||||
|
||||
patternsTest(
|
||||
'option testing - different path - with auto complete',
|
||||
endpoints,
|
||||
'a/e',
|
||||
{ autoCompleteSet: [] }
|
||||
{ method: 'GET', autoCompleteSet: [] }
|
||||
);
|
||||
}());
|
||||
|
||||
|
@ -267,12 +282,15 @@ describe('Url autocomplete', () => {
|
|||
url_components: {
|
||||
p: ['a', 'b'],
|
||||
},
|
||||
methods: [ 'GET' ]
|
||||
},
|
||||
'2': {
|
||||
patterns: ['b/{p}'],
|
||||
methods: [ 'GET' ]
|
||||
},
|
||||
'3': {
|
||||
patterns: ['b/{l}/c'],
|
||||
methods: [ 'GET' ],
|
||||
url_components: {
|
||||
l: {
|
||||
type: 'list',
|
||||
|
@ -292,7 +310,7 @@ describe('Url autocomplete', () => {
|
|||
'global parameters testing - completion 1',
|
||||
endpoints,
|
||||
'a/a$',
|
||||
{ endpoint: '1', p: ['a'] },
|
||||
{ method: 'GET', endpoint: '1', p: ['a'] },
|
||||
globalFactories
|
||||
);
|
||||
|
||||
|
@ -300,7 +318,7 @@ describe('Url autocomplete', () => {
|
|||
'global parameters testing - completion 2',
|
||||
endpoints,
|
||||
'b/g1$',
|
||||
{ endpoint: '2', p: ['g1'] },
|
||||
{ method: 'GET', endpoint: '2', p: ['g1'] },
|
||||
globalFactories
|
||||
);
|
||||
|
||||
|
@ -308,7 +326,7 @@ describe('Url autocomplete', () => {
|
|||
'global parameters testing - partial, with auto complete',
|
||||
endpoints,
|
||||
'a',
|
||||
{ autoCompleteSet: [t('a', 'p'), t('b', 'p')] },
|
||||
{ method: 'GET', autoCompleteSet: [t('a', 'p'), t('b', 'p')] },
|
||||
globalFactories
|
||||
);
|
||||
|
||||
|
@ -317,6 +335,7 @@ describe('Url autocomplete', () => {
|
|||
endpoints,
|
||||
'b',
|
||||
{
|
||||
method: 'GET',
|
||||
autoCompleteSet: [
|
||||
t('g1', 'p'),
|
||||
t('g2', 'p'),
|
||||
|
@ -331,14 +350,14 @@ describe('Url autocomplete', () => {
|
|||
'Non valid token acceptance - partial, with auto complete 1',
|
||||
endpoints,
|
||||
'b/la',
|
||||
{ autoCompleteSet: ['c'], l: ['la'] },
|
||||
{ method: 'GET', autoCompleteSet: ['c'], l: ['la'] },
|
||||
globalFactories
|
||||
);
|
||||
patternsTest(
|
||||
'Non valid token acceptance - partial, with auto complete 2',
|
||||
endpoints,
|
||||
'b/non_valid',
|
||||
{ autoCompleteSet: ['c'], l: ['non_valid'] },
|
||||
{ method: 'GET', autoCompleteSet: ['c'], l: ['non_valid'] },
|
||||
globalFactories
|
||||
);
|
||||
}());
|
||||
|
@ -347,13 +366,16 @@ describe('Url autocomplete', () => {
|
|||
const endpoints = {
|
||||
'1': {
|
||||
patterns: ['a/b/{p}/c/e'],
|
||||
methods: [ 'GET' ]
|
||||
},
|
||||
};
|
||||
patternsTest('look ahead - autocomplete before param 1', endpoints, 'a', {
|
||||
method: 'GET',
|
||||
autoCompleteSet: ['b'],
|
||||
});
|
||||
|
||||
patternsTest('look ahead - autocomplete before param 2', endpoints, [], {
|
||||
method: 'GET',
|
||||
autoCompleteSet: ['a/b'],
|
||||
});
|
||||
|
||||
|
@ -361,14 +383,14 @@ describe('Url autocomplete', () => {
|
|||
'look ahead - autocomplete after param 1',
|
||||
endpoints,
|
||||
'a/b/v',
|
||||
{ autoCompleteSet: ['c/e'], p: 'v' }
|
||||
{ method: 'GET', autoCompleteSet: ['c/e'], p: 'v' }
|
||||
);
|
||||
|
||||
patternsTest(
|
||||
'look ahead - autocomplete after param 2',
|
||||
endpoints,
|
||||
'a/b/v/c',
|
||||
{ autoCompleteSet: ['e'], p: 'v' }
|
||||
{ method: 'GET', autoCompleteSet: ['e'], p: 'v' }
|
||||
);
|
||||
}());
|
||||
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
{
|
||||
"{index_name}/_xpack/graph/_explore": {
|
||||
"{index}/_xpack/graph/_explore": {
|
||||
"methods": [
|
||||
"POST"
|
||||
],
|
||||
"patterns": [
|
||||
"{index_name}/_xpack/graph/_explore"
|
||||
"{index}/_xpack/graph/_explore"
|
||||
],
|
||||
"data_autocomplete_rules": {
|
||||
"query": {},
|
||||
|
|
|
@ -5,10 +5,10 @@
|
|||
],
|
||||
"patterns": [
|
||||
"_xpack/migration/assistance",
|
||||
"_xpack/migration/assistance/{index_name}"
|
||||
"_xpack/migration/assistance/{index}"
|
||||
]
|
||||
},
|
||||
"_xpack/migration/upgrade/{index_name}": {
|
||||
"_xpack/migration/upgrade/{index}": {
|
||||
"url_params": {
|
||||
"wait_for_completion": ["true", "false"]
|
||||
},
|
||||
|
@ -16,7 +16,7 @@
|
|||
"POST"
|
||||
],
|
||||
"patterns": [
|
||||
"_xpack/migration/upgrade/{index_name}"
|
||||
"_xpack/migration/upgrade/{index}"
|
||||
]
|
||||
},
|
||||
"_xpack/migration/deprecations": {
|
||||
|
@ -25,7 +25,7 @@
|
|||
],
|
||||
"patterns": [
|
||||
"_xpack/migration/deprecations",
|
||||
"{index_name}/_xpack/migration/deprecations"
|
||||
"{index}/_xpack/migration/deprecations"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -55,17 +55,17 @@
|
|||
"POST"
|
||||
]
|
||||
},
|
||||
"_xpack/rollup/data/{index_name}": {
|
||||
"_xpack/rollup/data/{index}": {
|
||||
"patterns": [
|
||||
"_xpack/rollup/data/{index_name}"
|
||||
"_xpack/rollup/data/{index}"
|
||||
],
|
||||
"methods": [
|
||||
"GET"
|
||||
]
|
||||
},
|
||||
"{index_name}/_rollup_search": {
|
||||
"{index}/_rollup_search": {
|
||||
"patterns": [
|
||||
"{index_name}/_rollup_search"
|
||||
"{index}/_rollup_search"
|
||||
],
|
||||
"methods": [
|
||||
"GET"
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue