Merge remote-tracking branch 'upstream/master'

This commit is contained in:
Chris Cowan 2014-03-04 16:25:13 -07:00
commit 90f555f861
64 changed files with 6373 additions and 1909 deletions

View file

@ -5,7 +5,7 @@ module.exports = function (grunt) {
var config = {
pkg: grunt.file.readJSON('package.json'),
kibanaCheckoutDir: './kibana/vendor/kibana',
kibanaRevision: 'marvel',
kibanaRevision: 'master',
agentDir: 'agent',
buildDir: 'build',
packageDir: 'build/packages',

View file

@ -1,4 +1,3 @@
# Installing the last release of Marvel
The easiest way to play/get to know Marvel is to install the latest release version of it. To do so, just run the following command on every node on your cluster (restart node for it to have effect):
@ -41,7 +40,7 @@ Merges kibana and marvel code, builds Kibana and the plugin (via mvn) and puts t
```grunt package```
Zips and tar+gzips the build in ./packages. Includes grunt build
Zips and tar+gzips the build in build/packages. Includes grunt build
```grunt release```
@ -54,3 +53,7 @@ Uploads created archives to download.elasticsearch.org/elasticsearch/marvel/marv
}
```
To upload the current archive as the "latest" release, use:
```grunt release --latest```

View file

@ -121,6 +121,8 @@ public class ESExporter extends AbstractLifecycleComponent<ESExporter> implement
clusterStatsRenderer = new ClusterStatsRenderer();
eventsRenderer = new EventsRenderer();
keepAliveWorker = new ConnectionKeepAliveWorker();
logger.debug("initialized with targets: {}, index prefix [{}], index time format [{}]", hosts, indexPrefix, indexTimeFormat);
}
@ -173,19 +175,8 @@ public class ESExporter extends AbstractLifecycleComponent<ESExporter> implement
exportXContent(clusterStatsRenderer);
}
protected void initKeepAliveWorker() {
keepAliveWorker = new ConnectionKeepAliveWorker();
keepAliveThread = new Thread(keepAliveWorker, EsExecutors.threadName(settings, "keep_alive"));
keepAliveThread.setDaemon(true);
keepAliveThread.start();
}
private HttpURLConnection openExportingConnection() {
if (keepAliveWorker == null) {
// delayed initialization of keep alive worker, to allow ES to start up in
// the case we send metrics to our own ES
initKeepAliveWorker();
}
if (!checkedAndUploadedAllResources) {
try {
checkedAndUploadedAllResources = checkAndUploadAllResources();
@ -199,6 +190,9 @@ public class ESExporter extends AbstractLifecycleComponent<ESExporter> implement
HttpURLConnection conn = openConnection("POST", "_bulk", XContentType.SMILE.restContentType());
if (conn == null) {
logger.error("could not connect to any configured elasticsearch instances: [{}]", hosts);
} else if (keepAliveThread == null || !keepAliveThread.isAlive()) {
// start keep alive upon successful connection if not there.
initKeepAliveThread();
}
return conn;
}
@ -225,17 +219,30 @@ public class ESExporter extends AbstractLifecycleComponent<ESExporter> implement
}
}
@SuppressWarnings("unchecked")
private void sendCloseExportingConnection(HttpURLConnection conn) throws IOException {
logger.trace("sending content");
OutputStream os = conn.getOutputStream();
os.close();
InputStream inputStream = conn.getInputStream();
while (inputStream.read() != -1) ;
inputStream.close();
if (conn.getResponseCode() != 200) {
logConnectionError("remote target didn't respond with 200 OK", conn);
return;
}
InputStream inputStream = conn.getInputStream();
XContentParser parser = XContentType.SMILE.xContent().createParser(inputStream);
Map<String, Object> response = parser.mapAndClose();
if (response.get("items") != null) {
ArrayList<Object> list = (ArrayList<Object>) response.get("items");
for (Object itemObject : list) {
Map<String, Object> actions = (Map<String, Object>) itemObject;
for (String actionKey : actions.keySet()) {
Map<String, Object> action = (Map<String, Object>) actions.get(actionKey);
if (action.get("error") != null) {
logger.error("{} failure (index:[{}] type: [{}]): {}", actionKey, action.get("_index"), action.get("_type"), action.get("error"));
}
}
}
}
}
@ -268,7 +275,7 @@ public class ESExporter extends AbstractLifecycleComponent<ESExporter> implement
@Override
protected void doStop() {
if (keepAliveWorker != null) {
if (keepAliveWorker != null && keepAliveThread.isAlive()) {
keepAliveWorker.closed = true;
keepAliveThread.interrupt();
try {
@ -508,7 +515,6 @@ public class ESExporter extends AbstractLifecycleComponent<ESExporter> implement
builder.endObject();
}
class NodeStatsRenderer implements MultiXContentRenderer {
NodeStats stats;
@ -717,6 +723,12 @@ public class ESExporter extends AbstractLifecycleComponent<ESExporter> implement
}
}
protected void initKeepAliveThread() {
keepAliveThread = new Thread(keepAliveWorker, EsExecutors.threadName(settings, "keep_alive"));
keepAliveThread.setDaemon(true);
keepAliveThread.start();
}
/**
* Sadly we need to make sure we keep the connection open to the target ES a
* Java's connection pooling closes connections if idle for 5sec.
@ -726,6 +738,7 @@ public class ESExporter extends AbstractLifecycleComponent<ESExporter> implement
@Override
public void run() {
logger.trace("starting keep alive thread");
while (!closed) {
try {
Thread.sleep(1000);
@ -739,7 +752,8 @@ public class ESExporter extends AbstractLifecycleComponent<ESExporter> implement
} catch (InterruptedException e) {
// ignore, if closed, good....
} catch (Throwable t) {
logger.debug("error in keep alive thread", t);
logger.debug("error in keep alive thread, shutting down (will be restarted after a successful connection has been made)", t);
return;
}
}
}

View file

@ -39,6 +39,10 @@ Defaults to `"YYYY.MM.dd"`, which produces index names like:
`.marvel-2014.01.28`. Supports date formats as explained
http://joda-time.sourceforge.net/api-release/org/joda/time/format/DateTimeFormat.html[here].
`marvel.agent.exporter.es.timeout`::
Sets the connection timeout for sending data. Defaults to `6s`.
[[marvel-indices]]
=== Marvel indices

View file

@ -138,7 +138,7 @@ var rows = [
"title": "Documents"
},
{
"value_field": "total.indexing.index_total",
"value_field": "primaries.indexing.index_total",
"derivative": true,
"mode": "min",
"scaleSeconds": true,

View file

@ -15,7 +15,7 @@ define([
'angular',
'app',
'jquery',
'lodash',
'lodash'
],
function (angular, app, $, _) {
'use strict';

View file

@ -32,10 +32,15 @@
height: 10px;
width: 50px;
}
.marvel-muted .mutable {
opacity: 0.3;
}
</style>
<div class="pull-left marvel-header marvel-table" ng-show="rows.length > 0 || panel.rowFilter">
<input type="text" class="input-medium" placeholder="Filter {{panel.mode}}..." ng-model="panel.rowFilter" ng-change="onRowFilterChange()"> <span class="count">{{rows.length}} of {{_.size(data)}} {{panel.mode}}</span> / {{selectedData().length}} selected / Last 10m </span>
<input type="text" class="input-medium" placeholder="Filter {{panel.mode}}..." ng-model="panel.rowFilter" ng-change="onRowFilterChange()">
<span class="count">{{rows.length}} of {{_.size(data)}} {{panel.mode}}</span> / {{selectedData().length}} selected / Last 10m </span>
<span ng-show="meta.masterCount > 1"> / </span><span class="text-warning" ng-show="meta.masterCount > 1">Warning: Multiple masters. {{meta.masterCount}} nodes report master role</span></span>
<br>
<span class="small muted pull-right" ng-show="!viewSelect"> <i class="icon-warning"></i> Compact view. Filter {{panel.mode}} to 5 or less, or set the page refresh rate to 2m or greater for more options.</span>
</div>
@ -58,19 +63,23 @@
<i ng-show='metric.field == panel.sort[0]' class="pointer link" ng-class="{'icon-chevron-up': panel.sort[1] == 'asc','icon-chevron-down': panel.sort[1] == 'desc'}"></i>
</th>
</thead>
<tr ng-repeat="row in rows">
<tr ng-repeat="row in rows" ng-class="{'marvel-muted':!row.alive}">
<td>
<div class="checkbox">
<label>
<div>
<label class="checkbox" ng-class="alertClass(row.id_alert_level)">
<input type="checkbox" ng-model="row.selected" ng-checked="row.selected">
<span class="pointer" ng-click="rowClick(row)">{{row.display_name}}</span>
<span class="pointer" ng-click="rowClick(row)">
{{row.display_name}}
<i bs-tooltip="'No report has been received for more than '+row.data_age_display" ng-show="!row.alive" class="icon-exclamation-sign"></i>
<i bs-tooltip="'This node is master'" ng-show="row.master" class="icon-star"></i>
</span>
<div class="marvel-persistent-name pointer" ng-hide="row.id == row.display_name" ng-click="rowClick(row)">{{row.id}}</div>
</label>
</div>
</td>
<td ng-repeat="metric in panel.metrics" ng-class="alertClass(row[metric.field].alert_level)">
<td ng-repeat="metric in panel.metrics" class="mutable" ng-class="alertClass(row[metric.field].alert_level)">
<div class="marvel-mean pointer" ng-click="rowClick(row,metric)">
<span bo-text="(_.isNull(row[metric.field].mean)?'n/a':row[metric.field].mean) | metric_format:metric"></span>
<span bo-text="(_.isNull(row[metric.field].value)?'n/a':row[metric.field].value) | metric_format:metric"></span>
<br>
<div class="marvel-stats-sparkline" panel='panel' field="metric.field" series="row[metric.field].series"></div>
@ -97,18 +106,20 @@
<i ng-show='metric.field == panel.sort[0]' class="pointer link" ng-class="{'icon-chevron-up': panel.sort[1] == 'asc','icon-chevron-down': panel.sort[1] == 'desc'}"></i>
</th>
</thead>
<tr ng-repeat="row in rows">
<tr ng-repeat="row in rows" ng-class="{'marvel-muted':!row.alive}">
<td>
<div class="checkbox">
<div class="checkbox" ng-class="alertClass(row.id_alert_level)">
<label>
<input type="checkbox" ng-model="row.selected" ng-checked="row.selected">
</label>
<span class="pointer" ng-click="rowClick(row)">{{ row.id }}</span>
<i bs-tooltip="'No report has been received for more than '+row.data_age_display" ng-show="!row.alive" class="icon-exclamation-sign"></i>
<i bs-tooltip="'This node is master'" ng-show="row.master" class="icon-star"></i>
</div>
</td>
<td ng-repeat="metric in panel.metrics" ng-class="alertClass(row[metric.field].alert_level)">
<td ng-repeat="metric in panel.metrics" ng-class="alertClass(row[metric.field].alert_level)" class="mutable">
<div class="pointer" ng-click="rowClick(row,metric)">
<span bo-text="(_.isNull(row[metric.field].mean)?'n/a':row[metric.field].mean) | metric_format:metric"></span>
<span bo-text="(_.isNull(row[metric.field].value)?'n/a':row[metric.field].value) | metric_format:metric"></span>
<div ng-if="sparkLines" class="marvel-stats-sparkline pointer" ng-click="rowClick(row,metric)" panel='panel' field="metric.field" series="row[metric.field].series"></div>
</div>

View file

@ -72,6 +72,8 @@ define([
add: undefined
};
$scope.staleIntervalCount = 5;
$scope.modeInfo = {
nodes: {
defaults: {
@ -340,23 +342,32 @@ define([
filter = filterSrv.getBoolFilter(filterSrv.ids);
var to = filterSrv.timeRange(false).to;
var maxFilterTime, to;
maxFilterTime = to = filterSrv.timeRange(false).to;
maxFilterTime = kbn.parseDate(maxFilterTime).getTime();
if (to !== "now") {
to = kbn.parseDate(to).valueOf() + "||";
}
filter.must($scope.get_mode_filter()).must($scope.ejs.RangeFilter('@timestamp').from(to + "-10m/m").to(to + "/m"));
request = $scope.ejs.Request().indices(dashboard.indices).size(0).searchType("count");
request = $scope.ejs.Request().indices(dashboard.indices).size(10);
request.query($scope.ejs.FilteredQuery($scope.ejs.MatchAllQuery(), filter));
// timestamp facet to give us the proper time ranges for each node
request.facet($scope.ejs.TermStatsFacet("timestamp")
.keyField($scope.panel.persistent_field).valueField("@timestamp")
.order('term')
.size(2000));
// master node detection
if ($scope.panel.mode === "nodes") {
request.facet($scope.ejs.TermStatsFacet("master_periods")
.keyField($scope.panel.persistent_field).valueField("@timestamp")
.order('term').facetFilter($scope.ejs.TermFilter("node.master", "true"))
.size(2000));
}
_.each($scope.panel.metrics, function (m) {
request.facet($scope.ejs.TermStatsFacet(m.field)
@ -371,22 +382,64 @@ define([
var mrequest, newData;
// populate the summary data based on the other facets
newData = {};
_.each(r.facets['timestamp'].terms, function (f) {
if (!$scope.panel.show_hidden && f.term[0] === ".") {
return;
}
var t_interval = (f.max - f.min) / f.count / 1000.0,
data_age_in_seconds = (maxFilterTime - f.max) / 1000.0;
if (t_interval <= 0) {
t_interval = 5;
}
var alive = data_age_in_seconds < Math.min(300 * 1000, $scope.staleIntervalCount * t_interval);
newData[f.term] = {
id: f.term,
time_span: (f.max - f.min) / 1000,
reporting_interval: t_interval / 1000,
data_age_in_seconds: data_age_in_seconds,
data_age_display: kbn.secondsToHms(Math.floor(data_age_in_seconds)),
alive: alive,
selected: ($scope.data[f.term] || {}).selected,
alert_level: 0
alert_level: 0,
id_alert_level: alive ? 0 : 1
};
});
if (r.facets['master_periods']) {
var most_recent_master = _.max(r.facets['master_periods'].terms, function (f) {
return f.max;
});
newData[most_recent_master.term].master = true;
// now check we have other active master within the same time frame
var other_masters = _.filter(r.facets['master_periods'].terms, function (t) {
if (t.term === most_recent_master.term) {
return false;
}
if (maxFilterTime - t.max > $scope.staleIntervalCount * newData[t.term].reporting_interval * 1000) {
// stale master info, we don't care.
return false;
}
// enough of overlap to not be a master swap
return (t.max - most_recent_master.min >
Math.min(300 * 1000, $scope.staleIntervalCount * newData[t.term].reporting_interval * 1000));
});
_.each(other_masters, function (t) {
newData[t.term].master = true;
});
if (other_masters.length > 0) {
// mark all master nodes as alerting
_.each(newData, function (n) {
if (n.master) {
n.alert_level = n.id_alert_level = 2;
}
});
}
}
_.each($scope.panel.metrics, function (m) {
_.each(r.facets[m.field].terms, function (f) {
@ -406,29 +459,23 @@ define([
summary[m.field] = m_summary;
return;
}
m_summary.mean = (f.max - f.min) / summary.time_span;
m_summary.value = (f.max - f.min) / summary.time_span;
if (m.scale && m.scale !== 1) {
m_summary.mean /= m.scale;
m_summary.value /= m.scale;
}
}
else {
m_summary.min = f.min;
m_summary.max = f.max;
m_summary.mean = f.mean;
m_summary.value = f.mean;
if (m.scale && m.scale !== 1) {
m_summary.mean /= m.scale;
m_summary.value /= m.scale;
m_summary.max /= m.scale;
m_summary.min /= m.scale;
}
}
summary[m.field] = m_summary;
m_summary.alert_level = $scope.alertLevel(m, m_summary.mean);
// if (f.term === "index_t_200" && m.field === "primaries.docs.count") {
// m_summary.alert_level = 1;
// }
// if (f.term === "index_t_300" && m.field === "primaries.indexing.index_total") {
// m_summary.alert_level = 2;
// }
m_summary.alert_level = $scope.alertLevel(m, m_summary.value);
if (m_summary.alert_level > summary.alert_level) {
summary.alert_level = m_summary.alert_level;
}
@ -466,41 +513,52 @@ define([
$scope.ejs.TermQuery($scope.panel.persistent_field, s.id)
)
);
rowRequest.size(1).fields(_.unique([ stripRaw($scope.panel.display_field), stripRaw($scope.panel.persistent_field)]));
rowRequest.size(1).fields(_.unique(
[ stripRaw($scope.panel.display_field), stripRaw($scope.panel.persistent_field)]
));
rowRequest.sort("@timestamp", "desc");
mrequest.requests(rowRequest);
});
mrequest.doSearch(function (r) {
var
hit,
display_name,
persistent_name;
_.each(r.responses, function (response) {
if (response.hits.hits.length === 0) {
return;
}
esVersion.is('>=1.0.0.RC1').then(function (version) {
var
hit,
display_name,
persistent_name;
hit = response.hits.hits[0];
if (esVersion.gte("1.0.0.RC1")) {
display_name = (hit.fields[stripRaw($scope.panel.display_field)] || [ undefined ])[0];
persistent_name = (hit.fields[stripRaw($scope.panel.persistent_field)] || [ undefined] )[0];
}
else {
display_name = hit.fields[stripRaw($scope.panel.display_field)];
persistent_name = hit.fields[stripRaw($scope.panel.persistent_field)];
}
(newData[persistent_name] || {}).display_name = display_name;
_.each(r.responses, function (response) {
if (response.hits.hits.length === 0) {
return;
}
hit = response.hits.hits[0];
if (version) {
display_name = (hit.fields[stripRaw($scope.panel.display_field)] || [ undefined ])[0];
persistent_name = (hit.fields[stripRaw($scope.panel.persistent_field)] || [ undefined] )[0];
}
else {
display_name = hit.fields[stripRaw($scope.panel.display_field)];
persistent_name = hit.fields[stripRaw($scope.panel.persistent_field)];
}
(newData[persistent_name] || {}).display_name = display_name;
});
$scope._register_data_end();
$scope.select_display_data_and_enrich(newData);
});
$scope._register_data_end();
$scope.select_display_data_and_enrich(newData);
}, $scope._register_data_end);
}, $scope._register_data_end);
};
function applyNewData(rows, data) {
$scope.meta = {
masterCount: _.filter(data, {master: true, alive: true}).length
};
$scope.rows = rows;
$scope.data = data;
$scope.updateUIFeaturesBasedOnData();
@ -572,6 +630,17 @@ define([
return 0;
}
function compareIdByStaleness(id1, id2) {
var s1 = newData[id1], s2 = newData[id2];
if (!s1.alive && s2.alive) {
return -1;
}
if (s1.alive && !s2.alive) {
return 1;
}
return 0;
}
function compareIdByName(id1, id2) {
var s1 = newData[id1], s2 = newData[id2];
if (s1.display_name < s2.display_name) {
@ -583,6 +652,17 @@ define([
return 0;
}
function compareIdByMasterRole(id1, id2) {
var s1 = newData[id1], s2 = newData[id2];
if (s1.master && !s2.master) {
return -1;
}
if (!s1.master && s2.master) {
return 1;
}
return 0;
}
function compareIdByPanelSort(id1, id2) {
var v1 = $scope.get_sort_value(id1, newData),
v2 = $scope.get_sort_value(id2, newData),
@ -614,12 +694,14 @@ define([
}
if ($scope.panel.sort) {
newRowsIds.sort(concatSorting(compareIdByPanelSort, compareIdByAlert, compareIdBySelection));
newRowsIds.sort(concatSorting(compareIdByPanelSort, compareIdByAlert, compareIdByStaleness,
compareIdBySelection, compareIdByMasterRole));
newRowsIds = newRowsIds.slice(0, $scope.rowLimit);
}
else {
newRowsIds.sort(concatSorting(compareIdBySelection, compareIdByAlert, compareIdByName));
newRowsIds.sort(concatSorting(compareIdBySelection, compareIdByAlert, compareIdByStaleness,
compareIdByMasterRole, compareIdByName));
newRowsIds = newRowsIds.slice(0, $scope.rowLimit);
// sort again for visual effect
// sort again for visual placement
@ -631,8 +713,6 @@ define([
return newData[id];
});
// now that we have selections, sort by name (if
request = $scope.ejs.Request().indices(dashboard.indices);
var to = filterSrv.timeRange(false).to;
@ -668,6 +748,19 @@ define([
// Populate scope when we have results
results.then(function (results) {
addHistoryFacetResults(results.facets, newRows, newData, $scope.panel.metrics);
// sort again for visual correctness & because history facets may change current values.
var sf;
if ($scope.panel.sort) {
sf = concatSorting(compareIdByPanelSort, compareIdByAlert, compareIdByStaleness,
compareIdBySelection, compareIdByMasterRole);
}
else {
sf = concatSorting(compareIdByAlert, compareIdByName);
}
newRows.sort(function (r1, r2) {
return sf(r1.id, r2.id);
});
applyNewData(newRows, newData);
}
);
@ -697,15 +790,6 @@ define([
// update mean to match min & max. Mean is calculated using the entire period's min/max
// this can be different than the calculation here that is based of the min of every small bucket
var _l = series_data.length - 1;
if (_l <= 0) {
summary.mean = null;
}
else {
var avg_time = (series_time[_l] - series_time[0]) / 1000;
summary.mean = (series_data[_l] - series_data[0]) / avg_time;
}
series_data = _.map(series_data, function (p, i) {
@ -717,7 +801,7 @@ define([
var _t = ((series_time[i] - series_time[i - 1]) / 1000); // milliseconds -> seconds.
_v = (p - series_data[i - 1]) / _t;
}
return _v;
return _v >= 0 ? _v : null; // we only derive increasing counters. Negative numbers mean reset.
});
summary.max = _.reduce(series_data, function (m, v) {
@ -736,7 +820,11 @@ define([
}
summary.series = _.zip(series_time, series_data);
summary.value = series_data[series_data.length - 1]; // use the last data point as value
summary.alert_level = $scope.alertLevel(m, summary.value);
if (summary.alert_level > row.alert_level) {
row.alert_level = summary.alert_level;
}
});
});
@ -763,7 +851,7 @@ define([
if ($scope.panel.sort[0] === '__name__') {
return id.display_name;
}
return id[$scope.panel.sort[0]].mean;
return id[$scope.panel.sort[0]].value;
};
$scope.set_sort = function (field) {
@ -857,10 +945,13 @@ define([
$scope.detailViewTip = function () {
if ($scope.panel.mode === "nodes") {
return $scope.hasSelected($scope.rows) ? 'Open node statistics dashboard for selected nodes' :
'Select nodes and click to open the node statistics dashboard';
} else {
return $scope.hasSelected($scope.rows) ? 'Open index stats dashboard for selected indices' :
return $scope.hasSelected($scope.rows) ?
'Open node statistics dashboard for selected nodes' :
'Select nodes and click to open the node statistics dashboard';
}
else {
return $scope.hasSelected($scope.rows) ?
'Open index stats dashboard for selected indices' :
'Select indices and click to open the index stats dashboard';
}

View file

@ -7,10 +7,11 @@ define([
'mappings',
'output',
'misc_inputs',
'es',
'utils',
'_'
],
function (curl, $helpPopup, history, input, $, mappings, output, miscInputs, utils, _) {
function (curl, $helpPopup, history, input, $, mappings, output, miscInputs, es, utils, _) {
'use strict';
$(document.body).removeClass('fouc');
@ -22,37 +23,55 @@ define([
cb = typeof cb === 'function' ? cb : $.noop;
input.getCurrentRequest(function (req) {
if (!req) return;
output.update('');
if (!req) {
return;
}
$("#notification").text("Calling ES....").css("visibility", "visible");
var es_server = $esServer.val();
var es_url = req.url;
var es_path = req.url;
var es_method = req.method;
var es_data = req.data.join("\n");
if (es_data) es_data += "\n"; //append a new line for bulk requests.
if (es_data) {
es_data += "\n";
} //append a new line for bulk requests.
utils.callES(es_server, es_url, es_method, es_data, null, function (xhr, status) {
es.send(es_method, es_path, es_data, null, function (xhr, status) {
$("#notification").text("").css("visibility", "hidden");
if (typeof xhr.status == "number" &&
((xhr.status >= 400 && xhr.status < 600) ||
(xhr.status >= 200 && xhr.status < 300)
)) {
// we have someone on the other side. Add to history
history.addToHistory(es_server, es_url, es_method, es_data);
history.addToHistory(es.getBaseUrl(), es_path, es_method, es_data);
var value = xhr.responseText;
try {
value = JSON.stringify(JSON.parse(value), null, 3);
var mode = "ace/mode/json";
var contentType = xhr.getAllResponseHeaders("Content-Type") || "";
if (contentType.indexOf("text/plain") >= 0) {
mode = "ace/mode/text";
}
catch (e) {
else if (contentType.indexOf("application/yaml") >= 0) {
mode = "ace/mode/yaml"
}
else {
// assume json - auto pretty
try {
value = JSON.stringify(JSON.parse(value), null, 3);
}
catch (e) {
}
}
cb(value);
output.update(value, mode);
}
else {
cb("Request failed to get to the server (status code: " + xhr.status + "):" + xhr.responseText);
cb("Request failed to get to the server (status code: " + xhr.status + "):" + xhr.responseText, 'ace/mode/text');
}
}
@ -64,8 +83,7 @@ define([
// set the value of the server and/or the input and clear the output
function resetToValues(server, content) {
if (server != null) {
$esServer.val(server);
mappings.notifyServerChange(server);
es.setBaseUrl(server);
}
if (content != null) {
input.update(content);
@ -77,26 +95,34 @@ define([
var sourceLocation = utils.getUrlParam('load_from') || "stored";
var previousSaveState = history.getSavedEditorState();
var defaultHost = "localhost:9200";
if (document.location.pathname && document.location.pathname.indexOf("_plugin") == 1) {
// running as an ES plugin. Always assume we are using that elasticsearch
defaultHost = document.location.host;
}
if (sourceLocation == "stored") {
if (previousSaveState) {
resetToValues(previousSaveState.server, previousSaveState.content);
} else {
}
else {
resetToValues(defaultHost);
input.autoIndent();
}
} else if (/^https?:\/\//.exec(sourceLocation)) {
}
else if (/^https?:\/\//.exec(sourceLocation)) {
$.get(sourceLocation, null, function (data) {
resetToValues(null, data);
input.highlightCurrentRequestAndUpdateActionBar();
input.updateActionsBar();
});
} else if (previousSaveState) {
}
else if (previousSaveState) {
resetToValues(previousSaveState.server);
} else {
resetToValues(defaultHost)
}
if (document.location.pathname && document.location.pathname.indexOf("_plugin") == 1) {
// running as an ES plugin. Always assume we are using that elasticsearch
resetToValues(document.location.host);
}
}());
(function setupAutosave() {
@ -152,7 +178,9 @@ define([
}
var s = prefix + req.method + " " + req.endpoint;
if (req.data) s += "\n" + req.data;
if (req.data) {
s += "\n" + req.data;
}
s += suffix;
@ -213,18 +241,11 @@ define([
input.commands.addCommand({
name: 'send to elasticsearch',
bindKey: {win: 'Ctrl-Enter', mac: 'Command-Enter'},
exec: function () {
output.update('');
submitCurrentRequestToES(function (resp) {
output.update(resp, 'ace/mode/json');
});
}
exec: submitCurrentRequestToES
});
$send.click(function () {
submitCurrentRequestToES(function (resp) {
output.update(resp, 'ace/mode/json');
});
submitCurrentRequestToES();
return false;
});
@ -238,8 +259,9 @@ define([
var a = li.find('a');
a.attr('href', link.url);
a.text(link.name);
if (a[0].href != window.location.href)
if (a[0].href != window.location.href) {
li.appendTo(linkMenu);
}
});
});
@ -255,4 +277,6 @@ define([
});
}
mappings.onInitComplete();
});

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,312 @@
define([
'exports',
'_'
],
function (exports, _) {
"use strict";
exports.AutocompleteComponent = function (name) {
this.name = name;
};
exports.AutocompleteComponent.prototype.getTerms = function (context, editor) {
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
}
*/
exports.AutocompleteComponent.prototype.match = function (token, context, editor) {
var r = {};
r[this.name] = token;
return {
next: this.next
};
};
function SharedComponent(name, parent) {
exports.AutocompleteComponent.call(this, name);
this._nextDict = {};
if (parent) {
parent.addComponent(this);
}
// for debugging purposes
this._parent = parent;
}
SharedComponent.prototype = _.create(
exports.AutocompleteComponent.prototype,
{ 'constructor': SharedComponent });
exports.SharedComponent = SharedComponent;
(function (cls) {
cls.getComponent = function (name) {
return this._nextDict[name];
};
cls.addComponent = function (c) {
this._nextDict[c.name] = c;
this.next = _.values(this._nextDict);
};
})(SharedComponent.prototype);
/** A component that suggests one of the give options, but accepts anything */
function ListComponent(name, list, parent, multi_valued, allow_non_valid_values) {
SharedComponent.call(this, name, parent);
this.listGenerator = _.isArray(list) ? function () {
return list
} : list;
this.multi_valued = _.isUndefined(multi_valued) ? true : multi_valued;
this.allow_non_valid_values = _.isUndefined(allow_non_valid_values) ? false : allow_non_valid_values;
}
ListComponent.prototype = _.create(SharedComponent.prototype, { "constructor": ListComponent });
exports.ListComponent = ListComponent;
(function (cls) {
cls.getTerms = function (context, editor) {
if (!this.multi_valued && context.otherTokenValues) {
// already have a value -> no suggestions
return []
}
var already_set = context.otherTokenValues || [];
if (_.isString(already_set)) {
already_set = [already_set];
}
var ret = _.difference(this.listGenerator(context, editor), already_set);
if (this.getDefaultTermMeta()) {
var meta = this.getDefaultTermMeta();
ret = _.map(ret, function (t) {
if (_.isString(t)) {
t = { "name": t};
}
return _.defaults(t, { meta: meta });
});
}
return ret;
};
cls.validateToken = function (token, context, editor) {
if (!this.multi_valued && token.length > 1) {
return false;
}
// verify we have all tokens
var list = this.listGenerator();
var not_found = _.any(token, function (p) {
return list.indexOf(p) == -1;
});
if (not_found) {
return false;
}
return true;
};
cls.getContextKey = function (context, editor) {
return this.name;
};
cls.getDefaultTermMeta = function (context, editor) {
return this.name;
};
cls.match = function (token, context, editor) {
if (!_.isArray(token)) {
token = [ token ]
}
if (!this.allow_non_valid_values && !this.validateToken(token, context, editor)) {
return null
}
var r = Object.getPrototypeOf(cls).match.call(this, token, context, editor);
r.context_values = r.context_values || {};
r.context_values[this.getContextKey()] = token;
return r;
}
})(ListComponent.prototype);
function SimpleParamComponent(name, parent) {
SharedComponent.call(this, name, parent);
}
SimpleParamComponent.prototype = _.create(SharedComponent.prototype, { "constructor": SimpleParamComponent });
exports.SimpleParamComponent = SimpleParamComponent;
(function (cls) {
cls.match = function (token, context, editor) {
var r = Object.getPrototypeOf(cls).match.call(this, token, context, editor);
r.context_values = r.context_values || {};
r.context_values[this.name] = token;
return r;
}
})(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 });
exports.ConstantComponent = ConstantComponent;
(function (cls) {
cls.getTerms = function () {
return this.options;
};
cls.addOption = function (options) {
if (!_.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);
function passThroughContext(context, extensionList) {
function PTC() {
}
PTC.prototype = context;
var r = new PTC();
if (extensionList) {
extensionList.unshift(r);
_.assign.apply(_, extensionList);
extensionList.shift();
}
return r;
}
function WalkingState(parent_name, components, contextExtensionList, depth, priority) {
this.parent_name = parent_name;
this.components = components;
this.contextExtensionList = contextExtensionList;
this.depth = depth || 0;
this.priority = priority;
}
function walkTokenPath(tokenPath, walkingStates, context, editor) {
if (!tokenPath || tokenPath.length === 0) {
return walkingStates
}
var token = tokenPath[0],
nextWalkingStates = [];
_.each(walkingStates, function (ws) {
var contextForState = passThroughContext(context, ws.contextExtensionList);
_.each(ws.components, function (component) {
var result = component.match(token, contextForState, editor);
if (result && !_.isEmpty(result)) {
var next, extensionList;
if (result.next && !_.isArray(result.next)) {
next = [result.next];
}
else {
next = result.next;
}
if (result.context_values) {
extensionList = [];
[].push.apply(extensionList, ws.contextExtensionList);
extensionList.push(result.context_values);
}
else {
extensionList = ws.contextExtensionList;
}
var priority = ws.priority;
if (_.isNumber(result.priority)) {
if (_.isNumber(priority)) {
priority = Math.min(priority, result.priority);
}
else {
priority = result.priority;
}
}
nextWalkingStates.push(new WalkingState(component.name, next, extensionList, ws.depth + 1, priority));
}
});
});
if (nextWalkingStates.length == 0) {
// no where to go, still return context variables returned so far..
return _.map(walkingStates, function (ws) {
return new WalkingState(ws.name, [], ws.contextExtensionList);
})
}
return walkTokenPath(tokenPath.splice(1), nextWalkingStates, context, editor);
}
exports.populateContext = function (tokenPath, context, editor, includeAutoComplete, components) {
var walkStates = walkTokenPath(tokenPath, [new WalkingState("ROOT", components, [])], context, editor);
if (includeAutoComplete) {
var autoCompleteSet = [];
_.each(walkStates, function (ws) {
var contextForState = passThroughContext(context, ws.contextExtensionList);
_.each(ws.components, function (c) {
_.each(c.getTerms(contextForState, editor), function (t) {
if (!_.isObject(t)) {
t = { name: t };
}
autoCompleteSet.push(t);
});
})
});
_.uniq(autoCompleteSet, false);
context.autoCompleteSet = autoCompleteSet;
}
// apply what values were set so far to context, selecting the deepest on which sets the context
if (walkStates.length !== 0) {
var wsToUse;
walkStates = _.sortBy(walkStates, function (ws) {
return _.isNumber(ws.priority) ? ws.priority : Number.MAX_VALUE;
});
wsToUse = _.find(walkStates, function (ws) {
return _.isEmpty(ws.components)
});
if (!wsToUse && walkStates.length > 1 && !includeAutoComplete) {
console.info("more then one context active for current path, but autocomplete isn't requested", walkStates);
}
if (!wsToUse) {
wsToUse = walkStates[0];
}
_.each(wsToUse.contextExtensionList, function (e) {
_.assign(context, e);
});
}
};
});

View file

@ -0,0 +1,199 @@
define([
'exports',
'./json_rule_walker',
'kb',
'mappings',
'_'
],
function (exports, json_rule_walker, kb, mappings, _) {
"use strict";
function merge(a, b) {
a.push.apply(a, b);
}
function addMetaToTermsList(list, meta, template) {
return _.map(list, function (t) {
if (typeof t !== "object") {
t = { name: t};
}
return _.defaults(t, { meta: meta, template: template });
});
}
function getRulesForPath(rules, tokenPath, scopeRules) {
// scopeRules are the rules used to resolve relative scope links
var walker = new json_rule_walker.RuleWalker(rules, scopeRules);
walker.walkTokenPath(tokenPath);
return walker.getNormalizedRules();
}
function expandTerm(term, context) {
if (term == "$INDEX$") {
return addMetaToTermsList(mappings.getIndices(), "index");
}
else if (term == "$TYPE$") {
return addMetaToTermsList(mappings.getTypes(context.indices), "type");
}
else if (term == "$FIELD$") {
return _.map(mappings.getFields(context.indices, context.types), function (f) {
return { name: f.name, meta: f.type };
});
}
return [ term ]
}
function addAutocompleteForPath(autocompleteSet, rules, tokenPath, context) {
// extracts the relevant parts of rules for tokenPath
var initialRules = rules;
rules = getRulesForPath(rules, tokenPath);
// apply rule set
var term;
if (rules) {
if (typeof rules == "string") {
merge(autocompleteSet, expandTerm(rules, context));
}
else if (rules instanceof Array) {
if (rules.length > 0 && typeof rules[0] != "object") {// not an array of objects
_.map(rules, function (t) {
merge(autocompleteSet, expandTerm(t, context));
});
}
}
else if (rules.__one_of) {
if (rules.__one_of.length > 0 && typeof rules.__one_of[0] != "object") {
merge(autocompleteSet, rules.__one_of);
}
}
else if (rules.__any_of) {
if (rules.__any_of.length > 0 && typeof rules.__any_of[0] != "object") {
merge(autocompleteSet, rules.__any_of);
}
}
else if (typeof rules == "object") {
for (term in rules) {
if (typeof term == "string" && term.match(/^__|^\*$/)) {
continue;
} // meta term
var rules_for_term = rules[term], template_for_term;
// following linked scope until we find the right template
while (typeof rules_for_term.__template == "undefined" &&
typeof rules_for_term.__scope_link != "undefined"
) {
rules_for_term = json_rule_walker.getLinkedRules(rules_for_term.__scope_link, initialRules);
}
if (typeof rules_for_term.__template != "undefined") {
template_for_term = rules_for_term.__template;
}
else if (rules_for_term instanceof Array) {
template_for_term = [];
if (rules_for_term.length) {
if (rules_for_term[0] instanceof Array) {
template_for_term = [
[]
];
}
else if (typeof rules_for_term[0] == "object") {
template_for_term = [
{}
];
}
else {
template_for_term = [rules_for_term[0]];
}
}
}
else if (_.isObject(rules_for_term)) {
if (rules_for_term.__one_of) {
template_for_term = rules_for_term.__one_of[0];
}
else if (_.isEmpty(rules_for_term))
// term sub rules object. Check if has actual or just meta stuff (like __one_of
{
template_for_term = {};
}
else {
for (var sub_rule in rules_for_term) {
if (!(typeof sub_rule == "string" && sub_rule.substring(0, 2) == "__")) {
// found a real sub element, it's an object.
template_for_term = {};
break;
}
}
}
}
else {
// just add what ever the value is -> default
template_for_term = rules_for_term;
}
switch (term) {
case "$INDEX$":
if (context.indices) {
merge(autocompleteSet,
addMetaToTermsList(context.indices, "index", template_for_term));
}
break;
case "$TYPE$":
merge(autocompleteSet,
addMetaToTermsList(mappings.getTypes(context.indices), "type", template_for_term));
break;
case "$FIELD$":
/* jshint -W083 */
merge(autocompleteSet,
_.map(mappings.getFields(context.indices, context.types), function (f) {
return { name: f.name, meta: f.type, template: template_for_term };
}));
break;
default:
autocompleteSet.push({ name: term, template: template_for_term });
break;
}
}
}
else {
autocompleteSet.push(rules);
}
}
return rules ? true : false;
}
exports.populateContext = function (tokenPath, context) {
var autocompleteSet = [];
tokenPath = _.clone(tokenPath);
// apply global rules first, as they are of lower priority.
// start with one before end as to not to resolve just "{" -> empty path
for (var i = tokenPath.length - 2; i >= 0; i--) {
var subPath = tokenPath.slice(i);
if (addAutocompleteForPath(autocompleteSet, kb.getGlobalAutocompleteRules(), subPath, context)) {
break;
}
}
var pathAsString = tokenPath.join(",");
addAutocompleteForPath(autocompleteSet, (context.endpoint || {}).data_autocomplete_rules,
tokenPath, context);
if (autocompleteSet) {
_.uniq(autocompleteSet, false, function (t) {
return t.name ? t.name : t
});
}
console.log("Resolved token path " + pathAsString + " to ", autocompleteSet,
" (endpoint: ", context.endpoint, ")"
);
context.autoCompleteSet = autocompleteSet;
return context;
}
});

View file

@ -0,0 +1,187 @@
define(['_', 'kb', 'exports'], function (_, kb, exports) {
'use strict';
var WALKER_MODE_EXPECTS_KEY = 1, WALKER_MODE_EXPECTS_CONTAINER = 2, WALKER_MODE_DONE = 3;
function RuleWalker(initialRules, scopeRules) {
// scopeRules are the rules used to resolve relative scope links
if (typeof scopeRules == "undefined") {
scopeRules = initialRules;
}
this._rules = initialRules;
this._mode = WALKER_MODE_EXPECTS_CONTAINER;
this.scopeRules = scopeRules;
}
function getRulesType(rules) {
if (rules == null || typeof rules == undefined) {
return "null";
}
if (rules.__any_of || rules instanceof Array) {
return "list";
}
if (rules.__one_of) {
return getRulesType(rules.__one_of[0]);
}
if (typeof rules == "object") {
return "object";
}
return "value";
}
function getLinkedRules(link, currentRules) {
var link_path = link.split(".");
var scheme_id = link_path.shift();
var linked_rules = currentRules;
if (scheme_id == "GLOBAL") {
linked_rules = kb.getGlobalAutocompleteRules();
}
else if (scheme_id) {
linked_rules = kb.getEndpointDescriptionByEndpoint(scheme_id);
if (!linked_rules) {
throw "Failed to resolve linked scheme: " + scheme_id;
}
linked_rules = linked_rules.data_autocomplete_rules;
if (!linked_rules) {
throw "No autocomplete rules defined in linked scheme: " + scheme_id;
}
}
var walker = new RuleWalker(linked_rules);
var normalized_path = [];
_.each(link_path, function (t) {
normalized_path.push("{", t);
}); // inject { before every step
walker.walkTokenPath(normalized_path);
var rules = walker.getRules();
if (!rules) {
throw "Failed to resolve rules by link: " + link;
}
return rules;
}
_.defaults(RuleWalker.prototype, {
walkByToken: function (token) {
var new_rules;
if (this._mode == WALKER_MODE_EXPECTS_KEY) {
if (token == "{" || token == "[") {
this._rules = null;
this._mode = WALKER_MODE_DONE;
return null;
}
new_rules = this._rules[token] || this._rules["*"]
|| this._rules["$FIELD$"] || this._rules["$TYPE$"]; // we accept anything for a field.
if (new_rules && new_rules.__scope_link) {
new_rules = getLinkedRules(new_rules.__scope_link, this.scopeRules);
}
switch (getRulesType(new_rules)) {
case "object":
case "list":
this._mode = WALKER_MODE_EXPECTS_CONTAINER;
break;
default:
this._mode = WALKER_MODE_DONE;
}
this._rules = new_rules;
return new_rules;
}
else if (this._mode == WALKER_MODE_EXPECTS_CONTAINER) {
var rulesType = getRulesType(this._rules);
if (token == "{") {
if (rulesType != "object") {
this._mode = WALKER_MODE_DONE;
return this._rules = null;
}
this._mode = WALKER_MODE_EXPECTS_KEY;
return this._rules;
}
else if (token == "[") {
if (this._rules.__any_of) {
new_rules = this._rules.__any_of;
}
else if (this._rules instanceof Array) {
new_rules = this._rules;
}
else {
this._mode = WALKER_MODE_DONE;
return this._rules = null;
}
// for now we resolve using the first element in the array
if (new_rules.length == 0) {
this._mode = WALKER_MODE_DONE;
return this._rules = null;
}
else {
if (new_rules[0] && new_rules[0].__scope_link) {
new_rules = [ getLinkedRules(new_rules[0].__scope_link, this.scopeRules) ];
}
switch (getRulesType(new_rules[0])) {
case "object":
this._mode = WALKER_MODE_EXPECTS_CONTAINER;
new_rules = new_rules[0];
break;
case "list":
this._mode = WALKER_MODE_EXPECTS_CONTAINER;
new_rules = new_rules[0];
break;
default:
this._mode = WALKER_MODE_EXPECTS_KEY;
}
}
this._rules = new_rules;
return this._rules;
}
else {
this._rules = null;
this._mode = WALKER_MODE_DONE;
return null;
}
}
else {
this._rules = null;
this._mode = WALKER_MODE_DONE;
return null;
}
},
walkTokenPath: function (tokenPath) {
if (tokenPath.length == 0) {
return;
}
tokenPath = _.clone(tokenPath);
var t;
do {
t = tokenPath.shift();
}
while (this._rules && this.walkByToken(t) != null && tokenPath.length);
},
getRules: function () {
return this._rules;
},
getNormalizedRules: function () {
var rulesType = getRulesType(this._rules);
if (this._mode == WALKER_MODE_EXPECTS_CONTAINER) {
switch (rulesType) {
case "object":
return [ "{" ];
case "list":
return [ "[" ];
}
}
return this._rules;
}
});
exports.RuleWalker = RuleWalker;
exports.getLinkedRules = getLinkedRules;
});

View file

@ -0,0 +1,62 @@
define([
"_", "exports", "./engine"
], function (_, exports, engine) {
"use strict";
function ParamComponent(name, parent, description) {
engine.ConstantComponent.call(this, name, parent);
this.description = description;
}
ParamComponent.prototype = _.create(engine.ConstantComponent.prototype, { "constructor": ParamComponent });
exports.ParamComponent = ParamComponent;
(function (cls) {
cls.getTerms = function () {
var t = { name: this.name };
if (this.description === "__flag__") {
t.meta = "flag"
}
else {
t.meta = "param";
t.insert_value = this.name + "=";
}
return [t];
};
})(ParamComponent.prototype);
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"]
};
}
description = _.clone(description || {});
_.defaults(description, defaults);
_.each(description, function (p_description, param) {
var values, component;
component = new ParamComponent(param, this.rootComponent, p_description);
if (_.isArray(p_description)) {
values = new engine.ListComponent(param, p_description, component);
}
else if (p_description === "__flag__") {
values = new engine.ListComponent(param, ["true", "false"], component);
}
}, this);
}
(function (cls) {
cls.getTopLevelComponents = function () {
return this.rootComponent.next;
}
})(UrlParams.prototype);
exports.UrlParams = UrlParams;
});

View file

@ -0,0 +1,127 @@
define([
"_", "exports", "./engine"
], function (_, exports, engine) {
"use strict";
exports.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 !== exports.URL_PATH_END_MARKER) {
return null;
}
if (this.endpoint.methods && -1 === _.indexOf(this.endpoint.methods, context.method)) {
return null;
}
var 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 globalSharedComponentFactories a dict of the following structure
* that will be used as a fall back for pattern parameters (i.e.: {indices})
* {
* indices: function (part, parent, endpoint) {
* return new SharedComponent(part, parent)
* }
* }
* @constructor
*/
function UrlPatternMatcher(globalSharedComponentFactories) {
// This is not really a component, just a handy container to make iteration logic simpler
this.rootComponent = new engine.SharedComponent("ROOT");
this.globalSharedComponentFactories = globalSharedComponentFactories || {};
}
(function (cls) {
cls.addEndpoint = function (pattern, endpoint) {
var c,
active_component = this.rootComponent,
endpointComponents = endpoint.url_components || {};
var partList = pattern.split("/");
_.each(partList, function (part, partIndex) {
if (part.search(/^{.+}$/) >= 0) {
part = part.substr(1, part.length - 2);
if (active_component.getComponent(part)) {
// we already have something for this, reuse
active_component = active_component.getComponent(part);
return;
}
// a new path, resolve.
if ((c = endpointComponents[part])) {
// endpoint specific. Support list
if (_.isArray(c)) {
c = new engine.ListComponent(part, c, active_component);
}
else if (_.isObject(c) && c.type === "list") {
c = new engine.ListComponent(part, c.list, active_component, c.multi_valued, c.allow_non_valid);
}
else {
console.warn("incorrectly configured url component ", part, " in endpoint", endpoint);
c = new engine.SharedComponent(part);
}
}
else if ((c = this.globalSharedComponentFactories[part])) {
// c is a f
c = c(part, active_component, endpoint);
}
else {
// just accept whatever with not suggestions
c = new engine.SimpleParamComponent(part, active_component);
}
active_component = c;
}
else {
// not pattern
var lookAhead = part, s;
for (partIndex++; partIndex < partList.length; partIndex++) {
s = partList[partIndex];
if (s.indexOf("{") >= 0) {
break;
}
lookAhead += "/" + s;
}
if (active_component.getComponent(part)) {
// we already have something for this, reuse
active_component = active_component.getComponent(part);
active_component.addOption(lookAhead);
}
else {
c = new engine.ConstantComponent(part, active_component, lookAhead);
active_component = c;
}
}
}, this);
// mark end of endpoint path
new AcceptEndpointComponent(endpoint, active_component);
};
cls.getTopLevelComponents = function () {
return this.rootComponent.next;
}
})(UrlPatternMatcher.prototype);
exports.UrlPatternMatcher = UrlPatternMatcher;
});

96
sense/app/es.js Normal file
View file

@ -0,0 +1,96 @@
define([
"_", "jquery", "exports"
], function (_, $, exports) {
"use strict";
var baseUrl;
var serverChangeListeners = [];
var esVersion = [];
exports.getBaseUrl = function () {
return baseUrl;
};
exports.getVersion = function () {
return esVersion;
};
exports.send = function (method, path, data, successCallback, completeCallback, server) {
server = server || exports.getBaseUrl();
path = exports.constructESUrl(server, path);
var uname_password_re = /^(https?:\/\/)?(?:(?:([^\/]*):)?([^\/]*?)@)?(.*)$/;
var url_parts = path.match(uname_password_re);
var uname = url_parts[2];
var password = url_parts[3];
path = url_parts[1] + url_parts[4];
console.log("Calling " + path + " (uname: " + uname + " pwd: " + password + ")");
if (data && method == "GET") {
method = "POST";
}
$.ajax({
url: path,
data: method == "GET" ? null : data,
password: password,
cache: false,
username: uname,
crossDomain: true,
type: method,
dataType: "json",
complete: completeCallback,
success: successCallback
});
};
exports.constructESUrl = function (server, path) {
if (!path) {
path = server;
server = exports.getBaseUrl();
}
if (path.indexOf("://") >= 0) {
return path;
}
if (server.indexOf("://") < 0) {
server = "http://" + server;
}
if (server.substr(-1) == "/") {
server = server.substr(0, server.length - 1);
}
if (path.charAt(0) === "/") {
path = path.substr(1);
}
return server + "/" + path;
};
exports.setBaseUrl = function (base) {
if (baseUrl !== base) {
var old = baseUrl;
baseUrl = base;
exports.send("GET", "/", null, null, function (xhr, status) {
if (xhr.status === 200) {
// parse for version
var value = xhr.responseText;
try {
value = JSON.parse(value);
if (value.version && value.version.number) {
esVersion = value.version.number.split(".");
}
}
catch (e) {
}
}
_.each(serverChangeListeners, function (cb) {
cb(base, old)
});
});
}
};
exports.addServerChangeListener = function (cb) {
serverChangeListeners.push(cb);
}
}
);

View file

@ -9,32 +9,16 @@ define([
'require',
'utils',
'zeroclip',
'ace_ext_language_tools',
'ace_ext_searchbox'
], function (ace, Autocomplete, $, mappings, output, SenseEditor, settings, require, utils, ZeroClipboard) {
'use strict';
// disable standard context based autocompletion.
ace.define('ace/autocomplete/text_completer', ['require', 'exports', 'module'], function(require, exports, module) {
exports.getCompletions = function(editor, session, pos, prefix, callback) {
callback(null, []);
}
});
ace.require('ace/ext/language_tools');
var input = new SenseEditor($('#editor'));
input.setOptions({
enableBasicAutocompletion: true
});
input.autocomplete = new Autocomplete(input);
input.$actions = $("#editor_actions");
ace.require('ace/ext/language_tools').addCompleter(input.autocomplete.completer);
input.commands.addCommand({
name: 'auto indent request',
bindKey: {win: 'Ctrl-I', mac: 'Command-I'},
@ -84,7 +68,7 @@ define([
});
zc.on('load', function () {
function setupCopyButton (cb) {
function setupCopyButton(cb) {
cb = typeof cb === 'function' ? cb : $.noop;
$copyAsCURL.css('visibility', 'hidden');
input.getCurrentRequestAsCURL(function (curl) {

View file

@ -2,50 +2,221 @@ define([
'_',
'exports',
'mappings',
'kb/api_0_90'
], function (_, exports, mappings, api_0_90) {
'use strict';
'es',
'kb/api',
'autocomplete/engine',
'require'
],
function (_, exports, mappings, es, api, autocomplete_engine, require) {
'use strict';
var ACTIVE_API = api_0_90.api;
var ACTIVE_API = new api.Api("empty");
function expandAliases(indices) {
if (indices && indices.length > 0) {
indices = mappings.expandAliases(indices);
function nonValidIndexType(token) {
return !(token === "_all" || token[0] !== "_");
}
return indices;
}
function getEndpointDescriptionByEndpoint(endpoint) {
return ACTIVE_API.getEndpointDescriptionByEndpoint(endpoint)
}
function IndexUrlComponent(name, parent, multi_valued) {
autocomplete_engine.ListComponent.call(this, name, mappings.getIndices, parent, multi_valued);
}
function getEndpointsForIndicesTypesAndId(indices, types, id) {
return ACTIVE_API.getEndpointsForIndicesTypesAndId(expandAliases(indices), types, id);
}
IndexUrlComponent.prototype = _.create(
autocomplete_engine.ListComponent.prototype,
{ 'constructor': IndexUrlComponent });
function getEndpointDescriptionByPath(path, indices, types, id) {
return ACTIVE_API.getEndpointDescriptionByPath(path, expandAliases(indices), types, id);
}
(function (cls) {
cls.validateToken = function (token) {
if (!this.multi_valued && token.length > 1) {
return false;
}
return !_.find(token, nonValidIndexType);
};
function getEndpointAutocomplete(indices, types, id) {
return ACTIVE_API.getEndpointAutocomplete(expandAliases(indices), types, id);
}
cls.getDefaultTermMeta = function () {
return "index"
};
function getGlobalAutocompleteRules() {
return ACTIVE_API.getGlobalAutocompleteRules();
}
cls.getContextKey = function () {
return "indices";
};
})(IndexUrlComponent.prototype);
function setActiveApi(api) {
ACTIVE_API = api;
}
exports.setActiveApi = setActiveApi;
exports.getGlobalAutocompleteRules = getGlobalAutocompleteRules;
exports.getEndpointAutocomplete = getEndpointAutocomplete;
exports.getEndpointDescriptionByPath = getEndpointDescriptionByPath;
exports.getEndpointDescriptionByEndpoint = getEndpointDescriptionByEndpoint;
exports.getEndpointsForIndicesTypesAndId = getEndpointsForIndicesTypesAndId;
function TypeGenerator(context) {
return mappings.getTypes(context.indices);
}
return exports;
});
function TypeUrlComponent(name, parent, multi_valued) {
autocomplete_engine.ListComponent.call(this, name, TypeGenerator, parent, multi_valued);
}
TypeUrlComponent.prototype = _.create(
autocomplete_engine.ListComponent.prototype,
{ 'constructor': TypeUrlComponent });
(function (cls) {
cls.validateToken = function (token) {
if (!this.multi_valued && token.length > 1) {
return false;
}
return !_.find(token, nonValidIndexType);
};
cls.getDefaultTermMeta = function () {
return "type"
};
cls.getContextKey = function () {
return "types";
};
})(TypeUrlComponent.prototype);
function FieldGenerator(context) {
return mappings.getFields(context.indices, context.types);
}
function FieldUrlComponent(name, parent, multi_valued) {
autocomplete_engine.ListComponent.call(this, name, FieldGenerator, parent, multi_valued);
}
FieldUrlComponent.prototype = _.create(
autocomplete_engine.ListComponent.prototype,
{ 'constructor': FieldUrlComponent });
(function (cls) {
cls.validateToken = function (token) {
if (!this.multi_valued && token.length > 1) {
return false;
}
return !_.find(token, function (t) {
return t.match(/[^\w.?*]/);
});
};
cls.getDefaultTermMeta = function () {
return "field"
};
cls.getContextKey = function () {
return "fields";
};
})(FieldUrlComponent.prototype);
function IdUrlComponent(name, parent) {
autocomplete_engine.SharedComponent.call(this, name, parent);
}
IdUrlComponent.prototype = _.create(
autocomplete_engine.SharedComponent.prototype,
{ 'constructor': IdUrlComponent });
(function (cls) {
cls.match = function (token, context, editor) {
if (_.isArray(token) || !token) {
return null;
}
if (token.match(/[\/,]/)) {
return null;
}
var r = Object.getPrototypeOf(cls).match.call(this, token, context, editor);
r.context_values = r.context_values || {};
r.context_values['id'] = token;
return r;
};
})(IdUrlComponent.prototype);
var globalUrlComponentFactories = {
'index': function (part, parent, endpoint) {
return new IndexUrlComponent(part, parent, false);
},
'indices': function (part, parent, endpoint) {
return new IndexUrlComponent(part, parent, true);
},
'type': function (part, parent, endpoint) {
return new TypeUrlComponent(part, parent, false);
},
'types': function (part, parent, endpoint) {
return new TypeUrlComponent(part, parent, true);
},
'id': function (part, parent, endpoint) {
return new IdUrlComponent(part, parent);
},
'fields': function (part, parent, endpoint) {
return new FieldUrlComponent(part, parent, true);
},
'nodes': function (part, parent, endpoint) {
return new autocomplete_engine.ListComponent(part, ["_local", "_master", "data:true", "data:false",
"master:true", "master:false"], parent)
}
};
function expandAliases(indices) {
if (indices && indices.length > 0) {
indices = mappings.expandAliases(indices);
}
return indices;
}
function getEndpointDescriptionByEndpoint(endpoint) {
return ACTIVE_API.getEndpointDescriptionByEndpoint(endpoint)
}
function getTopLevelUrlCompleteComponents() {
return ACTIVE_API.getTopLevelUrlCompleteComponents();
}
function getGlobalAutocompleteRules() {
return ACTIVE_API.getGlobalAutocompleteRules();
}
function setActiveApi(api) {
if (_.isString(api)) {
require([api], setActiveApi);
return;
}
if (_.isFunction(api)) {
/* jshint -W055 */
setActiveApi(new api(globalUrlComponentFactories));
return;
}
ACTIVE_API = api;
console.log("setting api to " + api.name);
}
es.addServerChangeListener(function () {
var version = es.getVersion(), api;
if (!version || version.length == 0) {
api = "kb/api_0_90";
}
else if (version[0] === "1") {
api = "kb/api_1_0";
}
else if (version[0] === "2") {
api = "kb/api_1_0";
}
else {
api = "kb/api_0_90";
}
if (api) {
setActiveApi(api);
}
});
exports.setActiveApi = setActiveApi;
exports.getGlobalAutocompleteRules = getGlobalAutocompleteRules;
exports.getEndpointDescriptionByEndpoint = getEndpointDescriptionByEndpoint;
exports.getTopLevelUrlCompleteComponents = getTopLevelUrlCompleteComponents;
exports._test = {
globalUrlComponentFactories: globalUrlComponentFactories
};
return exports;
});

View file

@ -1,41 +1,44 @@
define([ '_', 'exports'],
function (_, exports) {
define([ '_', 'exports', 'autocomplete/url_pattern_matcher', 'autocomplete/url_params'],
function (_, exports, url_pattern_matcher, url_params) {
'use strict';
function Api() {
this.global_rules = {};
/**
*
* @param name
* @param globalSharedComponentFactories a dictionary of factory functions
* that will be used as fallback for parametrized path part (i.e., {indices} )
* see url_pattern_matcher.UrlPatternMatcher
* @constructor
*/
function Api(name, globalSharedComponentFactories) {
this.globalRules = {};
this.endpoints = {};
}
function escapeRegex(text) {
return text.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
this.name = name;
this.urlPatternMatcher = new url_pattern_matcher.UrlPatternMatcher(globalSharedComponentFactories);
}
Api.prototype.addGlobalAutocompleteRules = function (parentNode, rules) {
this.global_rules[parentNode] = rules;
this.globalRules[parentNode] = rules;
};
Api.prototype.getGlobalAutocompleteRules = function () {
return this.global_rules;
return this.globalRules;
};
Api.prototype.addEndpointDescription = function (endpoint, description) {
if (!description.endpoint_autocomplete) {
description.endpoint_autocomplete = [endpoint];
}
if (!description.match) {
var l = _.map(description.endpoint_autocomplete, escapeRegex);
description.match = "(?:" + l.join(")|(?:") + ")";
}
if (typeof description.match == "string") {
description.match = new RegExp(description.match);
}
var copiedDescription = {};
_.extend(copiedDescription, description);
copiedDescription._id = endpoint;
_.extend(copiedDescription, description || {});
_.defaults(copiedDescription, {
id: endpoint,
patterns: [endpoint],
methods: [ 'GET' ]
});
_.each(copiedDescription.patterns, function (p) {
this.urlPatternMatcher.addEndpoint(p, copiedDescription);
}, this);
copiedDescription.paramsAutocomplete = new url_params.UrlParams(copiedDescription.url_params);
this.endpoints[endpoint] = copiedDescription;
};
@ -44,100 +47,14 @@ define([ '_', 'exports'],
return this.endpoints[endpoint];
};
Api.prototype.getEndpointsForIndicesTypesAndId = function (indices, types, id) {
var ret = [];
var index_mode = "none";
if (indices && indices.length > 0) {
index_mode = typeof indices == "string" ? "single" : "multi";
}
var type_mode = "none";
if (types && types.length > 0) {
type_mode = types.length > 1 ? "multi" : "single";
}
var id_mode = "none";
if (id && id.length > 0) {
id_mode = "single";
}
for (var endpoint in this.endpoints) {
var scheme = this.endpoints[endpoint];
switch (scheme.indices_mode) {
case "none":
if (index_mode !== "none") {
continue;
}
break;
case "single":
if (index_mode !== "single") {
continue;
}
break;
case "required_multi":
if (index_mode === "none") {
continue;
}
break;
case "multi": // always good
break;
}
switch (scheme.types_mode) {
case "none":
if (type_mode !== "none") {
continue;
}
break;
case "single":
if (type_mode !== "single") {
continue;
}
break;
case "multi": // always good
break;
}
switch (scheme.doc_id_mode) {
case "none":
if (id_mode !== "none") {
continue;
}
break;
case "required_single":
if (id_mode === "none") {
continue;
}
break;
}
ret.push(endpoint);
}
return ret;
};
Api.prototype.getEndpointDescriptionByPath = function (path, indices, types, id) {
var endpoints = this.getEndpointsForIndicesTypesAndId(indices, types, id);
for (var i = 0; i < endpoints.length; i++) {
var scheme = this.endpoints[endpoints[i]];
if (scheme.match.test(path || "")) {
return scheme;
}
}
return null;
};
Api.prototype.getEndpointAutocomplete = function (indices, types, id) {
var ret = [];
var endpoints = this.getEndpointsForIndicesTypesAndId(indices, types, id);
for (var i = 0; i < endpoints.length; i++) {
var scheme = this.endpoints[endpoints[i]];
ret.push.apply(ret, scheme.endpoint_autocomplete);
}
return ret;
Api.prototype.getTopLevelUrlCompleteComponents = function () {
return this.urlPatternMatcher.getTopLevelComponents();
};
Api.prototype.clear = function () {
this.endpoints = {};
this.global_rules = {};
this.globalRules = {};
};
exports.Api = Api;

View file

@ -1,9 +1,9 @@
define([
'_',
'exports',
'./api',
'./api_0_90/aliases',
'./api_0_90/cluster',
'./api_0_90/document',
'./api_0_90/facets',
'./api_0_90/filter',
'./api_0_90/globals',
@ -15,15 +15,19 @@ define([
'./api_0_90/settings',
'./api_0_90/templates',
'./api_0_90/warmers'
], function (_, exports, api) {
], function (_, api) {
'use strict';
var api_0_90 = new api.Api();
var parts = _(arguments).rest(2);
_(arguments).rest(3).each(function (apiSection) {
apiSection(api_0_90);
});
function Api_0_90(globalSharedComponentFactories) {
api.Api.call(this, "api_0_90", globalSharedComponentFactories);
parts.each(function (apiSection) {
apiSection(this);
}, this);
}
exports.api = api_0_90;
return exports;
Api_0_90.prototype = _.create(api.Api.prototype, { 'constructor': Api_0_90 });
return Api_0_90;
});

View file

@ -3,15 +3,12 @@ define(function () {
return function init(api) {
api.addEndpointDescription('_aliases', {
match: /_aliases/,
def_method: 'GET',
methods: ['GET', 'POST'],
endpoint_autocomplete: [
'_aliases'
patterns: [
"{indices}/_aliases",
"_aliases",
],
indices_mode: 'multi',
types_mode: 'none',
doc_id_mode: 'none',
data_autocomplete_rules: {
'actions': {
__template: [

View file

@ -2,34 +2,16 @@ define(function () {
'use strict';
return function init(api) {
api.addEndpointDescription('_cluster/nodes/stats', {
methods: ['GET'],
indices_mode: 'none',
types_mode: 'none'
});
api.addEndpointDescription('_cluster/state', {
methods: ['GET'],
endpoint_autocomplete: ['_cluster/state'],
indices_mode: 'none',
types_mode: 'none'
});
api.addEndpointDescription('_cluster/state');
api.addEndpointDescription('_cluster/health', {
methods: ['GET'],
endpoint_autocomplete: ['_cluster/health'],
indices_mode: 'none',
types_mode: 'none'
});
api.addEndpointDescription('_cluster/health');
api.addEndpointDescription('_cluster/settings', {
methods: ['GET', 'PUT'],
endpoint_autocomplete: ['_cluster/settings'],
indices_mode: 'none',
types_mode: 'none',
data_autocomplete_rules: {
data_autocomplete_rules: {
persistent: {
'routing.allocation.same_shard.host' : { __one_of: [ false, true ]}
'routing.allocation.same_shard.host': { __one_of: [ false, true ]}
},
transient: {
__scope_link: '.persistent'

View file

@ -0,0 +1,92 @@
define(function () {
'use strict';
return function init(api) {
api.addEndpointDescription('_get_doc', {
methods: ['GET'],
patterns: [
"{index}/{type}/{id}"
],
url_params: {
"version": 1,
"routing": "",
"parent": ""
}
});
api.addEndpointDescription('_get_doc_source', {
methods: ['GET'],
patterns: [
"{index}/{type}/{id}/_source"
]
});
api.addEndpointDescription('_delete_doc', {
methods: ['DELETE'],
patterns: [
"{index}/{type}/{id}/"
],
url_params: {
"version": 1,
"version_type": ["external", "internal"],
"routing": "",
"parent": ""
}
});
api.addEndpointDescription('index_doc', {
methods: ['PUT', 'POST'],
patterns: [
"{index}/{type}/{id}"
],
url_params: {
"version": 1,
"version_type": ["external", "internal"],
"op_type": ["create"],
"routing": "",
"parent": "",
"timestamp": "",
"ttl": "5m",
"consistency": ["qurom", "one", "all"],
"replication": ["sync", "async"],
"refresh": "__flag__",
"timeout": "1m"
}
});
api.addEndpointDescription('create_doc', {
methods: ['PUT', 'POST'],
patterns: [
"{index}/{type}/{id}/_create"
],
url_params: {
"version": 1,
"version_type": ["external", "internal"],
"routing": "",
"parent": "",
"timestamp": "",
"ttl": "5m",
"consistency": ["qurom", "one", "all"],
"replication": ["sync", "async"],
"refresh": "__flag__",
"timeout": "1m"
}
});
api.addEndpointDescription('index_doc_no_id', {
methods: ['POST'],
patterns: [
"{index}/{type}"
],
url_params: {
"version": 1,
"version_type": ["external", "internal"],
"routing": "",
"parent": "",
"timestamp": "",
"ttl": "5m",
"consistency": ["qurom", "one", "all"],
"replication": ["sync", "async"],
"refresh": "__flag__",
"timeout": "1m"
}
});
}
});

View file

@ -3,49 +3,44 @@ define(function () {
return function init(api) {
api.addEndpointDescription('_refresh', {
def_method: 'POST',
methods: ['POST'],
endpoint_autocomplete: [
'_refresh'
],
indices_mode: 'multi'
methods: ['POST']
});
api.addEndpointDescription('_stats', {
def_method: 'GET',
methods: ['GET'],
endpoint_autocomplete: [
'_stats'
],
indices_mode: 'multi'
patterns: [
"{indices}/_stats",
"_stats"
]
});
api.addEndpointDescription('_segments', {
def_method: 'GET',
methods: ['GET'],
endpoint_autocomplete: [
'_segments'
],
indices_mode: 'multi'
patterns: [
"{indices}/_segments",
"_segments"
]
});
api.addEndpointDescription('__create_index__', {
methods: ['PUT', 'DELETE'],
indices_mode: 'single',
types_mode: 'none',
match: '^/?$',
endpoint_autocomplete: [
''
methods: ['PUT'],
patterns: [
"{index}"
],
data_autocomplete_rules: {
mappings: {
__scope_link: '_mapping'
__scope_link: '_put_mapping'
},
settings: {
__scope_link: '_settings.index'
__scope_link: '_put_settings.index'
}
}
});
api.addEndpointDescription('__delete_indices__', {
methods: ['DELETE'],
patterns: [
"{indices}"
]
});
};
});

View file

@ -2,11 +2,22 @@ define(function () {
'use strict';
return function init(api) {
api.addEndpointDescription('_mapping', {
def_method: 'GET',
methods: ['GET', 'PUT'],
indices_mode: 'multi',
types_mode: 'multi',
api.addEndpointDescription('_get_mapping', {
methods: ['GET'],
priority: 10, // collides with get doc by id
patterns: [
"{indices}/_mapping",
"{indices}/{types}/_mapping",
"_mapping"
]
});
api.addEndpointDescription('_put_mapping', {
methods: ['PUT'],
patterns: [
"{indices}/_mapping",
"{indices}/{type}/_mapping",
],
priority: 10, // collides with put doc by id
data_autocomplete_rules: {
'$TYPE$': {
__template: {
@ -106,7 +117,7 @@ define(function () {
// objects
properties: {
__scope_link: '_mapping.$TYPE$.properties'
__scope_link: '_put_mapping.$TYPE$.properties'
},
// multi_field
@ -115,7 +126,7 @@ define(function () {
},
fields: {
'*': {
__scope_link: '_mapping.$TYPE$.properties.$FIELD$'
__scope_link: '_put_mapping.$TYPE$.properties.$FIELD$'
}
}
}

View file

@ -2,30 +2,9 @@ define(function () {
'use strict';
return function init(api) {
api.addEndpointDescription('_stats', {
methods: ['GET'],
endpoint_autocomplete: ['_stats'],
indices_mode: 'multi',
types_mode: 'none',
doc_id_mode: 'none'
});
api.addEndpointDescription('_cache/clear', {
methods: ['GET'],
endpoint_autocomplete: ['_cache/clear'],
indices_mode: 'multi',
types_mode: 'none',
doc_id_mode: 'none'
});
api.addEndpointDescription('_status', {
methods: ['GET'],
indices_mode: 'multi',
types_mode: 'none',
doc_id_mode: 'none',
endpoint_autocomplete: ['_status']
});
api.addEndpointDescription('_cache/clear');
api.addEndpointDescription('_status');
};

View file

@ -3,14 +3,33 @@ define(function () {
return function init(api) {
api.addEndpointDescription('_search', {
def_method: 'POST',
methods: ['GET', 'POST'],
endpoint_autocomplete: [
'_search'
priority: 10, // collides with get doc by id
patterns: [
"{indices}/{types}/_search",
"{indices}/_search",
"_search"
],
indices_mode: 'multi',
types_mode: 'multi',
doc_id_mode: 'none',
url_params: {
q: "",
df: "",
analyzer: "",
default_operator: ["AND", "OR"],
explain: "__flag__",
fields: [],
sort: "",
track_scores: "__flag__",
timeout: 1,
from: 0,
size: 10,
search_type: ["dfs_query_then_fetch", "dfs_query_and_fetch", "query_then_fetch", "query_and_fetch", "count", "scan"],
lowercase_expanded_terms: ["true", "false"],
analyze_wildcard: "__flag__",
preference: ["_primary", "_primary_first", "_local", "_only_node:xyz", "_prefer_node:xyz", "_shards:2,3"],
scroll: "5m",
scroll_id: "",
routing: ""
},
data_autocomplete_rules: {
query: {
// populated by a global rule

View file

@ -2,13 +2,18 @@ define(function () {
'use strict';
return function init(api) {
api.addEndpointDescription('_settings', {
match: /_settings/,
methods: ['GET', 'PUT'],
endpoint_autocomplete: ['_settings'],
indices_mode: 'multi',
types_mode: 'none',
doc_id_mode: 'none',
api.addEndpointDescription('_get_settings', {
patterns: [
"{indices}/_settings",
"_settings"
]
});
api.addEndpointDescription('_put_settings', {
methods: ['PUT'],
patterns: [
"{indices}/_settings",
"_settings"
],
data_autocomplete_rules: {
index: {
refresh_interval: '1s',

View file

@ -2,16 +2,24 @@ define(function () {
'use strict';
return function init(api) {
api.addEndpointDescription('_template', {
match: /\/?_template/,
def_method: 'PUT',
methods: ['GET', 'PUT', 'DELETE'],
endpoint_autocomplete: [
'_template/TEMPLATE_ID'
api.addEndpointDescription('_delete_template', {
methods: ['DELETE'],
patterns: [
"_template/{id}",
]
});
api.addEndpointDescription('_get_template', {
methods: ['GET'],
patterns: [
"_template/{id}",
"_template",
]
});
api.addEndpointDescription('_put_template', {
methods: ['PUT'],
patterns: [
"_template/{id}",
],
indices_mode: 'none',
types_mode: 'none',
doc_id_mode: 'none',
data_autocomplete_rules: {
template: 'index*',
warmers: { __scope_link: '_warmer' },

View file

@ -2,16 +2,23 @@ define(function () {
'use strict';
return function init(api) {
api.addEndpointDescription('_warmer', {
match: /_warmer/,
def_method: 'PUT',
methods: ['GET', 'PUT', 'DELETE'],
endpoint_autocomplete: [
'_warmer', '_warmer/WARMER_ID'
api.addEndpointDescription('_get_warmer', {
patterns: ["_warmer", "_warmer/{id}"]
});
api.addEndpointDescription('_delete_warmer', {
methods: ['DELETE'],
patterns: [
"{indices}/_warmer",
"{indices}/_warmer/{id}"
]
});
api.addEndpointDescription('_put_warmer', {
methods: ['PUT'],
patterns: [
"{indices}/_warmer",
"{indices}/_warmer/{id}",
"{indices}/{types}/_warmer/{id}"
],
indices_mode: 'required_multi',
types_mode: 'none',
doc_id_mode: 'none',
data_autocomplete_rules: {
query: {
// populated by a global rule

58
sense/app/kb/api_1_0.js Normal file
View file

@ -0,0 +1,58 @@
define([
'_',
'./api',
'./api_1_0/aliases',
'./api_1_0/aggregations',
'./api_1_0/cat',
'./api_1_0/cluster',
'./api_1_0/document',
'./api_1_0/facets',
'./api_1_0/filter',
'./api_1_0/nodes',
'./api_1_0/globals',
'./api_1_0/indices',
'./api_1_0/mappings',
'./api_1_0/misc',
'./api_1_0/query',
'./api_1_0/search',
'./api_1_0/settings',
'./api_1_0/templates',
'./api_1_0/warmers'
], function (_, api) {
'use strict';
var parts = _(arguments).rest(2);
function Api_1_0(globalSharedComponentFactories) {
api.Api.call(this, "api_1_0", globalSharedComponentFactories);
parts.each(function (apiSection) {
apiSection(this);
}, this);
}
Api_1_0.prototype = _.create(api.Api.prototype, { 'constructor': Api_1_0 });
(function (cls) {
cls.addEndpointDescription = function (endpoint, description) {
if (description) {
var url_params_def = {};
_.each(description.patterns || [], function (p) {
if (p.indexOf("{indices}") >= 0) {
url_params_def["ignore_unavailable"] = "__flag__";
url_params_def["allow_no_indices"] = "__flag__";
url_params_def["expand_wildcards"] = ["open", "closed"];
}
});
if (url_params_def) {
description.url_params = description.url_params || {};
_.defaults(description.url_params, url_params_def);
}
}
Object.getPrototypeOf(cls).addEndpointDescription.call(this, endpoint, description);
};
})(Api_1_0.prototype);
return Api_1_0;
});

View file

@ -0,0 +1,198 @@
define(function () {
'use strict';
var simple_metric = {
__template: { field: ""},
field: "$FIELD$",
script: "",
params: {
},
lang: "mvel"
}, field_metric = {
__template: { field: ""},
field: "$FIELD$"
};
var rules = {
"*": {
"aggs": {
__template: {
"NAME": {
"AGG_TYPE": {
}
}
}
},
"min": simple_metric,
"max": simple_metric,
"avg": simple_metric,
"stats": simple_metric,
"extended_stats": simple_metric,
"value_count": {
__template: { field: ""},
field: "$FIELD$"
},
"global": {},
"filter": {},
"missing": field_metric,
"nested": {
__template: {
"path": ""
},
"path": ""
},
"terms": {
__template: {
"field": "",
"size": 10
},
"field": "$FIELD$",
"size": 10,
"shard_size": 10,
"order": {
__template: {
"_term": "asc"
},
"_term": { __one_of: ["asc", "desc"] },
"_count": { __one_of: ["asc", "desc"] },
"*": { __one_of: ["asc", "desc"] }
},
"min_doc_count": 10,
"script": "_value",
"params": {},
"lang": "mvel",
// TODO: these also support regex - extend!
"include": "*",
"exclude": "*",
"execution_hint": { __one_of: ["asc", "desc"] }
},
"range": {
__template: {
"field": "",
"ranges": [
{ "from": 50, "to": 100 },
]
},
"field": "$FIELD$",
"ranges": [
{ "to": 50, "from": 100, "key": "" }
],
"keyed": { __one_of: [true, false]},
"script": "_value",
"params": {},
"lang": "mvel"
},
"date_range": {
__template: {
"field": "",
"ranges": [
{ "from": "now-10d/d", "to": "now" },
]
},
"field": "$FIELD$",
"format": "MM-yyy",
"ranges": [
{ "to": "", "from": "", "key": "" }
],
"keyed": { __one_of: [true, false]},
"script": "_value",
"params": {},
"lang": "mvel"
},
"ip_range": {
__template: {
"field": "",
"ranges": [
{ "from": "10.0.0.5", "to": "10.0.0.10" },
]
},
"field": "$FIELD$",
"format": "MM-yyy",
"ranges": [
{ "to": "", "from": "", "key": "", "mask": "10.0.0.127/25" }
],
"keyed": { __one_of: [true, false]},
"script": "_value",
"params": {},
"lang": "mvel"
},
"histogram": {
__template: {
"field": "price",
"interval": 50
},
"field": "$FIELD$",
"interval": 50,
"min_doc_count": 0,
"order": {
__template: {
"_key": "asc"
},
"_key": { __one_of: ["asc", "desc"] },
"_count": { __one_of: ["asc", "desc"] },
"*": { __one_of: ["asc", "desc"] }
},
"keyed": { __one_of: [true, false]}
},
"date_histogram": {
__template: {
"field": "date",
"interval": "month"
},
"field": "$FIELD$",
"interval": { __one_of: [ "year", "quarter", "week", "day", "hour", "minute", "second"]},
"min_doc_count": 0,
"order": {
__template: {
"_key": "asc"
},
"_key": { __one_of: ["asc", "desc"] },
"_count": { __one_of: ["asc", "desc"] },
"*": { __one_of: ["asc", "desc"] }
},
"keyed": { __one_of: [true, false]},
"pre_zone": "-01:00",
"post_zone": "-01:00",
"pre_zone_adjust_large_interval": { __one_of: [true, false]},
"factor": 1000,
"pre_offset": "1d",
"post_offset": "1d",
"format": "yyyy-MM-dd"
},
"geo_distance": {
__template: {
"field": "location",
"origin": { "lat": 52.3760, "lon": 4.894 },
"ranges": [
{ "from": 100, "to": 300 },
]
},
"field": "$FIELD$",
"origin": { "lat": 0.0, "lon": 0.0 },
"unit": { __one_of: ["mi", "km", "in", "yd", "m", "cm", "mm"]},
"ranges": [
{ "from": 50, "to": 100 }
],
"distance_type": { __one_of: ["arc", "sloppy_arc", "plane"]}
},
"geohash_grid": {
__template: {
"field": "",
"precision": 3
},
"field": "$FIELD#",
"precision": { __one_of: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]},
"size": 10,
"shard_size": 10
}
}
};
return function init(api) {
api.addGlobalAutocompleteRules('aggregations', rules);
api.addGlobalAutocompleteRules('aggs', rules);
};
});

View file

@ -0,0 +1,68 @@
define(function () {
'use strict';
return function init(api) {
api.addEndpointDescription('_post_aliases', {
methods: ['POST'],
patterns: [
"_aliases",
],
data_autocomplete_rules: {
'actions': {
__template: [
{ 'add': { 'index': 'test1', 'alias': 'alias1' } }
],
__any_of: [
{
add: {
index: '$INDEX$',
alias: '',
filter: {},
routing: '1',
search_routing: '1,2',
index_routing: '1'
},
remove: {
index: '',
alias: ''
}
}
]
}
}
});
api.addEndpointDescription('_get_aliases', {
methods: ['GET'],
patterns: [
"_aliases",
]
});
api.addEndpointDescription('_post_alias', {
methods: ["POST", "PUT"],
patterns: [
"{indices}/_alias/{name}"
],
data_autocomplete_rules: {
filter: {},
routing: '1',
search_routing: '1,2',
index_routing: '1'
}
});
api.addEndpointDescription('_delete_alias', {
methods: ["DELETE"],
patterns: [
"{indices}/_alias/{name}"
]
});
api.addEndpointDescription('_get_alias', {
methods: ["GET"],
patterns: [
"_alias",
"{indices}/_alias",
"{indices}/_alias/{name}",
"_alias/{name}"
]
});
};
});

View file

@ -0,0 +1,42 @@
define(["_"], function (_) {
'use strict';
function addSimpleCat(endpoint, api, params, patterns) {
var url_params = { "help": "__flag__", "v": "__flag__", "bytes": ["b"]};
_.each(params || [], function (p) {
if (_.isString(p)) {
url_params[p] = "__flag__";
}
else {
var k = Object.keys(p)[0];
url_params[k] = p[k];
}
});
api.addEndpointDescription(endpoint, {
match: endpoint,
url_params: url_params,
patterns: patterns || [endpoint]
});
}
return function init(api) {
addSimpleCat('_cat/aliases', api);
addSimpleCat('_cat/allocation', api, null, ['_cat/allocation', '_cat/allocation/{nodes}']);
addSimpleCat('_cat/count', api);
addSimpleCat('_cat/health', api, [
{"ts": ["false", "true"]}
]);
addSimpleCat('_cat/indices', api, [
{h: []},
"pri",
],
['_cat/indices', '_cat/indices/{indices}']);
addSimpleCat('_cat/master', api);
addSimpleCat('_cat/nodes', api);
addSimpleCat('_cat/pending_tasks', api);
addSimpleCat('_cat/recovery', api);
addSimpleCat('_cat/thread_pool', api);
addSimpleCat('_cat/shards', api);
};
});

View file

@ -0,0 +1,40 @@
define(function () {
'use strict';
return function init(api) {
api.addEndpointDescription('_cluster/nodes/stats');
api.addEndpointDescription('_cluster/state', {
patterns: [
"_cluster/state",
"_cluster/state/{metrics}",
"_cluster/state/{metrics}/{indices}"
],
url_components: {
"metrics": [ "version", "master_node", "nodes", "routing_table", "metadata", "blocks" ]
}
});
api.addEndpointDescription('_cluster/health');
api.addEndpointDescription('_cluster/pending_tasks');
api.addEndpointDescription('get_cluster/settings', {
patterns: [
'_cluster/settings'
]
});
api.addEndpointDescription('put_cluster/settings', {
methods: ['PUT'],
patterns: [
'_cluster/settings'
],
data_autocomplete_rules: {
persistent: {
'routing.allocation.same_shard.host': { __one_of: [ false, true ]},
'cluster.routing.allocation.enable': { __one_of: [ "all", "primaries", "new_primaries", "none" ]}
},
transient: {
__scope_link: '.persistent'
}
}
});
};
});

View file

@ -0,0 +1,96 @@
define(function () {
'use strict';
return function init(api) {
api.addEndpointDescription('_get_doc', {
methods: ['GET'],
patterns: [
"{index}/{type}/{id}"
],
url_params: {
"version": 1,
"routing": "",
"parent": ""
}
});
api.addEndpointDescription('_get_doc_source', {
methods: ['GET'],
patterns: [
"{index}/{type}/{id}/_source"
],
url_params: {
"version": 1,
"routing": "",
"parent": ""
}
});
api.addEndpointDescription('_delete_doc', {
methods: ['DELETE'],
patterns: [
"{index}/{type}/{id}"
],
url_params: {
"version": 1,
"version_type": ["external", "internal"],
"routing": "",
"parent": ""
}
});
api.addEndpointDescription('index_doc', {
methods: ['PUT', 'POST'],
patterns: [
"{index}/{type}/{id}"
],
url_params: {
"version": 1,
"version_type": ["external", "internal"],
"op_type": ["create"],
"routing": "",
"parent": "",
"timestamp": "",
"ttl": "5m",
"consistency": ["qurom", "one", "all"],
"replication": ["sync", "async"],
"refresh": "__flag__",
"timeout": "1m"
}
});
api.addEndpointDescription('create_doc', {
methods: ['PUT', 'POST'],
patterns: [
"{index}/{type}/{id}/_create"
],
url_params: {
"version": 1,
"version_type": ["external", "internal"],
"routing": "",
"parent": "",
"timestamp": "",
"ttl": "5m",
"consistency": ["qurom", "one", "all"],
"replication": ["sync", "async"],
"refresh": "__flag__",
"timeout": "1m"
}
});
api.addEndpointDescription('index_doc_no_id', {
methods: ['POST'],
patterns: [
"{index}/{type}"
],
url_params: {
"version": 1,
"version_type": ["external", "internal"],
"routing": "",
"parent": "",
"timestamp": "",
"ttl": "5m",
"consistency": ["qurom", "one", "all"],
"replication": ["sync", "async"],
"refresh": "__flag__",
"timeout": "1m"
}
});
}
});

View file

@ -0,0 +1,118 @@
define(function () {
'use strict';
return function init(api) {
api.addGlobalAutocompleteRules('facets', {
'*': {
terms: {
__template: {
field: 'FIELD',
size: 10
},
field: '$FIELD$',
fields: ['$FIELD$'],
size: 10,
script: '',
script_field: '',
order: {
__one_of: ['count', 'term', 'reverse_count', 'reverse_term']
},
all_terms: {
__one_of: [false, true]
},
exclude: ['TERM'],
regex: '',
regex_flags: ''
},
range: {
__template: {
field: 'FIELD',
ranges: [
{
'to': 50
},
{
'from': 20,
'to': 70
},
{
'from': 70,
'to': 120
},
{
'from': 150
}
]
},
field: '$FIELD$',
ranges: [
{
to: 10,
from: 20
}
]
},
histogram: {
__template: {
field: 'FIELD',
interval: 100
},
field: '$FIELD$',
interval: 100,
time_interval: '1.5h',
key_field: '$FIELD$',
value_field: '$FIELD$',
key_script: '',
value_script: '',
params: {}
},
date_histogram: {
__template: {
field: 'FIELD',
'interval': 'day'
},
field: '$FIELD$',
interval: {
__one_of: ['year', 'quarter', 'month', 'week', 'day', 'hour', 'minute', '1h', '1d', '1w']
},
post_zone: -1,
pre_zone: -1,
factor: 1000,
pre_offset: '1d',
post_offset: '1d',
key_field: '$FIELD$',
value_field: '$FIELD$',
value_script: ''
},
filter: {},
query: {},
facet_filter: {
__scope_link: 'GLOBAL.filter'
},
statistical: {
__template: {
field: 'FIELD'
},
field: '$FIELD$',
fields: ['$FIELD$'],
script: ''
},
terms_stats: {
__template: {
key_field: 'FIELD',
value_field: 'FIELD'
},
key_field: '$FIELD$',
value_field: '$FIELD$',
value_script: '',
size: 10,
order: {
__one_of: ['count', 'term', 'reverse_term', 'reverse_count', 'total', 'reverse_total',
'min', 'reverse_min', 'max', 'reverse_max', 'mean', 'reverse_mean'
]
}
}
}
});
};
});

View file

@ -0,0 +1,429 @@
define(function () {
'use strict';
var filters = {};
filters.and = {
__template: {
filters: [
{}
]
},
filters: [
{
__scope_link: '.filter'
}
],
_cache: {
__one_of: [false, true]
}
};
filters.bool = {
must: [
{
__scope_link: '.filter'
}
],
must_not: [
{
__scope_link: '.filter'
}
],
should: [
{
__scope_link: '.filter'
}
],
_cache: {
__one_of: [false, true]
}
};
filters.exists = {
__template: {
'FIELD': 'VALUE'
},
'$FIELD$': ''
};
filters.ids = {
__template: {
'values': ['ID']
},
'type': '$TYPE$',
'values': ['']
};
filters.limit = {
__template: {
value: 100
},
value: 100
};
filters.type = {
__template: {
value: 'TYPE'
},
value: '$TYPE$'
};
filters.geo_bounding_box = {
__template: {
'FIELD': {
'top_left': {
'lat': 40.73,
'lon': -74.1
},
'bottom_right': {
'lat': 40.717,
'lon': -73.99
}
}
},
'$FIELD$': {
top_left: {
lat: 40.73,
lon: -74.1
},
bottom_right: {
lat: 40.73,
lon: -74.1
}
},
type: {
__one_of: ['memory', 'indexed']
},
_cache: {
__one_of: [false, true]
}
};
filters.geo_distance = {
__template: {
distance: 100,
distance_unit: 'km',
'FIELD': {
lat: 40.73,
lon: -74.1
}
},
distance: 100,
distance_unit: {
__one_of: ['km', 'miles']
},
distance_type: {
__one_of: ['arc', 'plane']
},
optimize_bbox: {
__one_of: ['memory', 'indexed', 'none']
},
'$FIELD$': {
lat: 40.73,
lon: -74.1
},
_cache: {
__one_of: [false, true]
}
};
filters.geo_distance_range = {
__template: {
from: 100,
to: 200,
distance_unit: 'km',
'FIELD': {
lat: 40.73,
lon: -74.1
}
},
from: 100,
to: 200,
distance_unit: {
__one_of: ['km', 'miles']
},
distance_type: {
__one_of: ['arc', 'plane']
},
include_lower: {
__one_of: [true, false]
},
include_upper: {
__one_of: [true, false]
},
'$FIELD$': {
lat: 40.73,
lon: -74.1
},
_cache: {
__one_of: [false, true]
}
};
filters.geo_polygon = {
__template: {
'FIELD': {
'points': [
{
lat: 40.73,
lon: -74.1
},
{
lat: 40.83,
lon: -75.1
}
]
}
},
'$FIELD$': {
points: [
{
lat: 40.73,
lon: -74.1
}
]
},
_cache: {
__one_of: [false, true]
}
};
filters.geo_shape = {
__template: {
'FIELD': {
shape: {
type: 'envelope',
coordinates: [
[-45, 45],
[45, -45]
]
},
'relation': 'within'
}
},
'$FIELD$': {
shape: {
type: '',
coordinates: []
},
indexed_shape: {
id: '',
index: '$INDEX$',
type: '$TYPE$',
shape_field_name: 'shape'
},
relation: {
__one_of: ['within', 'intersects', 'disjoint']
}
}
};
filters.has_child = {
__template: {
type: 'TYPE',
query: {}
},
type: '$TYPE$',
query: {},
_scope: ''
};
filters.has_parent = {
__template: {
type: 'TYPE',
query: {}
},
type: '$TYPE$',
query: {},
_scope: ''
};
filters.m = filters.missing = {
__template: {
field: 'FIELD'
},
existence: {
__one_of: [true, false]
},
null_value: {
__one_of: [true, false]
},
field: '$FIELD$'
};
filters.not = {
__template: {
filter: {}
},
filter: {
__scope_link: '.filter'
},
_cache: {
__one_of: [true, false]
}
};
filters.numeric_range = {
__template: {
'FIELD': {
from: 10,
to: 20
}
},
"$FIELD$": {
from: 1,
to: 20,
include_lower: {
__one_of: [true, false]
},
include_upper: {
__one_of: [true, false]
}
}
};
filters.or = {
__template: {
filters: [
{}
]
},
filters: [
{
__scope_link: '.filter'
}
],
_cache: {
__one_of: [false, true]
}
};
filters.prefix = {
__template: {
'FIELD': 'VALUE'
},
'$FIELD$': '',
_cache: {
__one_of: [true, false]
}
};
filters.query = {
__scope_link: '.query'
};
filters.fquery = {
__template: {
query: {},
_cache: true
},
query: {
__scope_link: '.query'
},
_cache: {
__one_of: [true, false]
}
};
filters.range = {
__template: {
'FIELD': {
from: 10,
to: 20
}
},
"$FIELD$": {
from: 1,
to: 20,
include_lower: {
__one_of: [true, false]
},
include_upper: {
__one_of: [true, false]
},
_cache: {
__one_of: [false, true]
}
}
};
filters.script = {
__template: {
script: 'SCRIPT',
params: {}
},
script: '',
params: {},
_cache: {
__one_of: [true, false]
}
};
filters.term = {
__template: {
'FIELD': 'VALUE'
},
'$FIELD$': '',
_cache: {
__one_of: [false, true]
}
};
filters.terms = {
__template: {
'FIELD': ['VALUE1', 'VALUE2']
},
field: ['$FIELD$'],
execution: {
__one_of: ['plain', 'bool', 'and', 'or', 'bool_nocache', 'and_nocache', 'or_nocache']
},
_cache: {
__one_of: [false, true]
}
};
filters.nested = {
__template: {
path: 'path_to_nested_doc',
query: {}
},
query: {},
path: '',
_cache: {
__one_of: [true, false]
},
_name: ''
};
return function init(api) {
api.addGlobalAutocompleteRules('filter', filters);
};
});

View file

@ -0,0 +1,26 @@
define(function () {
'use strict';
return function init(api) {
api.addGlobalAutocompleteRules('highlight', {
pre_tags: {},
post_tags: {},
tags_schema: {},
fields: {
'$FIELD$': {
fragment_size: 20,
number_of_fragments: 3
}
}
});
// only used with scope links as there is no common name for scripts
api.addGlobalAutocompleteRules('SCRIPT_ENV', {
__template: { 'script': ''},
script: '',
lang: '',
params: {}
});
};
});

View file

@ -0,0 +1,75 @@
define(function () {
'use strict';
return function init(api) {
api.addEndpointDescription('_refresh', {
methods: ['POST']
});
api.addEndpointDescription('_stats', {
patterns: [
"_stats",
"_stats/{metrics}",
"{indices}/_stats",
"{indices}/_stats/{metrics}",
],
url_components: {
"metrics": [
"docs",
"store",
"indexing",
"search",
"get",
"merge",
"refresh",
"flush",
"warmer",
"filter_cache",
"id_cache",
"percolate",
"segments",
"fielddata",
"completion",
"_all"
]
},
url_params: {
"fields": [],
"types": [],
"completion_fields": [],
"fielddata_fields": []
}
});
api.addEndpointDescription('_segments', {
patterns: [
"{indices}/_segments",
"_segments"
]
});
api.addEndpointDescription('__create_index__', {
methods: ['PUT'],
patterns: [
"{index}"
],
data_autocomplete_rules: {
mappings: {
__scope_link: '_put_mapping'
},
settings: {
__scope_link: '_put_settings.index'
}
}
});
api.addEndpointDescription('__delete_indices__', {
methods: ['DELETE'],
patterns: [
"{indices}"
]
});
};
});

View file

@ -0,0 +1,160 @@
define(function () {
'use strict';
return function init(api) {
api.addEndpointDescription('_get_mapping', {
methods: ['GET'],
priority: 10, // collides with get doc by id
patterns: [
"{indices}/_mapping",
"{indices}/_mapping/{types}",
"{indices}/{types}/_mapping",
"_mapping"
]
});
api.addEndpointDescription('_delete_mapping', {
methods: ['DELETE'],
priority: 10, // collides with get doc by id
patterns: [
"{indices}/_mapping",
"{indices}/_mapping/{types}",
"{indices}/{types}/_mapping",
"_mapping"
]
});
api.addEndpointDescription('_put_type_mapping', {
methods: ['PUT', 'POST'],
patterns: [
"{indices}/{type}/_mapping",
"{indices}/_mapping/{type}",
],
priority: 10, // collides with put doc by id
data_autocomplete_rules: {
__template: {
properties: {
'FIELD': {}
}
},
'_parent': {
__template: {
'type': ''
},
'type': '$TYPE$'
},
'index_analyzer': 'standard',
'search_analyzer': 'standard',
'analyzer': 'standard',
'dynamic_date_formats': ['yyyy-MM-dd'],
'date_detection': {
__one_of: [true, false]
},
'numeric_detection': {
__one_of: [true, false]
},
'properties': {
'*': {
type: {
__one_of: ['string', 'float', 'double', 'byte', 'short', 'integer', 'long', 'date', 'boolean',
'binary', 'object', 'nested', 'multi_field'
]
},
// strings
index_name: '',
store: {
__one_of: ['no', 'yes']
},
index: {
__one_of: ['analyzed', 'not_analyzed', 'no']
},
term_vector: {
__one_of: ['no', 'yes', 'with_offsets', 'with_positions', 'with_positions_offsets']
},
boost: 1.0,
null_value: '',
omit_norms: {
__one_of: [true, false]
},
index_options: {
__one_of: ['docs', 'freqs', 'positions']
},
analyzer: 'standard',
index_analyzer: 'standard',
search_analyzer: 'standard',
include_in_all: {
__one_of: [false, true]
},
ignore_above: 10,
position_offset_gap: 0,
// numeric
precision_step: 4,
ignore_malformed: {
__one_of: [true, false]
},
// dates
format: {
__one_of: ['basic_date', 'basic_date_time', 'basic_date_time_no_millis',
'basic_ordinal_date', 'basic_ordinal_date_time', 'basic_ordinal_date_time_no_millis',
'basic_time', 'basic_time_no_millis', 'basic_t_time', 'basic_t_time_no_millis',
'basic_week_date', 'basic_week_date_time', 'basic_week_date_time_no_millis',
'date', 'date_hour', 'date_hour_minute', 'date_hour_minute_second', 'date_hour_minute_second_fraction',
'date_hour_minute_second_millis', 'date_optional_time', 'date_time', 'date_time_no_millis',
'hour', 'hour_minute', 'hour_minute_second', 'hour_minute_second_fraction', 'hour_minute_second_millis',
'ordinal_date', 'ordinal_date_time', 'ordinal_date_time_no_millis', 'time', 'time_no_millis',
't_time', 't_time_no_millis', 'week_date', 'week_date_time', 'weekDateTimeNoMillis', 'week_year',
'weekyearWeek', 'weekyearWeekDay', 'year', 'year_month', 'year_month_day'
]
},
fielddata: {
filter: {
regex: '',
frequency: {
min: 0.001,
max: 0.1,
min_segment_size: 500
}
}
},
postings_format: {
__one_of: ['direct', 'memory', 'pulsing', 'bloom_default', 'bloom_pulsing', 'default']
},
similarity: {
__one_of: ['default', 'BM25']
},
// objects
properties: {
__scope_link: '_put_mapping.$TYPE$.properties'
},
// multi_field
path: {
__one_of: ['just_name', 'full']
},
fields: {
'*': {
__scope_link: '_put_mapping.$TYPE$.properties.$FIELD$'
}
}
}
}
}
});
api.addEndpointDescription('_put_mapping', {
methods: ['PUT'],
patterns: [
"{indices}/_mapping",
],
data_autocomplete_rules: {
'$TYPE$': {
__scope_link: '_put_type_mapping'
}
}
});
};
});

View file

@ -0,0 +1,26 @@
define(function () {
'use strict';
return function init(api) {
api.addEndpointDescription('_stats', {
patterns: [
"_stats",
"{indices}/_stats"
]
});
api.addEndpointDescription('_cache/clear', {
patterns: [
"_cache/clear",
"{indices}/_cache/clear"
]
});
api.addEndpointDescription('_status', {
patterns: [
"_status",
"{indices}/_status"
]
});
};
});

View file

@ -0,0 +1,73 @@
define(function () {
'use strict';
return function init(api) {
api.addEndpointDescription('_nodes/info', {
patterns: [
"_nodes",
"_nodes/{metrics}",
"_nodes/{nodes}/stats",
"_nodes/{nodes}/stats/{metrics}",
"_nodes/{nodes}/stats/{metrics}/{index_metric}",
"_nodes/{nodes}/stats/{metrics}/{index_metric}/{fields}"
],
url_components: {
"metrics": [
"settings",
"os",
"process",
"jvm",
"thread_pool",
"network",
"transport",
"http",
"plugin",
"_all"
]
}
});
api.addEndpointDescription('_nodes/stats', {
patterns: [
"_nodes/stats",
"_nodes/stats/{metrics}",
"_nodes/{nodes}/stats",
"_nodes/{nodes}/stats/{metrics}",
"_nodes/{nodes}/stats/{metrics}/{index_metric}",
"_nodes/{nodes}/stats/{metrics}/{index_metric}/{fields}"
],
url_components: {
"metrics": [
"os",
"jvm",
"thread_pool",
"network",
"fs",
"transport",
"http",
"indices",
"process",
"breaker",
"_all"
],
"index_metric": [
"store",
"indexing",
"get",
"search",
"merge",
"flush",
"refresh",
"filter_cache",
"id_cache",
"fielddata",
"docs",
"warmer",
"percolate",
"completion",
"segments",
"translog",
"_all"
]
}
});
};
});

View file

@ -0,0 +1,503 @@
define(function () {
'use strict';
var SPAN_QUERIES = {
// TODO add one_of for objects
span_first: {
__scope_link: '.query.span_first'
},
span_near: {
__scope_link: '.query.span_near'
},
span_or: {
__scope_link: '.query.span_or'
},
span_not: {
__scope_link: '.query.span_not'
},
span_term: {
__scope_link: '.query.span_term'
}
};
return function init(api) {
api.addGlobalAutocompleteRules('query', {
match: {
__template: {
'FIELD': 'TEXT'
},
'$FIELD$': {
'query': '',
'operator': {
__one_of: ['and', 'or']
},
'type': {
__one_of: ['phrase', 'phrase_prefix', 'boolean']
},
'max_expansions': 10,
'analyzer': '',
'fuzziness': 1.0,
'prefix_length': 1
}
},
match_phrase: {
__template: {
'FIELD': 'PHRASE'
},
'$FIELD$': {
query: '',
analyzer: ''
}
},
match_phrase_prefix: {
__template: {
'FIELD': 'PREFIX'
},
'$FIELD$': {
query: '',
analyzer: '',
max_expansions: 10,
prefix_length: 1,
fuzziness: 0.1
}
},
multi_match: {
__template: {
'query': '',
'fields': []
},
query: '',
fields: ['$FIELD$'],
use_dis_max: {
__template: true,
__one_of: [true, false]
},
tie_breaker: 0.0
},
bool: {
must: [
{
__scope_link: 'GLOBAL.query'
}
],
must_not: [
{
__scope_link: 'GLOBAL.query'
}
],
should: [
{
__scope_link: 'GLOBAL.query'
}
],
minimum_number_should_match: 1,
boost: 1.0
},
boosting: {
positive: {
__scope_link: '.query'
},
negative: {
__scope_link: '.query'
},
negative_boost: 0.2
},
ids: {
type: '',
values: []
},
custom_score: {
__template: {
query: {},
script: ''
},
query: {},
script: '',
params: {},
lang: 'mvel'
},
custom_boost_factor: {
__template: {
query: {},
boost_factor: 1.1
},
query: {},
boost_factor: 1.1
},
constant_score: {
__template: {
filter: {},
boost: 1.2
},
query: {},
filter: {},
boost: 1.2
},
dis_max: {
__template: {
tie_breaker: 0.7,
boost: 1.2,
queries: []
},
tie_breaker: 0.7,
boost: 1.2,
queries: [
{
__scope_link: '.query'
}
]
},
field: {
'$FIELD$': {
query: '',
boost: 2.0,
enable_position_increments: {
__template: false,
__one_of: [true, false]
}
}
},
filtered: {
__template: {
query: {},
filter: {}
},
query: {},
filter: {}
},
fuzzy_like_this: {
fields: [],
like_text: '',
max_query_terms: 12
},
flt: {
__scope_link: '.query.fuzzy_like_this'
},
fuzzy: {
'$FIELD$': {
'value': '',
'boost': 1.0,
'min_similarity': 0.5,
'prefix_length': 0
}
},
has_child: {
'type': '$TYPE$',
'score_type': {
__one_of: ['none', 'max', 'sum', 'avg']
},
'_scope': '',
'query': {}
},
has_parent: {
'parent_type': '$TYPE$',
'score_type': {
__one_of: ['none', 'score']
},
'_scope': '',
'query': {}
},
match_all: {},
more_like_this: {
__template: {
'fields': ['FIELD'],
'like_text': 'text like this one',
'min_term_freq': 1,
'max_query_terms': 12
},
fields: ['$FIELD$ '],
like_text: '',
percent_terms_to_match: 0.3,
min_term_freq: 2,
max_query_terms: 25,
stop_words: [''],
min_doc_freq: 5,
max_doc_freq: 100,
min_word_len: 0,
max_word_len: 0,
boost_terms: 1,
boost: 1.0,
analyzer: ''
},
more_like_this_field: {
__template: {
'FIELD': {
'like_text': 'text like this one',
'min_term_freq': 1,
'max_query_terms': 12
}
},
'$FIELD$': {
like_text: '',
percent_terms_to_match: 0.3,
min_term_freq: 2,
max_query_terms: 25,
stop_words: [''],
min_doc_freq: 5,
max_doc_freq: 100,
min_word_len: 0,
max_word_len: 0,
boost_terms: 1,
boost: 1.0,
analyzer: ''
}
},
prefix: {
__template: {
'FIELD': {
'value': ''
}
},
'$FIELD$': {
value: '',
boost: 1.0
}
},
query_string: {
__template: {
'default_field': 'FIELD',
'query': 'this AND that OR thus'
},
query: '',
default_field: '$FIELD$',
fields: ['$FIELD$'],
default_operator: {
__one_of: ['OR', 'AND']
},
analyzer: '',
allow_leading_wildcard: {
__one_of: [true, false]
},
lowercase_expanded_terms: {
__one_of: [true, false]
},
enable_position_increments: {
__one_of: [true, false]
},
fuzzy_max_expansions: 50,
fuzzy_min_sim: 0.5,
fuzzy_prefix_length: 0,
phrase_slop: 0,
boost: 1.0,
analyze_wildcard: {
__one_of: [false, true]
},
auto_generate_phrase_queries: {
__one_of: [false, true]
},
minimum_should_match: '20%',
lenient: {
__one_of: [false, true]
},
use_dis_max: {
__one_of: [true, false]
},
tie_breaker: 0
},
range: {
__template: {
'FIELD': {
from: 10,
to: 20
}
},
'$FIELD$': {
__template: {
from: 10,
to: 20
},
from: 1,
to: 20,
include_lower: {
__one_of: [true, false]
},
include_upper: {
__one_of: [true, false]
},
boost: 1.0
}
},
span_first: {
__template: {
'match': {
'span_term': {
'FIELD': 'VALUE'
}
},
'end': 3
},
match: SPAN_QUERIES
},
span_near: {
__template: {
'clauses': [
{
span_term: {
'FIELD': {
'value': 'VALUE'
}
}
}
],
slop: 12,
in_order: false
},
clauses: [
SPAN_QUERIES
],
slop: 12,
in_order: {
__one_of: [false, true]
},
collect_payloads: {
__one_of: [false, true]
}
},
span_term: {
__template: {
'FIELD': {
'value': 'VALUE'
}
},
'$FIELD$': {
value: '',
boost: 2.0
}
},
span_not: {
__template: {
include: {
span_term: {
'FIELD': {
'value': 'VALUE'
}
}
},
exclude: {
span_term: {
'FIELD': {
'value': 'VALUE'
}
}
}
},
include: SPAN_QUERIES,
exclude: SPAN_QUERIES
},
span_or: {
__template: {
clauses: [
{
span_term: {
'FIELD': {
'value': 'VALUE'
}
}
}
]
},
clauses: [
SPAN_QUERIES
]
},
term: {
__template: {
'FIELD': {
value: 'VALUE'
}
},
'$FIELD$': {
value: '',
boost: 2.0
}
},
terms: {
__template: {
'FIELD': ['VALUE1', 'VALUE2']
},
'$FIELD$': [''],
minimum_match: 1
},
top_children: {
__template: {
type: 'CHILD_TYPE',
query: {}
},
type: '$CHILD_TYPE$',
query: {},
score: {
__one_of: ['max', 'sum', 'avg']
},
factor: 5,
incremental_factor: 2
},
wildcard: {
__template: {
'FIELD': {
value: 'VALUE'
}
},
'$FIELD$': {
value: '',
boost: 2.0
}
},
nested: {
__template: {
path: 'path_to_nested_doc',
query: {}
},
path: '',
query: {},
filter: {},
score_mode: {
__one_of: ['avg', 'total', 'max', 'none']
}
},
custom_filters_score: {
__template: {
query: {},
filters: [
{
filter: {}
}
]
},
query: {},
filters: [
{
filter: {},
boost: 2.0,
script: ''
}
],
score_mode: {
__one_of: ['first', 'min', 'max', 'total', 'avg', 'multiply']
},
max_boost: 2.0,
params: {},
lang: ''
},
indices: {
__template: {
indices: ['INDEX1', 'INDEX2'],
query: {}
},
indices: ['$INDEX$'],
query: {},
no_match_query: {
__scope_link: '.query'
}
},
geo_shape: {
__template: {
location: {},
relation: 'within'
},
__scope_link: '.filter.geo_shape'
}
});
};
});

View file

@ -0,0 +1,120 @@
define(function () {
'use strict';
return function init(api) {
api.addEndpointDescription('_search', {
methods: ['GET', 'POST'],
priority: 10, // collides with get doc by id
patterns: [
"{indices}/{types}/_search",
"{indices}/_search",
"_search"
],
url_params: {
q: "",
df: "",
analyzer: "",
default_operator: ["AND", "OR"],
explain: "__flag__",
_source: "",
_source_include: "",
_source_exclude: "",
fields: [],
sort: "",
track_scores: "__flag__",
timeout: 1,
from: 0,
size: 10,
search_type: ["dfs_query_then_fetch", "dfs_query_and_fetch", "query_then_fetch", "query_and_fetch", "count", "scan"],
lowercase_expanded_terms: ["true", "false"],
analyze_wildcard: "__flag__",
preference: ["_primary", "_primary_first", "_local", "_only_node:xyz", "_prefer_node:xyz", "_shards:2,3"],
scroll: "5m",
scroll_id: "",
routing: ""
},
data_autocomplete_rules: {
query: {
// populated by a global rule
},
facets: {
__template: {
'NAME': {
'TYPE': {}
}
}
// populated by a global rule
},
aggs: {
__template: {
"NAME": {
"AGG_TYPE": {
}
}
}
},
post_filter: {
__scope_link: 'GLOBAL.filter'
},
size: {
__template: 20
},
from: {},
sort: {
__template: [
{
'FIELD': {
'order': 'desc'
}
}
],
__any_of: [
{
'$FIELD$': {
'order': {
__one_of: ['desc', 'asc']
}
}
},
'$FIELD$',
'_score'
]
},
search_type: {},
fields: ['$FIELD$'],
script_fields: {
__template: {
'FIELD': {
'script': ''
}
},
'*': {
__scope_link: 'GLOBAL.SCRIPT_ENV'
}
},
partial_fields: {
__template: {
'NAME': {
include: []
}
},
'*': {
include: [],
exclude: []
}
},
highlight: {
// populated by a global rule
},
explain: {
__one_of: [true, false]
},
stats: ['']
}
});
};
});

View file

@ -0,0 +1,77 @@
define(function () {
'use strict';
return function init(api) {
api.addEndpointDescription('_get_settings', {
patterns: [
"{indices}/_settings",
"_settings"
]
});
api.addEndpointDescription('_put_settings', {
methods: ['PUT'],
patterns: [
"{indices}/_settings",
"_settings"
],
data_autocomplete_rules: {
index: {
refresh_interval: '1s',
number_of_shards: 5,
number_of_replicas: 1,
'blocks.read_only': {
__one_of: [false, true]
},
'blocks.read': {
__one_of: [true, false]
},
'blocks.write': {
__one_of: [true, false]
},
'blocks.metadata': {
__one_of: [true, false]
},
term_index_interval: 32,
term_index_divisor: 1,
'translog.flush_threshold_ops': 5000,
'translog.flush_threshold_size': '200mb',
'translog.flush_threshold_period': '30m',
'translog.disable_flush': {
__one_of: [true, false]
},
'cache.filter.max_size': '2gb',
'cache.filter.expire': '2h',
'gateway.snapshot_interval': '10s',
routing: {
allocation: {
include: {
tag: ''
},
exclude: {
tag: ''
},
require: {
tag: ''
},
total_shards_per_node: -1
}
},
'recovery.initial_shards': {
__one_of: ['quorum', 'quorum-1', 'half', 'full', 'full-1']
},
'ttl.disable_purge': {
__one_of: [true, false]
},
analysis: {
analyzer: {},
tokenizer: {},
filter: {},
char_filter: {}
}
}
}
});
};
});

View file

@ -0,0 +1,32 @@
define(function () {
'use strict';
return function init(api) {
api.addEndpointDescription('_delete_template', {
methods: ['DELETE'],
patterns: [
"_template/{id}",
]
});
api.addEndpointDescription('_get_template', {
methods: ['GET'],
patterns: [
"_template/{id}",
"_template",
]
});
api.addEndpointDescription('_put_template', {
methods: ['PUT'],
patterns: [
"_template/{id}",
],
data_autocomplete_rules: {
template: 'index*',
warmers: { __scope_link: '_warmer' },
mappings: {},
settings: {}
}
});
};
});

View file

@ -0,0 +1,37 @@
define(function () {
'use strict';
return function init(api) {
api.addEndpointDescription('_get_warmer', {
patterns: ["_warmer", "_warmer/{name}", "{indices}/_warmer", "{indices}/_warmer/{name}"]
});
api.addEndpointDescription('_delete_warmer', {
methods: ['DELETE'],
patterns: [
"{indices}/_warmer/{name}"
]
});
api.addEndpointDescription('_put_warmer', {
methods: ['PUT'],
patterns: [
"{indices}/_warmer/{name}",
"{indices}/{types}/_warmer/{name}"
],
data_autocomplete_rules: {
query: {
// populated by a global rule
},
facets: {
// populated by a global rule
},
aggs: {
},
sort: {
__scope_link: "_search.sort"
}
}
});
};
});

View file

@ -1,11 +1,11 @@
define([
'jquery',
'utils',
'es',
'_'
], function ($, utils, _) {
], function ($, utils, es, _) {
'use strict';
var currentServer;
var per_index_types = {};
var per_alias_indexes = [];
@ -143,6 +143,15 @@ define([
if (field_mapping["index_name"]) ret.name = field_mapping["index_name"];
if (field_mapping["fields"]) {
nested_fields = $.map(field_mapping['fields'], function (field_mapping, field_name) {
return getFieldNamesFromFieldMapping(field_name, field_mapping);
});
nested_fields = applyPathSettings(nested_fields);
nested_fields.unshift(ret);
return nested_fields;
}
return [ret];
}
@ -197,24 +206,15 @@ define([
}
function retrieveMappingFromServer() {
if (!currentServer) return;
utils.callES(currentServer, "_mapping", "GET", null, function (data, status, xhr) {
es.send("GET", "_mapping", null, function (data, status, xhr) {
loadMappings(data);
});
utils.callES(currentServer, "_aliases", "GET", null, function (data, status, xhr) {
es.send("GET", "_aliases", null, function (data, status, xhr) {
loadAliases(data);
});
}
function notifyServerChange(newServer) {
if (newServer.indexOf("://") < 0) newServer = "http://" + newServer;
newServer = newServer.trim("/");
if (newServer === currentServer) return; // already have it.
currentServer = newServer;
retrieveMappingFromServer();
}
function mapping_retriever() {
retrieveMappingFromServer();
setTimeout(function () {
@ -222,7 +222,11 @@ define([
}, 60000);
}
mapping_retriever();
es.addServerChangeListener(retrieveMappingFromServer);
function onInitComplete() {
mapping_retriever();
}
return {
getFields: getFields,
@ -232,7 +236,7 @@ define([
loadAliases: loadAliases,
expandAliases: expandAliases,
clear: clear,
notifyServerChange: notifyServerChange
onInitComplete: onInitComplete
};
});

View file

@ -4,16 +4,16 @@ define([
'input',
'mappings',
'output',
'es',
'bootstrap',
'jquery-ui'
], function ($, history, input, mappings, output) {
], function ($, history, input, mappings, output, es) {
'use strict';
var $esServer = $("#es_server");
$esServer.blur(function () {
mappings.notifyServerChange($esServer.val());
es.setBaseUrl($esServer.val());
});
// initialize auto complete
@ -58,6 +58,10 @@ define([
var $resizer = input.$el.siblings('.ui-resizable-e');
es.addServerChangeListener(function (server) {
$esServer.val(server);
});
return {
$esServer: $esServer,
$send: $send,
@ -65,4 +69,4 @@ define([
$header: $header,
$resizer: $resizer
};
})
});

View file

@ -5,8 +5,9 @@ define([
'jquery',
'sense_editor/row_parser',
'sense_editor/mode/sense',
'utils'
], function (_, ace, curl, $, RowParser, SenseMode, utils) {
'utils',
'es'
], function (_, ace, curl, $, RowParser, SenseMode, utils, es) {
'use strict';
function isInt(x) {
@ -79,7 +80,8 @@ define([
setTimeout(function check() {
if (session.bgTokenizer.running) {
timer = setTimeout(check, checkInterval);
} else {
}
else {
func.apply(self, args);
}
});
@ -104,7 +106,9 @@ define([
editor.autoIndent = onceDoneTokenizing(function () {
editor.getCurrentRequestRange(function (req_range) {
if (!req_range) return;
if (!req_range) {
return;
}
editor.getCurrentRequest(function (parsed_req) {
if (parsed_req.data && parsed_req.data.length > 0) {
var indent = parsed_req.data.length == 1; // unindent multi docs by default
@ -142,7 +146,13 @@ define([
editor.replaceRequestRange = function (newRequest, requestRange) {
var text = utils.textFromRequest(newRequest);
if (requestRange) {
var pos = editor.getCursorPosition();
editor.getSession().replace(requestRange, text);
var max_row = Math.max(requestRange.start.row + text.split('\n').length - 1, 0);
pos.row = Math.min(pos.row, max_row);
editor.moveCursorToPosition(pos);
// ACE UPGRADE - check if needed - at the moment the above may trigger a selection.
editor.clearSelection();
}
else {
// just insert where we are
@ -160,7 +170,9 @@ define([
};
editor.getCurrentRequestRange = onceDoneTokenizing(function (cb) {
if (typeof cb !== 'function') return;
if (typeof cb !== 'function') {
return;
}
if (editor.parser.isInBetweenRequestsRow(null)) {
cb(null);
@ -176,7 +188,9 @@ define([
});
editor.getCurrentRequest = onceDoneTokenizing(function (cb) {
if (typeof cb !== 'function') return;
if (typeof cb !== 'function') {
return;
}
if (editor.parser.isInBetweenRequestsRow(null)) {
cb(null);
return;
@ -198,7 +212,9 @@ define([
}
request.method = t.value;
t = editor.parser.nextNonEmptyToken(tokenIter);
if (!t || t.type == "method") return null;
if (!t || t.type == "method") {
return null;
}
request.url = "";
while (t && t.type && t.type.indexOf("url") == 0) {
request.url += t.value;
@ -251,8 +267,12 @@ define([
var maxLines = session.getLength();
for (; curRow < maxLines - 1; curRow++) {
var curRowMode = editor.parser.getRowParseMode(curRow, editor);
if ((curRowMode & RowParser.MODE_REQUEST_END) > 0) break;
if (curRow != pos.row && (curRowMode & RowParser.MODE_REQUEST_START) > 0) break;
if ((curRowMode & editor.parser.MODE.REQUEST_END) > 0) {
break;
}
if (curRow != pos.row && (curRowMode & editor.parser.MODE.REQUEST_START) > 0) {
break;
}
}
var column = (session.getLine(curRow) || "").length;
@ -270,8 +290,12 @@ define([
if ((curRowMode & RowParser.REQUEST_END) > 0) {
break;
}
if ((curRowMode & RowParser.MODE_MULTI_DOC_CUR_DOC_END) > 0) break;
if (curRow != pos.row && (curRowMode & RowParser.MODE_REQUEST_START) > 0) break;
if ((curRowMode & editor.parser.MODE.MULTI_DOC_CUR_DOC_END) > 0) {
break;
}
if (curRow != pos.row && (curRowMode & editor.parser.MODE.REQUEST_START) > 0) {
break;
}
}
var column = (session.getLine(curRow) || "").length;
@ -291,9 +315,13 @@ define([
editor.handleCURLPaste = function (text) {
var curlInput = curl.parseCURL(text);
if ($("#es_server").val()) curlInput.server = null; // do not override server
if ($("#es_server").val()) {
curlInput.server = null;
} // do not override server
if (!curlInput.method) curlInput.method = "GET";
if (!curlInput.method) {
curlInput.method = "GET";
}
editor.insert(utils.textFromRequest(curlInput));
};
@ -301,7 +329,9 @@ define([
editor.highlightCurrentRequestAndUpdateActionBar = onceDoneTokenizing(function () {
var session = editor.getSession();
editor.getCurrentRequestRange(function (new_current_req_range) {
if (new_current_req_range == null && CURRENT_REQ_RANGE == null) return;
if (new_current_req_range == null && CURRENT_REQ_RANGE == null) {
return;
}
if (new_current_req_range != null && CURRENT_REQ_RANGE != null &&
new_current_req_range.start.row == CURRENT_REQ_RANGE.start.row &&
new_current_req_range.end.row == CURRENT_REQ_RANGE.end.row
@ -329,21 +359,25 @@ define([
editor.getCurrentRequestAsCURL = function (cb) {
cb = typeof cb === 'function' ? cb : $.noop;
editor.getCurrentRequest(function (req) {
if (!req) return;
if (!req) {
return;
}
var es_server = $("#es_server").val(),
es_url = req.url,
var
es_path = req.url,
es_method = req.method,
es_data = req.data;
var url = utils.constructESUrl(es_server, es_url);
var url = es.constructESUrl(es_path);
var curl = 'curl -X' + es_method + ' "' + url + '"';
if (es_data && es_data.length) {
curl += " -d'\n";
// since Sense doesn't allow single quote json string any single qoute is within a string.
curl += es_data.join("\n").replace(/'/g, '\\"');
if (es_data.length > 1) curl += "\n"; // end with a new line
if (es_data.length > 1) {
curl += "\n";
} // end with a new line
curl += "'";
}
@ -363,7 +397,8 @@ define([
var set = function (top) {
if (top == null) {
editor.$actions.css('visibility', 'hidden');
} else {
}
else {
editor.$actions.css({
top: top,
visibility: 'visible'

View file

@ -13,7 +13,9 @@ define(['require', 'exports', 'module' , 'ace'], function (require, exports, mod
}
function addEOL(tokens, reg, nextIfEOL, normalNext) {
if (typeof reg == "object") reg = reg.source;
if (typeof reg == "object") {
reg = reg.source;
}
return [
{ token: tokens.concat(["whitespace"]), regex: reg + "(\\s*)$", next: nextIfEOL },
{ token: tokens, regex: reg, next: normalNext }
@ -41,33 +43,12 @@ define(['require', 'exports', 'module' , 'ace'], function (require, exports, mod
}
]),
"method_sep": mergeTokens(
addEOL(["whitespace", "url.slash"], /(\s+)(\/)/, "start", "indices"),
addEOL(["whitespace"], /(\s+)/, "start", "indices")
addEOL(["whitespace", "url.slash"], /(\s+)(\/)/, "start", "url"),
addEOL(["whitespace"], /(\s+)/, "start", "url")
),
"indices": mergeTokens(
addEOL(["url.scheme", "url.host", "url.slash"], /([^:]+:\/\/)([^?\/\s]*)(\/?)/, "start"),
addEOL(["url.index"], /(_all)/, "start"),
addEOL(["url.endpoint"], /(_[^\/?]+)/, "start", "urlRest"),
addEOL(["url.index"], /([^\/?,]+)/, "start"),
"url": mergeTokens(
addEOL(["url.part"], /([^?\/,]+)/, "start"),
addEOL(["url.comma"], /(,)/, "start"),
addEOL(["url.slash"], /(\/)/, "start", "types"),
addEOL(["url.questionmark"], /(\?)/, "start", "urlParams")
),
"types": mergeTokens(
addEOL(["url.endpoint"], /(_[^\/?]+)/, "start", "urlRest"),
addEOL(["url.type"], /([^\/?,]+)/, "start"),
addEOL(["url.comma"], /(,)/, "start"),
addEOL(["url.slash"], /(\/)/, "start", "id"),
addEOL(["url.questionmark"], /(\?)/, "start", "urlParams")
),
"id": mergeTokens(
addEOL(["url.endpoint"], /(_[^\/?]+)/, "start", "urlRest"),
addEOL(["url.id"], /([^\/?]+)/, "start"),
addEOL(["url.slash"], /(\/)/, "start", "urlRest"),
addEOL(["url.questionmark"], /(\?)/, "start", "urlParams")
),
"urlRest": mergeTokens(
addEOL(["url.part"], /([^?\/]+)/, "start"),
addEOL(["url.slash"], /(\/)/, "start"),
addEOL(["url.questionmark"], /(\?)/, "start", "urlParams")
),
@ -165,8 +146,9 @@ define(['require', 'exports', 'module' , 'ace'], function (require, exports, mod
]
}
if (this.constructor === SenseJsonHighlightRules)
if (this.constructor === SenseJsonHighlightRules) {
this.normalizeRules();
}
};
oop.inherits(SenseJsonHighlightRules, TextHighlightRules);

View file

@ -1,21 +1,39 @@
define([], function () {
'use strict';
var MODE = {
REQUEST_START: 2,
IN_REQUEST: 4,
MULTI_DOC_CUR_DOC_END: 8,
REQUEST_END: 16,
BETWEEN_REQUESTS: 32
};
function RowParser(editor) {
var defaultEditor = editor;
this.getRowParseMode = function (row) {
if (row == null || typeof row == "undefined") row = editor.getCursorPosition().row;
if (row == null || typeof row == "undefined") {
row = editor.getCursorPosition().row;
}
var session = editor.getSession();
if (row >= session.getLength()) return RowParser.MODE_BETWEEN_REQUESTS;
if (row >= session.getLength() || row < 0) {
return MODE.BETWEEN_REQUESTS;
}
var mode = session.getState(row);
if (!mode)
return RowParser.MODE_BETWEEN_REQUESTS; // shouldn't really happen
if (!mode) {
return MODE.BETWEEN_REQUESTS;
} // shouldn't really happen
if (mode !== "start") return RowParser.MODE_IN_REQUEST;
if (mode !== "start") {
return MODE.IN_REQUEST;
}
var line = (session.getLine(row) || "").trim();
if (!line || line[0] === '#') return RowParser.MODE_BETWEEN_REQUESTS; // empty line or a comment waiting for a new req to start
if (!line || line[0] === '#') {
return MODE.BETWEEN_REQUESTS;
} // empty line or a comment waiting for a new req to start
if (line.indexOf("}", line.length - 1) >= 0) {
// check for a multi doc request (must start a new json doc immediately after this one end.
@ -23,59 +41,59 @@ define([], function () {
if (row < session.getLength()) {
line = (session.getLine(row) || "").trim();
if (line.indexOf("{") === 0) { // next line is another doc in a multi doc
return RowParser.MODE_MULTI_DOC_CUR_DOC_END | RowParser.MODE_IN_REQUEST;
return MODE.MULTI_DOC_CUR_DOC_END | MODE.IN_REQUEST;
}
}
return RowParser.MODE_REQUEST_END | RowParser.MODE_MULTI_DOC_CUR_DOC_END; // end of request
return MODE.REQUEST_END | MODE.MULTI_DOC_CUR_DOC_END; // end of request
}
// check for single line requests
row++;
if (row >= session.getLength()) {
return RowParser.MODE_REQUEST_START | RowParser.MODE_REQUEST_END;
return MODE.REQUEST_START | MODE.REQUEST_END;
}
line = (session.getLine(row) || "").trim();
if (line.indexOf("{") !== 0) { // next line is another request
return RowParser.MODE_REQUEST_START | RowParser.MODE_REQUEST_END;
return MODE.REQUEST_START | MODE.REQUEST_END;
}
return RowParser.MODE_REQUEST_START;
}
return MODE.REQUEST_START;
};
this.rowPredicate = function (row, editor, value) {
var mode = this.getRowParseMode(row, editor);
return (mode & value) > 0;
}
};
this.isEndRequestRow = function (row, _e) {
var editor = _e || defaultEditor;
return this.rowPredicate(row, editor, RowParser.MODE_REQUEST_END);
return this.rowPredicate(row, editor, MODE.REQUEST_END);
};
this.isRequestEdge = function (row, _e) {
var editor = _e || defaultEditor;
return this.rowPredicate(row, editor, RowParser.MODE_REQUEST_END | RowParser.MODE_REQUEST_START);
return this.rowPredicate(row, editor, MODE.REQUEST_END | MODE.REQUEST_START);
};
this.isStartRequestRow = function (row, _e) {
var editor = _e || defaultEditor;
return this.rowPredicate(row, editor, RowParser.MODE_REQUEST_START);
return this.rowPredicate(row, editor, MODE.REQUEST_START);
};
this.isInBetweenRequestsRow = function (row, _e) {
var editor = _e || defaultEditor;
return this.rowPredicate(row, editor, RowParser.MODE_BETWEEN_REQUESTS);
return this.rowPredicate(row, editor, MODE.BETWEEN_REQUESTS);
};
this.isInRequestsRow = function (row, _e) {
var editor = _e || defaultEditor;
return this.rowPredicate(row, editor, RowParser.MODE_IN_REQUEST);
return this.rowPredicate(row, editor, MODE.IN_REQUEST);
};
this.isMultiDocDocEndRow = function (row, _e) {
var editor = _e || defaultEditor;
return this.rowPredicate(row, editor, RowParser.MODE_MULTI_DOC_CUR_DOC_END);
return this.rowPredicate(row, editor, MODE.MULTI_DOC_CUR_DOC_END);
};
this.isEmptyToken = function (tokenOrTokenIter) {
@ -103,11 +121,7 @@ define([], function () {
};
}
RowParser.MODE_REQUEST_START = 2;
RowParser.MODE_IN_REQUEST = 4;
RowParser.MODE_MULTI_DOC_CUR_DOC_END = 8;
RowParser.MODE_REQUEST_END = 16;
RowParser.MODE_BETWEEN_REQUESTS = 32;
RowParser.prototype.MODE = MODE;
return RowParser;
})
});

View file

@ -20,7 +20,7 @@ define([
return results == null ? "" : decodeURIComponent(results[1].replace(/\+/g, " "));
};
utils.jsonToString = function(data, indent) {
utils.jsonToString = function (data, indent) {
return JSON.stringify(data, null, indent ? 2 : 0);
};
@ -46,41 +46,6 @@ define([
};
};
utils.callES = function (server, url, method, data, successCallback, completeCallback) {
url = utils.constructESUrl(server, url);
var uname_password_re = /^(https?:\/\/)?(?:(?:([^\/]*):)?([^\/]*?)@)?(.*)$/;
var url_parts = url.match(uname_password_re);
var uname = url_parts[2];
var password = url_parts[3];
url = url_parts[1] + url_parts[4];
console.log("Calling " + url + " (uname: " + uname + " pwd: " + password + ")");
if (data && method == "GET") method = "POST";
$.ajax({
url: url,
data: method == "GET" ? null : data,
password: password,
cache: false,
username: uname,
crossDomain: true,
type: method,
dataType: "json",
complete: completeCallback,
success: successCallback
});
};
utils.constructESUrl = function (server, url) {
if (url.indexOf("://") >= 0) return url;
if (server.indexOf("://") < 0) server = "http://" + server;
if (server.substr(-1) == "/") {
server = server.substr(0, server.length - 1);
}
if (url.charAt(0) === "/") url = url.substr(1);
return server + "/" + url;
};
return utils;
});

View file

@ -15,7 +15,7 @@
<span class="brand" id="server_label">Server</span>
<form class="navbar-form pull-left">
<input id="es_server" type="text" class="span5" value="localhost:9200"/>
<input id="es_server" type="text" class="span5" value=""/>
</form>
<span class="pull-left btn btn-link"><span id="notification" style="visibility: hidden"
class="label label-info"></span></span>
@ -44,7 +44,7 @@
<div id="main" class="container-fluid">
<div id="editor_container">
<div id="editor">GET _search
{
{
"query": { "match_all": {} }
}</div>
<div id="editor_actions">

View file

@ -15,6 +15,7 @@
z-index: 200;
border: 1px solid #333;
}
#output_container {
display: none;
position: absolute;
@ -25,52 +26,60 @@
z-index: 201;
border: 1px solid #333;
}
#editor, #output {
height: 100%;
width: 100%;
position: relative;
}
</style>
</style>
</head>
<body>
<div id="qunit"></div>
<div id="editor_container"><div id="editor"></div></div>
<div id="output_container"><div id="output"></div></div>
<div id="editor_container">
<div id="editor"></div>
</div>
<div id="output_container">
<div id="output"></div>
</div>
<script src="../vendor/require/require.js"></script>
<script src="../app/require.config.js"></script>
<script src="lib/qunit-1.10.0.js"></script>
<script>
/* global QUnit */
QUnit.config.autostart = false;
/* global QUnit */
QUnit.config.autostart = false;
require.config({
baseUrl: '../app'
});
require(["require","ace"], function (require) {
require.config({
baseUrl: '../app'
});
require(["require", "ace"], function (require) {
'use strict';
'use strict';
var tests = [
'../tests/src/curl_tests.js',
'../tests/src/kb_tests.js',
'../tests/src/mapping_tests.js',
'../tests/src/editor_tests.js',
'../tests/src/tokenization_tests.js',
'../tests/src/integration_tests.js'
];
var tests = [
'../tests/src/url_autocomplete_tests.js',
'../tests/src/url_params_tests.js',
'../tests/src/curl_tests.js',
'../tests/src/kb_tests.js',
'../tests/src/mapping_tests.js',
'../tests/src/editor_tests.js',
'../tests/src/tokenization_tests.js',
'../tests/src/integration_tests.js'
];
// load the tests in series
(function next(){
if (tests.length) {
require(tests.splice(0, 1), next);
} else {
console.log('all tests loaded');
QUnit.start();
}
}());
// load the tests in series
(function next() {
if (tests.length) {
require(tests.splice(0, 1), next);
}
else {
console.log('all tests loaded');
QUnit.start();
}
}());
});
});
</script>
</body>
</html>

View file

@ -36,16 +36,19 @@ define([
mappings.clear();
mappings.loadMappings(mapping);
var test_api = new api.Api();
var test_api = new api.Api('test', kb._test.globalUrlComponentFactories);
if (kb_schemes) {
if (kb_schemes.globals)
if (kb_schemes.globals) {
$.each(kb_schemes.globals, function (parent, rules) {
test_api.addGlobalAutocompleteRules(parent, rules);
});
if (kb_schemes.endpoints)
}
if (kb_schemes.endpoints) {
$.each(kb_schemes.endpoints, function (endpoint, scheme) {
_.defaults(scheme, { methods: null }); // disable method testing unless specified in test
test_api.addEndpointDescription(endpoint, scheme);
});
}
}
kb.setActiveApi(test_api);
@ -56,74 +59,80 @@ define([
setTimeout(function () {
input.completer = {
base: {},
changeListener : function () {}
changeListener: function () {
}
}; // mimic auto complete
input.autocomplete.completer.getCompletions(input, input.getSession(), test.cursor, "",
function (err, terms) {
input.autocomplete._test.getCompletions(input, input.getSession(), test.cursor, "",
function (err, terms) {
if (test.no_context) {
ok(!terms || terms.length === 0, "Expected no context bug got terms.");
}
else {
ok(terms && terms.length > 0, "failed to extract terms ...");
}
if (!terms || terms.length === 0) {
start();
return;
}
if (test["autoCompleteSet"]) {
var expected_terms = _.map(test["autoCompleteSet"], function (t) {
if (typeof t !== "object") {
t = { "name": t };
}
return t;
});
if (terms.length != expected_terms.length) {
equal(_.pluck(terms, 'name'), _.pluck(expected_terms, 'name'), "list of completion terms is not of equal size");
} else {
var filtered_actual_terms = _.map(terms, function (actual_term,i) {
var expected_term = expected_terms[i];
var filtered_term = {};
_.each(expected_term, function (v,p) { filtered_term[p] = actual_term[p]; });
return filtered_term;
});
deepEqual(filtered_actual_terms, expected_terms);
if (test.no_context) {
ok(!terms || terms.length === 0, "Expected no context bug got terms.");
}
else {
ok(terms && terms.length > 0, "failed to extract terms ...");
}
}
var context = terms[0].context;
input.autocomplete._test.addReplacementInfoToContext(context, test.cursor, terms[0].value);
if (!terms || terms.length === 0) {
start();
return;
}
function ac(prop, prop_test) {
if (typeof test[prop] != "undefined")
if (prop_test)
prop_test(context[prop], test[prop], prop);
else
deepEqual(context[prop], test[prop], 'context.' + prop + ' should equal ' + JSON.stringify(test[prop]));
}
function pos_compare(actual, expected, name) {
equal(actual.row, expected.row + rowOffset, "row of " + name + " position is not as expected");
equal(actual.column, expected.column, "column of " + name + " position is not as expected");
}
if (test["autoCompleteSet"]) {
var expected_terms = _.map(test["autoCompleteSet"], function (t) {
if (typeof t !== "object") {
t = { "name": t };
}
return t;
});
if (terms.length != expected_terms.length) {
equal(_.pluck(terms, 'name'), _.pluck(expected_terms, 'name'), "list of completion terms is not of equal size");
}
else {
var filtered_actual_terms = _.map(terms, function (actual_term, i) {
var expected_term = expected_terms[i];
var filtered_term = {};
_.each(expected_term, function (v, p) {
filtered_term[p] = actual_term[p];
});
return filtered_term;
});
deepEqual(filtered_actual_terms, expected_terms);
}
}
function range_compare(actual, expected, name) {
pos_compare(actual.start, expected.start, name + ".start");
pos_compare(actual.end, expected.end, name + ".end");
}
var context = terms[0].context;
input.autocomplete._test.addReplacementInfoToContext(context, test.cursor, terms[0].value);
ac("prefixToAdd");
ac("suffixToAdd");
ac("addTemplate");
ac("textBoxPosition", pos_compare);
ac("rangeToReplace", range_compare);
function ac(prop, prop_test) {
if (typeof test[prop] != "undefined") {
if (prop_test) {
prop_test(context[prop], test[prop], prop);
}
else {
deepEqual(context[prop], test[prop], 'context.' + prop + ' should equal ' + JSON.stringify(test[prop]));
}
}
}
start();
});
function pos_compare(actual, expected, name) {
equal(actual.row, expected.row + rowOffset, "row of " + name + " position is not as expected");
equal(actual.column, expected.column, "column of " + name + " position is not as expected");
}
function range_compare(actual, expected, name) {
pos_compare(actual.start, expected.start, name + ".start");
pos_compare(actual.end, expected.end, name + ".end");
}
ac("prefixToAdd");
ac("suffixToAdd");
ac("addTemplate");
ac("textBoxPosition", pos_compare);
ac("rangeToReplace", range_compare);
start();
});
});
});
@ -131,7 +140,9 @@ define([
}
function context_tests(data, mapping, kb_schemes, request_line, tests) {
if (data != null && typeof data != "string") data = JSON.stringify(data, null, 3);
if (data != null && typeof data != "string") {
data = JSON.stringify(data, null, 3);
}
for (var t = 0; t < tests.length; t++) {
process_context_test(data, mapping, kb_schemes, request_line, tests[t]);
}
@ -140,6 +151,11 @@ define([
var SEARCH_KB = {
endpoints: {
_search: {
patterns: [
"{indices}/{types}/_search",
"{indices}/_search",
"_search"
],
data_autocomplete_rules: {
query: { match_all: {}, term: { "$FIELD$": ""}},
size: {},
@ -307,17 +323,22 @@ define([
"object": 1,
"array": 1,
"value_one_of": 1,
"value": 2
"value": 2,
"something_else": 5
},
MAPPING,
{
endpoints: {
_test: {
patterns: [
"_test"
],
data_autocomplete_rules: {
object: { bla: 1 },
array: [ 1 ],
value_one_of: { __one_of: [ 1, 2]},
value: 3
value: 3,
"*": { __one_of: [ 4, 5]}
}
}
}
@ -347,7 +368,13 @@ define([
cursor: { row: 4, column: 12},
initialValue: "",
autoCompleteSet: [ 3 ]
}
},
{
name: "matching any value with one_of",
cursor: { row: 5, column: 21},
initialValue: "",
autoCompleteSet: [ 4, 5]
},
]
);
@ -373,7 +400,9 @@ define([
prefixToAdd: "",
suffixToAdd: "",
rangeToReplace: { start: { row: 5, column: 15 }, end: { row: 5, column: 15 }},
autoCompleteSet: [{ name: "terms", meta: "API" }]
autoCompleteSet: [
{ name: "terms", meta: "API" }
]
}
]
);
@ -386,6 +415,9 @@ define([
{
endpoints: {
_test: {
patterns: [
"_test"
],
data_autocomplete_rules: {
index: "$INDEX$"
}
@ -397,7 +429,10 @@ define([
{
name: "$INDEX$ matching",
cursor: { row: 1, column: 15},
autoCompleteSet: [{ name: "index1", meta: "index"}, { name: "index2", meta: "index"}]
autoCompleteSet: [
{ name: "index1", meta: "index"},
{ name: "index2", meta: "index"}
]
}
]
);
@ -417,6 +452,9 @@ define([
{
endpoints: {
_endpoint: {
patterns: [
"_endpoint"
],
data_autocomplete_rules: {
array: [ "a", "b"],
number: 1,
@ -433,7 +471,7 @@ define([
name: "Templates 1",
cursor: { row: 1, column: 0},
autoCompleteSet: [
tt("array", [ "a" ]), tt("fixed", { a: 1 }), tt("number",1), tt("object", {}), tt("oneof", "o1")
tt("array", [ "a" ]), tt("fixed", { a: 1 }), tt("number", 1), tt("object", {}), tt("oneof", "o1")
]
},
{
@ -460,6 +498,9 @@ define([
{
endpoints: {
_endpoint: {
patterns: [
"_endpoint"
],
data_autocomplete_rules: {
any_of_numbers: { __template: [1, 2], __any_of: [1, 2, 3]},
any_of_obj: { __template: [
@ -478,9 +519,11 @@ define([
name: "Any of - templates",
cursor: { row: 1, column: 0},
autoCompleteSet: [
tt("any_of_numbers", [ 1, 2 ]),
tt("any_of_obj", [ { c: 1} ])
]
tt("any_of_numbers", [ 1, 2 ]),
tt("any_of_obj", [
{ c: 1}
])
]
},
{
name: "Any of - numbers",
@ -491,7 +534,7 @@ define([
name: "Any of - object",
cursor: { row: 6, column: 2},
autoCompleteSet: [
tt("a", 1),tt("b", 2 )
tt("a", 1), tt("b", 2)
]
}
]
@ -503,6 +546,7 @@ define([
{
endpoints: {
_endpoint: {
patterns: [ "_endpoint" ],
data_autocomplete_rules: {
"query": ""
}
@ -514,7 +558,7 @@ define([
{
name: "Empty string as default",
cursor: { row: 0, column: 1},
autoCompleteSet: [tt("query","")]
autoCompleteSet: [tt("query", "")]
}
]
);
@ -540,8 +584,8 @@ define([
},
endpoints: {
_current: {
_id: "POST _current",
patterns: [ "_current" ],
id: "POST _current",
data_autocomplete_rules: {
"a": {
"b": {
@ -565,6 +609,7 @@ define([
}
},
ext: {
patterns: [ "ext" ],
data_autocomplete_rules: {
target: {
t2: 1
@ -578,8 +623,10 @@ define([
{
name: "Relative scope link test",
cursor: { row: 2, column: 12},
autoCompleteSet:[
tt("b", {}), tt("c", {}), tt("d", {}), tt("e", {}), tt("f", [ {} ])
autoCompleteSet: [
tt("b", {}), tt("c", {}), tt("d", {}), tt("e", {}), tt("f", [
{}
])
]
},
{
@ -613,6 +660,7 @@ define([
{
endpoints: {
_endpoint: {
patterns: ["_endpoint"],
data_autocomplete_rules: {
"a": {},
"b": {}
@ -658,6 +706,7 @@ define([
{
endpoints: {
_endpoint: {
patterns: ["_endpoint"],
data_autocomplete_rules: {
"a": [
{ b: 1}
@ -718,10 +767,10 @@ define([
context_tests(
"",
"POST _search",
MAPPING,
SEARCH_KB,
"POST _search",
null,
[
{
name: "initial doc start",
@ -764,15 +813,22 @@ define([
var CLUSTER_KB = {
endpoints: {
"_search": {
patterns: ["_search", "{indices}/{types}/_search", "{indices}/_search"],
url_params: {
"search_type": ["count", "query_then_fetch" ],
"scroll": "10m"
},
data_autocomplete_rules: {
}
},
"_cluster/stats": {
patterns: ["_cluster/stats"],
indices_mode: "none",
data_autocomplete_rules: {
}
},
"_cluster/nodes/stats": {
patterns: ["_cluster/nodes/stats"],
data_autocomplete_rules: {
}
}
@ -788,7 +844,7 @@ define([
{
name: "Endpoints with slashes - no slash",
cursor: { row: 0, column: 8},
autoCompleteSet: [ "_cluster/nodes/stats", "_cluster/stats", "_search"],
autoCompleteSet: [ "_cluster/nodes/stats", "_cluster/stats", "_search", "index1", "index2"],
prefixToAdd: "",
suffixToAdd: ""
}
@ -804,14 +860,21 @@ define([
{
name: "Endpoints with slashes - before slash",
cursor: { row: 0, column: 8},
autoCompleteSet: [ "_cluster/nodes/stats", "_cluster/stats", "_search"],
autoCompleteSet: [ "_cluster/nodes/stats", "_cluster/stats", "_search", "index1", "index2"],
prefixToAdd: "",
suffixToAdd: ""
},
{
name: "Endpoints with slashes - on slash",
cursor: { row: 0, column: 13},
autoCompleteSet: [ "_cluster/nodes/stats", "_cluster/stats", "_search"],
autoCompleteSet: [ "_cluster/nodes/stats", "_cluster/stats", "_search", "index1", "index2"],
prefixToAdd: "",
suffixToAdd: ""
},
{
name: "Endpoints with slashes - after slash",
cursor: { row: 0, column: 14},
autoCompleteSet: [ "nodes/stats", "stats"],
prefixToAdd: "",
suffixToAdd: ""
}
@ -827,7 +890,10 @@ define([
{
name: "Endpoints with slashes - after slash",
cursor: { row: 0, column: 15},
autoCompleteSet: [ { name: "nodes/stats", meta: "endpoint" } , { name: "stats", meta: "endpoint" } ],
autoCompleteSet: [
{ name: "nodes/stats", meta: "endpoint" } ,
{ name: "stats", meta: "endpoint" }
],
prefixToAdd: "",
suffixToAdd: "",
initialValue: "no"
@ -852,6 +918,29 @@ define([
]
);
context_tests(
null,
MAPPING,
CLUSTER_KB,
"POST ",
[
{
name: "Immediately after space + method",
cursor: { row: 0, column: 5},
autoCompleteSet: [
{ name: "_cluster/nodes/stats", meta: "endpoint" },
{ name: "_cluster/stats", meta: "endpoint" },
{ name: "_search", meta: "endpoint" },
{ name: "index1", meta: "index" },
{ name: "index2", meta: "index" }
],
prefixToAdd: "",
suffixToAdd: "",
initialValue: ""
}
]
);
context_tests(
null,
MAPPING,
@ -874,4 +963,160 @@ define([
}
]
);
context_tests(
null,
MAPPING,
CLUSTER_KB,
"POST cl",
[
{
name: "Endpoints by subpart",
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" }
],
prefixToAdd: "",
suffixToAdd: "",
initialValue: "cl"
}
]
);
context_tests(
null,
MAPPING,
CLUSTER_KB,
"GET _search?",
[
{
name: "Params just after ?",
cursor: { row: 0, column: 12},
autoCompleteSet: [
{ name: "format", meta: "param", "insert_value": "format=" },
{ name: "pretty", meta: "flag" },
{ name: "scroll", meta: "param", "insert_value": "scroll=" },
{ name: "search_type", meta: "param", "insert_value": "search_type=" },
],
prefixToAdd: "",
suffixToAdd: ""
}
]
);
context_tests(
null,
MAPPING,
CLUSTER_KB,
"GET _search?format=",
[
{
name: "Params values",
cursor: { row: 0, column: 19},
autoCompleteSet: [
{ name: "json", meta: "format" },
{ name: "yaml", meta: "format" }
],
prefixToAdd: "",
suffixToAdd: ""
}
]
);
context_tests(
null,
MAPPING,
CLUSTER_KB,
"GET _search?format=yaml&",
[
{
name: "Params after amp",
cursor: { row: 0, column: 24},
autoCompleteSet: [
{ name: "format", meta: "param", "insert_value": "format=" },
{ name: "pretty", meta: "flag" },
{ name: "scroll", meta: "param", "insert_value": "scroll=" },
{ name: "search_type", meta: "param", "insert_value": "search_type=" },
],
prefixToAdd: "",
suffixToAdd: ""
}
]
);
context_tests(
null,
MAPPING,
CLUSTER_KB,
"GET _search?format=yaml&search",
[
{
name: "Params on existing param",
cursor: { row: 0, column: 26},
rangeToReplace: {
start: { row: 0, column: 24},
end: { row: 0, column: 30}
},
autoCompleteSet: [
{ name: "format", meta: "param", "insert_value": "format=" },
{ name: "pretty", meta: "flag" },
{ name: "scroll", meta: "param", "insert_value": "scroll=" },
{ name: "search_type", meta: "param", "insert_value": "search_type=" },
],
prefixToAdd: "",
suffixToAdd: ""
}
]
);
context_tests(
null,
MAPPING,
CLUSTER_KB,
"GET _search?format=yaml&search_type=cou",
[
{
name: "Params on existing value",
cursor: { row: 0, column: 37},
rangeToReplace: {
start: { row: 0, column: 36},
end: { row: 0, column: 39}
},
autoCompleteSet: [
{ name: "count", meta: "search_type" },
{ name: "query_then_fetch", meta: "search_type" },
],
prefixToAdd: "",
suffixToAdd: ""
}
]
);
context_tests(
null,
MAPPING,
CLUSTER_KB,
"GET _search?format=yaml&search_type=cou",
[
{
name: "Params on just after = with existing value",
cursor: { row: 0, column: 36},
rangeToReplace: {
start: { row: 0, column: 36},
end: { row: 0, column: 36}
},
autoCompleteSet: [
{ name: "count", meta: "search_type" },
{ name: "query_then_fetch", meta: "search_type" },
],
prefixToAdd: "",
suffixToAdd: ""
}
]
);
});

View file

@ -1,8 +1,9 @@
define([
'kb',
'mappings',
'kb/api'
], function (kb, mappings, api) {
'kb/api',
'autocomplete/engine'
], function (kb, mappings, api, autocomplete_engine) {
'use strict';
module("Knowledge base", {
@ -16,102 +17,160 @@ define([
}
});
var MAPPING = {
"index1": {
"type1.1": {
"properties": {
"field1.1.1": { "type": "string" },
"field1.1.2": { "type": "string" }
}
},
"type1.2": {
"properties": {
}
}
},
"index2": {
"type2.1": {
"properties": {
"field2.1.1": { "type": "string" },
"field2.1.2": { "type": "string" }
}
}
}
};
test("Index mode filters", function () {
var test_api = new api.Api();
test_api.addEndpointDescription("_multi_indices", {
indices_mode: "multi"
});
test_api.addEndpointDescription("_one_or_more_indices", {
indices_mode: "required_multi"
});
test_api.addEndpointDescription("_single_index", {
match: "_single_index",
endpoint_autocomplete: [
"_single_index"
],
indices_mode: "single"
});
test_api.addEndpointDescription("_no_index", {
indices_mode: "none"
});
kb.setActiveApi(test_api);
function testContext(tokenPath, otherTokenValues, expectedContext) {
deepEqual(kb.getEndpointAutocomplete([], [], null).sort(), ["_multi_indices", "_no_index" ]);
deepEqual(kb.getEndpointAutocomplete(["index"], [], null).sort(), ["_multi_indices", "_one_or_more_indices", "_single_index"]);
deepEqual(kb.getEndpointAutocomplete(["index1", "index2"], [], null).sort(), ["_multi_indices", "_one_or_more_indices"]);
deepEqual(kb.getEndpointAutocomplete(["index1", "index2"], ["type"], null).sort(), ["_multi_indices", "_one_or_more_indices"]);
});
if (expectedContext.autoCompleteSet) {
expectedContext.autoCompleteSet = _.map(expectedContext.autoCompleteSet, function (t) {
if (_.isString(t)) {
t = { name: t}
}
return t;
})
}
test("Type mode filters", function () {
var test_api = new api.Api();
var context = { otherTokenValues: otherTokenValues};
autocomplete_engine.populateContext(tokenPath, context, null,
expectedContext.autoCompleteSet, kb.getTopLevelUrlCompleteComponents()
);
test_api.addEndpointDescription("_multi_types", {
indices_mode: "single",
types_mode: "multi"
// override context to just check on id
if (context.endpoint) {
context.endpoint = context.endpoint.id;
}
delete context.otherTokenValues;
function norm(t) {
if (_.isString(t)) {
return { name: t };
}
return t;
}
if (context.autoCompleteSet) {
context.autoCompleteSet = _.sortBy(_.map(context.autoCompleteSet, norm), 'name');
}
if (expectedContext.autoCompleteSet) {
expectedContext.autoCompleteSet = _.sortBy(_.map(expectedContext.autoCompleteSet, norm), 'name');
}
deepEqual(context, expectedContext);
}
function t(term) {
return { name: term, meta: "type"};
}
function i(term) {
return { name: term, meta: "index"};
}
function index_test(name, tokenPath, otherTokenValues, expectedContext) {
test(name, function () {
var test_api = new api.Api("text", kb._test.globalUrlComponentFactories);
test_api.addEndpointDescription("_multi_indices", {
patterns: ["{indices}/_multi_indices"]
});
test_api.addEndpointDescription("_single_index", {
patterns: ["{index}/_single_index"]
});
test_api.addEndpointDescription("_no_index", {
// testing default patterns
// patterns: ["_no_index"]
});
kb.setActiveApi(test_api);
mappings.loadMappings(MAPPING);
testContext(tokenPath, otherTokenValues, expectedContext);
});
test_api.addEndpointDescription("_single_type", {
endpoint_autocomplete: [
"_single_type"
],
indices_mode: "single",
types_mode: "single"
});
test_api.addEndpointDescription("_no_types", {
indices_mode: "single",
types_mode: "none"
}
index_test("Index integration 1", [], [],
{ autoCompleteSet: ["_no_index", i("index1"), i("index2")]}
);
index_test("Index integration 2", [], ["index1"],
// still return _no_index as index1 is not committed to yet.
{ autoCompleteSet: ["_no_index", i("index2")]}
);
index_test("Index integration 2", ["index1"], [],
{ indices: ["index1"], autoCompleteSet: ["_multi_indices", "_single_index"]}
);
index_test("Index integration 2", [
["index1", "index2"]
], [],
{ indices: ["index1", "index2"], autoCompleteSet: ["_multi_indices"]}
);
function type_test(name, tokenPath, otherTokenValues, expectedContext) {
test(name, function () {
var test_api = new api.Api("type_test", kb._test.globalUrlComponentFactories);
test_api.addEndpointDescription("_multi_types", {
patterns: ["{indices}/{types}/_multi_types"]
});
test_api.addEndpointDescription("_single_type", {
patterns: ["{indices}/{type}/_single_type"]
});
test_api.addEndpointDescription("_no_types", {
patterns: ["{indices}/_no_types"]
});
kb.setActiveApi(test_api);
mappings.loadMappings(MAPPING);
testContext(tokenPath, otherTokenValues, expectedContext);
});
kb.setActiveApi(test_api);
}
type_test("Type integration 1", ["index1"], [],
{ indices: ["index1"], autoCompleteSet: ["_no_types", t("type1.1"), t("type1.2")]}
);
type_test("Type integration 2", ["index1"], ["type1.2"],
// we are not yet comitted to type1.2, so _no_types is returned
{ indices: ["index1"], autoCompleteSet: ["_no_types", t("type1.1")]}
);
deepEqual(kb.getEndpointAutocomplete(["index"], [], null).sort(), ["_multi_types", "_no_types" ]);
deepEqual(kb.getEndpointAutocomplete(["index"], ["type"], null).sort(), ["_multi_types", "_single_type"]);
deepEqual(kb.getEndpointAutocomplete(["index"], ["type", "type1"], null).sort(), ["_multi_types"]);
});
type_test("Type integration 3", ["index2"], [],
{ indices: ["index2"], autoCompleteSet: ["_no_types", t("type2.1")]}
);
test("Id mode filters", function () {
var test_api = new api.Api();
type_test("Type integration 4", ["index1", "type1.2"], [],
{ indices: ["index1"], types: ["type1.2"], autoCompleteSet: ["_multi_types", "_single_type"]}
);
test_api.addEndpointDescription("_single_id", {
indices_mode: "single",
types_mode: "single",
doc_id_mode: "required_single"
});
test_api.addEndpointDescription("_no_id", {
indices_mode: "single",
types_mode: "single",
doc_id_mode: "none"
type_test("Type integration 5", [
["index1", "index2"],
["type1.2", "type1.1"]
], [],
{ indices: ["index1", "index2"], types: ["type1.2", "type1.1"], autoCompleteSet: ["_multi_types"]}
);
});
kb.setActiveApi(test_api);
deepEqual(kb.getEndpointAutocomplete(["index"], ["type"], null).sort(), ["_no_id"].sort());
deepEqual(kb.getEndpointAutocomplete(["index"], ["type"], "123").sort(), ["_single_id"].sort());
});
test("Get active scheme by doc id", function () {
var test_api = new api.Api();
test_api.addEndpointDescription("_single_id", {
match: ".*",
indices_mode: "single",
types_mode: "single",
doc_id_mode: "required_single"
});
test_api.addEndpointDescription("_no_id", {
match: ".*",
indices_mode: "single",
types_mode: "single",
doc_id_mode: "none"
});
kb.setActiveApi(test_api);
deepEqual(kb.getEndpointDescriptionByPath("bla", ["index"], ["type"], null).doc_id_mode, "none");
deepEqual(kb.getEndpointDescriptionByPath("bla", ["index"], ["type"], "123").doc_id_mode, "required_single");
});
});

View file

@ -52,6 +52,33 @@ define([
f("any_name", "string"), f("first_name", "string"), f("last_name", "string")]);
});
test("Multi fields 1.0 style", function () {
mappings.loadMappings({
"index": {
"tweet": {
"properties": {
"first_name": {
"type": "string", "index": "analyzed",
"path": "just_name",
"fields": {
"any_name": {"type": "string", "index": "analyzed"}
}
},
"last_name": {
"type": "string", "index": "no",
"fields": {
"raw": {"type": "string", "index": "analyzed"}
}
}
}
}
}
});
deepEqual(mappings.getFields("index").sort(fc), [
f("any_name", "string"), f("first_name", "string"), f("last_name", "string"), f("last_name.raw", "string")]);
});
test("Simple fields", function () {
mappings.loadMappings({
"index": {

View file

@ -22,7 +22,9 @@ define([
var iter = new token_iterator.TokenIterator(input.getSession(), 0, 0);
var ret = [];
var t = iter.getCurrentToken();
if (input.parser.isEmptyToken(t)) t = input.parser.nextNonEmptyToken(iter);
if (input.parser.isEmptyToken(t)) {
t = input.parser.nextNonEmptyToken(iter);
}
while (t) {
ret.push({ value: t.value, type: t.type });
t = input.parser.nextNonEmptyToken(iter);
@ -34,10 +36,15 @@ define([
var testCount = 0;
function token_test(token_list, prefix, data) {
if (data && typeof data != "string") data = JSON.stringify(data, null, 3);
if (data && typeof data != "string") {
data = JSON.stringify(data, null, 3);
}
if (data) {
if (prefix) data = prefix + "\n" + data;
} else {
if (prefix) {
data = prefix + "\n" + data;
}
}
else {
data = prefix;
}
@ -57,54 +64,54 @@ define([
}
token_test(
[ "method", "GET", "url.endpoint", "_search" ],
[ "method", "GET", "url.part", "_search" ],
"GET _search"
);
token_test(
[ "method", "GET", "url.slash", "/", "url.endpoint", "_search" ],
[ "method", "GET", "url.slash", "/", "url.part", "_search" ],
"GET /_search"
);
token_test(
[ "method", "GET", "url.endpoint", "_cluster", "url.slash", "/", "url.part" , "nodes" ],
[ "method", "GET", "url.part", "_cluster", "url.slash", "/", "url.part" , "nodes" ],
"GET _cluster/nodes"
);
token_test(
[ "method", "GET", "url.slash", "/", "url.endpoint", "_cluster", "url.slash", "/", "url.part" , "nodes" ],
[ "method", "GET", "url.slash", "/", "url.part", "_cluster", "url.slash", "/", "url.part" , "nodes" ],
"GET /_cluster/nodes"
);
token_test(
[ "method", "GET", "url.index", "index", "url.slash", "/", "url.endpoint", "_search" ],
[ "method", "GET", "url.part", "index", "url.slash", "/", "url.part", "_search" ],
"GET index/_search"
);
token_test(
[ "method", "GET", "url.index", "index" ],
[ "method", "GET", "url.part", "index" ],
"GET index"
);
token_test(
[ "method", "GET", "url.index", "index", "url.slash", "/", "url.type", "type" ],
[ "method", "GET", "url.part", "index", "url.slash", "/", "url.part", "type" ],
"GET index/type"
);
token_test(
[ "method", "GET", "url.slash", "/", "url.index", "index", "url.slash", "/", "url.type", "type", "url.slash", "/" ],
[ "method", "GET", "url.slash", "/", "url.part", "index", "url.slash", "/", "url.part", "type", "url.slash", "/" ],
"GET /index/type/"
);
token_test(
[ "method", "GET", "url.index", "index", "url.slash", "/", "url.type", "type", "url.slash", "/", "url.endpoint", "_search" ],
[ "method", "GET", "url.part", "index", "url.slash", "/", "url.part", "type", "url.slash", "/", "url.part", "_search" ],
"GET index/type/_search"
);
token_test(
[ "method", "GET", "url.index", "index", "url.slash", "/", "url.type", "type", "url.slash", "/", "url.endpoint", "_search",
[ "method", "GET", "url.part", "index", "url.slash", "/", "url.part", "type", "url.slash", "/", "url.part", "_search",
"url.questionmark", "?", "url.param", "value", "url.equal", "=", "url.value", "1"
],
"GET index/type/_search?value=1"
@ -112,76 +119,76 @@ define([
token_test(
[ "method", "GET", "url.index", "index", "url.slash", "/", "url.type", "type", "url.slash", "/", "url.id", "1" ],
[ "method", "GET", "url.part", "index", "url.slash", "/", "url.part", "type", "url.slash", "/", "url.part", "1" ],
"GET index/type/1"
);
token_test(
[ "method", "GET", "url.slash", "/", "url.index", "index1", "url.comma", ",", "url.index", "index2", "url.slash", "/" ],
[ "method", "GET", "url.slash", "/", "url.part", "index1", "url.comma", ",", "url.part", "index2", "url.slash", "/" ],
"GET /index1,index2/"
);
token_test(
[ "method", "GET", "url.slash", "/", "url.index", "index1", "url.comma", ",", "url.index", "index2", "url.slash", "/",
"url.endpoint", "_search"],
[ "method", "GET", "url.slash", "/", "url.part", "index1", "url.comma", ",", "url.part", "index2", "url.slash", "/",
"url.part", "_search"],
"GET /index1,index2/_search"
);
token_test(
[ "method", "GET", "url.index", "index1", "url.comma", ",", "url.index", "index2", "url.slash", "/",
"url.endpoint", "_search"],
[ "method", "GET", "url.part", "index1", "url.comma", ",", "url.part", "index2", "url.slash", "/",
"url.part", "_search"],
"GET index1,index2/_search"
);
token_test(
[ "method", "GET", "url.slash", "/", "url.index", "index1", "url.comma", ",", "url.index", "index2" ],
[ "method", "GET", "url.slash", "/", "url.part", "index1", "url.comma", ",", "url.part", "index2" ],
"GET /index1,index2"
);
token_test(
[ "method", "GET", "url.index", "index1", "url.comma", ",", "url.index", "index2" ],
[ "method", "GET", "url.part", "index1", "url.comma", ",", "url.part", "index2" ],
"GET index1,index2"
);
token_test(
[ "method", "GET", "url.slash", "/", "url.index", "index1", "url.comma", "," ],
[ "method", "GET", "url.slash", "/", "url.part", "index1", "url.comma", "," ],
"GET /index1,"
);
token_test(
[ "method", "PUT", "url.slash", "/", "url.index", "index", "url.slash", "/" ],
[ "method", "PUT", "url.slash", "/", "url.part", "index", "url.slash", "/" ],
"PUT /index/"
);
token_test(
[ "method", "PUT", "url.slash", "/", "url.index", "index" ],
[ "method", "PUT", "url.slash", "/", "url.part", "index" ],
"PUT /index"
);
token_test(
[ "method", "PUT", "url.slash", "/", "url.index", "index1", "url.comma", ",", "url.index", "index2",
"url.slash", "/", "url.type", "type1", "url.comma", ",", "url.type", "type2"],
[ "method", "PUT", "url.slash", "/", "url.part", "index1", "url.comma", ",", "url.part", "index2",
"url.slash", "/", "url.part", "type1", "url.comma", ",", "url.part", "type2"],
"PUT /index1,index2/type1,type2"
);
token_test(
[ "method", "PUT", "url.slash", "/", "url.index", "index1",
"url.slash", "/", "url.type", "type1", "url.comma", ",", "url.type", "type2", "url.comma", ","],
[ "method", "PUT", "url.slash", "/", "url.part", "index1",
"url.slash", "/", "url.part", "type1", "url.comma", ",", "url.part", "type2", "url.comma", ","],
"PUT /index1/type1,type2,"
);
token_test(
[ "method", "PUT", "url.index", "index1", "url.comma", ",", "url.index", "index2",
"url.slash", "/", "url.type", "type1", "url.comma", ",", "url.type", "type2", "url.slash", "/",
"url.id", "1234"],
[ "method", "PUT", "url.part", "index1", "url.comma", ",", "url.part", "index2",
"url.slash", "/", "url.part", "type1", "url.comma", ",", "url.part", "type2", "url.slash", "/",
"url.part", "1234"],
"PUT index1,index2/type1,type2/1234"
);
token_test(
[ "method", "POST", "url.endpoint", "_search", "paren.lparen", "{", "variable", '"q"', "punctuation.colon", ":",
[ "method", "POST", "url.part", "_search", "paren.lparen", "{", "variable", '"q"', "punctuation.colon", ":",
"paren.lparen", "{", "paren.rparen", "}", "paren.rparen", "}"
],
'POST _search\n' +
@ -192,8 +199,8 @@ define([
);
token_test(
[ "method", "POST", "url.endpoint", "_search", "paren.lparen", "{", "variable", '"q"', "punctuation.colon", ":",
"paren.lparen", "{", "variable", '"s"', "punctuation.colon", ":", "paren.lparen", "{", "paren.rparen", "}",
[ "method", "POST", "url.part", "_search", "paren.lparen", "{", "variable", '"q"', "punctuation.colon", ":",
"paren.lparen", "{", "variable", '"s"', "punctuation.colon", ":", "paren.lparen", "{", "paren.rparen", "}",
"paren.rparen", "}", "paren.rparen", "}"
],
'POST _search\n' +
@ -214,10 +221,15 @@ define([
function states_test(states_list, prefix, data) {
if (data && typeof data != "string") data = JSON.stringify(data, null, 3);
if (data && typeof data != "string") {
data = JSON.stringify(data, null, 3);
}
if (data) {
if (prefix) data = prefix + "\n" + data;
} else {
if (prefix) {
data = prefix + "\n" + data;
}
}
else {
data = prefix;
}

View file

@ -0,0 +1,475 @@
define([
'_',
'autocomplete/url_pattern_matcher',
'autocomplete/engine'
], function (_, url_pattern_matcher, autocomplete_engine) {
'use strict';
module("Url autocomplete");
function patterns_test(name, endpoints, tokenPath, expectedContext, globalUrlComponentFactories) {
test(name, function () {
var patternMatcher = new url_pattern_matcher.UrlPatternMatcher(globalUrlComponentFactories);
_.each(endpoints, function (e, id) {
e.id = id;
_.each(e.patterns, function (p) {
patternMatcher.addEndpoint(p, e);
});
});
if (typeof tokenPath === "string") {
if (tokenPath[tokenPath.length - 1] == "$") {
tokenPath = tokenPath.substr(0, tokenPath.length - 1) + "/" + url_pattern_matcher.URL_PATH_END_MARKER;
}
tokenPath = _.map(tokenPath.split("/"), function (p) {
p = p.split(",");
if (p.length === 1) {
return p[0];
}
return p;
});
}
if (expectedContext.autoCompleteSet) {
expectedContext.autoCompleteSet = _.map(expectedContext.autoCompleteSet, function (t) {
if (_.isString(t)) {
t = { name: t}
}
return t;
});
expectedContext.autoCompleteSet = _.sortBy(expectedContext.autoCompleteSet, 'name');
}
var context = {};
if (expectedContext.method) {
context.method = expectedContext.method;
}
autocomplete_engine.populateContext(tokenPath, context, null,
expectedContext.autoCompleteSet, patternMatcher.getTopLevelComponents()
);
// override context to just check on id
if (context.endpoint) {
context.endpoint = context.endpoint.id;
}
if (context.autoCompleteSet) {
context.autoCompleteSet = _.sortBy(context.autoCompleteSet, 'name');
}
deepEqual(context, expectedContext);
});
}
function t(name, meta) {
if (meta) {
return {name: name, meta: meta};
}
return name;
}
(function () {
var endpoints = {
"1": {
patterns: [
"a/b"
]
}
};
patterns_test("simple single path - completion",
endpoints,
"a/b$",
{ endpoint: "1"}
);
patterns_test("simple single path - completion, with auto complete",
endpoints,
"a/b",
{ autoCompleteSet: [] }
);
patterns_test("simple single path - partial, without auto complete",
endpoints,
"a",
{ }
);
patterns_test("simple single path - partial, with auto complete",
endpoints,
"a",
{ autoCompleteSet: ["b"] }
);
patterns_test("simple single path - partial, with auto complete",
endpoints,
[],
{ autoCompleteSet: ["a/b"] }
);
patterns_test("simple single path - different path",
endpoints,
"a/c",
{ }
);
})();
(function () {
var endpoints = {
"1": {
patterns: [
"a/b",
"a/b/{p}"
]
},
"2": {
patterns: [
"a/c"
]
}
};
patterns_test("shared path - completion 1",
endpoints,
"a/b$",
{ endpoint: "1"}
);
patterns_test("shared path - completion 2",
endpoints,
"a/c$",
{ endpoint: "2"}
);
patterns_test("shared path - completion 1 with param",
endpoints,
"a/b/v$",
{ endpoint: "1", p: "v"}
);
patterns_test("shared path - partial, with auto complete",
endpoints,
"a",
{ autoCompleteSet: ["b", "c"] }
);
patterns_test("shared path - partial, with auto complete of param, no options",
endpoints,
"a/b",
{ autoCompleteSet: [] }
);
patterns_test("shared path - partial, without auto complete",
endpoints,
"a",
{ }
);
patterns_test("shared path - different path - with auto complete",
endpoints,
"a/e",
{ autoCompleteSet: []}
);
patterns_test("shared path - different path - without auto complete",
endpoints,
"a/e",
{ }
);
})();
(function () {
var endpoints = {
"1": {
patterns: [
"a/{p}",
],
url_components: {
p: ["a", "b"]
}
},
"2": {
patterns: [
"a/c"
]
}
};
patterns_test("option testing - completion 1",
endpoints,
"a/a$",
{ endpoint: "1", p: ["a"]}
);
patterns_test("option testing - completion 2",
endpoints,
"a/b$",
{ endpoint: "1", p: ["b"]}
);
patterns_test("option testing - completion 3",
endpoints,
"a/b,a$",
{ endpoint: "1", p: ["b", "a"]}
);
patterns_test("option testing - completion 4",
endpoints,
"a/c$",
{ endpoint: "2"}
);
patterns_test("option testing - completion 5",
endpoints,
"a/d$",
{ }
);
patterns_test("option testing - partial, with auto complete",
endpoints,
"a",
{ autoCompleteSet: [t("a", "p"), t("b", "p"), "c"] }
);
patterns_test("option testing - partial, without auto complete",
endpoints,
"a",
{ }
);
patterns_test("option testing - different path - with auto complete",
endpoints,
"a/e",
{ autoCompleteSet: []}
);
})();
(function () {
var endpoints = {
"1": {
patterns: [
"a/{p}",
],
url_components: {
p: ["a", "b"]
}
},
"2": {
patterns: [
"b/{p}",
]
},
"3": {
patterns: [
"b/{l}/c",
],
url_components: {
l: {
type: "list",
list: ["la", "lb"],
allow_non_valid: true
}
}
}
};
var globalFactories = {
"p": function (name, parent) {
return new autocomplete_engine.ListComponent(name, ["g1", "g2"], parent);
}
};
patterns_test("global parameters testing - completion 1",
endpoints,
"a/a$",
{ endpoint: "1", p: ["a"]},
globalFactories
);
patterns_test("global parameters testing - completion 2",
endpoints,
"b/g1$",
{ endpoint: "2", p: ["g1"]},
globalFactories
);
patterns_test("global parameters testing - partial, with auto complete",
endpoints,
"a",
{ autoCompleteSet: [t("a", "p"), t("b", "p")] },
globalFactories
);
patterns_test("global parameters testing - partial, with auto complete 2",
endpoints,
"b",
{ autoCompleteSet: [t("g1", "p"), t("g2", "p"), t("la", "l"), t("lb", "l")] },
globalFactories
);
patterns_test("Non valid token acceptance - partial, with auto complete 1",
endpoints,
"b/la",
{ autoCompleteSet: ["c"], "l": ["la"] },
globalFactories
);
patterns_test("Non valid token acceptance - partial, with auto complete 2",
endpoints,
"b/non_valid",
{ autoCompleteSet: ["c"], "l": ["non_valid"] },
globalFactories
);
})();
(function () {
var endpoints = {
"1": {
patterns: [
"a/b/{p}/c/e"
]
}
};
patterns_test("look ahead - autocomplete before param 1",
endpoints,
"a",
{ autoCompleteSet: [ "b" ]}
);
patterns_test("look ahead - autocomplete before param 2",
endpoints,
[],
{ autoCompleteSet: [ "a/b" ]}
);
patterns_test("look ahead - autocomplete after param 1",
endpoints,
"a/b/v",
{ autoCompleteSet: [ "c/e" ], "p": "v"}
);
patterns_test("look ahead - autocomplete after param 2",
endpoints,
"a/b/v/c",
{ autoCompleteSet: [ "e" ], "p": "v"}
);
})();
(function () {
var endpoints = {
"1_param": {
patterns: [
"a/{p}"
],
methods: ["GET"]
},
"2_explicit": {
patterns: [
"a/b"
],
methods: ["GET"]
}};
var e = _.cloneDeep(endpoints);
e["1_param"].priority = 1;
patterns_test("Competing endpoints - priority 1",
e,
"a/b$",
{ method: "GET", endpoint: "1_param", "p": "b"}
);
e = _.cloneDeep(endpoints);
e["1_param"].priority = 1;
e["2_explicit"].priority = 0;
patterns_test("Competing endpoints - priority 2",
e,
"a/b$",
{ method: "GET", endpoint: "2_explicit"}
);
e = _.cloneDeep(endpoints);
e["2_explicit"].priority = 0;
patterns_test("Competing endpoints - priority 3",
e,
"a/b$",
{ method: "GET", endpoint: "2_explicit"}
);
})();
(function () {
var endpoints = {
"1_GET": {
patterns: [
"a"
],
methods: ["GET"]
},
"1_PUT": {
patterns: [
"a"
],
methods: ["PUT"]
},
"2_GET": {
patterns: [
"a/b"
],
methods: ["GET"]
},
"2_DELETE": {
patterns: [
"a/b"
],
methods: ["DELETE"]
}
};
patterns_test("Competing endpoint - sub url of another - auto complete",
endpoints,
"a",
{ method: "GET", autoCompleteSet: [ "b" ]}
);
patterns_test("Competing endpoint - sub url of another, complete 1",
endpoints,
"a$",
{ method: "GET", endpoint: "1_GET"}
);
patterns_test("Competing endpoint - sub url of another, complete 2",
endpoints,
"a$",
{ method: "PUT", endpoint: "1_PUT"}
);
patterns_test("Competing endpoint - sub url of another, complete 3",
endpoints,
"a$",
{ method: "DELETE" }
);
patterns_test("Competing endpoint - extension of another, complete 1, auto complete",
endpoints,
"a/b$",
{ method: "PUT", autoCompleteSet: []}
);
patterns_test("Competing endpoint - extension of another, complete 1",
endpoints,
"a/b$",
{ method: "GET", endpoint: "2_GET"}
);
patterns_test("Competing endpoint - extension of another, complete 1",
endpoints,
"a/b$",
{ method: "DELETE", endpoint: "2_DELETE"}
);
patterns_test("Competing endpoint - extension of another, complete 1",
endpoints,
"a/b$",
{ method: "PUT"}
);
})();
});

View file

@ -0,0 +1,107 @@
define([
'_',
'autocomplete/url_params',
'autocomplete/engine'
], function (_, url_params, autocomplete_engine) {
'use strict';
module("Url params");
function param_test(name, description, tokenPath, expectedContext, globalParams) {
test(name, function () {
var urlParams = new url_params.UrlParams(description, globalParams || {});
if (typeof tokenPath === "string") {
tokenPath = _.map(tokenPath.split("/"), function (p) {
p = p.split(",");
if (p.length === 1) {
return p[0];
}
return p;
});
}
if (expectedContext.autoCompleteSet) {
expectedContext.autoCompleteSet = _.map(expectedContext.autoCompleteSet, function (t) {
if (_.isString(t)) {
t = { name: t}
}
return t;
});
expectedContext.autoCompleteSet = _.sortBy(expectedContext.autoCompleteSet, 'name');
}
var context = {};
autocomplete_engine.populateContext(tokenPath, context, null,
expectedContext.autoCompleteSet, urlParams.getTopLevelComponents()
);
if (context.autoCompleteSet) {
context.autoCompleteSet = _.sortBy(context.autoCompleteSet, 'name');
}
deepEqual(context, expectedContext);
});
}
function t(name, meta, insert_value) {
var r = name;
if (meta) {
r = {name: name, meta: meta};
if (meta === "param" && !insert_value) {
insert_value = name + "=";
}
}
if (insert_value) {
if (_.isString(r)) {
r = {name: name}
}
r.insert_value = insert_value;
}
return r;
}
(function () {
var params = {
"a": ["1", "2"],
"b": "__flag__"
};
param_test("settings params",
params,
"a/1",
{ "a": ["1"]}
);
param_test("autocomplete top level",
params,
[],
{ autoCompleteSet: [ t("a", "param"), t("b", "flag")]}
);
param_test("autocomplete top level, with defaults",
params,
[],
{ autoCompleteSet: [ t("a", "param"), t("b", "flag"), t("c", "param")]},
{
"c": [2]
}
);
param_test("autocomplete values",
params,
"a",
{ autoCompleteSet: [ t("1", "a"), t("2", "a")]}
);
param_test("autocomplete values flag",
params,
"b",
{ autoCompleteSet: [ t("true", "b"), t("false", "b")]}
);
})();
});

290
sense/vendor/ace/mode-yaml.js vendored Normal file
View file

@ -0,0 +1,290 @@
/* ***** BEGIN LICENSE BLOCK *****
* Distributed under the BSD license:
*
* Copyright (c) 2010, Ajax.org B.V.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Ajax.org B.V. nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* ***** END LICENSE BLOCK ***** */
ace.define('ace/mode/yaml', ['require', 'exports', 'module' , 'ace/lib/oop', 'ace/mode/text', 'ace/tokenizer', 'ace/mode/yaml_highlight_rules', 'ace/mode/matching_brace_outdent', 'ace/mode/folding/coffee'], function(require, exports, module) {
var oop = require("../lib/oop");
var TextMode = require("./text").Mode;
var Tokenizer = require("../tokenizer").Tokenizer;
var YamlHighlightRules = require("./yaml_highlight_rules").YamlHighlightRules;
var MatchingBraceOutdent = require("./matching_brace_outdent").MatchingBraceOutdent;
var FoldMode = require("./folding/coffee").FoldMode;
var Mode = function() {
this.HighlightRules = YamlHighlightRules;
this.$outdent = new MatchingBraceOutdent();
this.foldingRules = new FoldMode();
};
oop.inherits(Mode, TextMode);
(function() {
this.lineCommentStart = "#";
this.getNextLineIndent = function(state, line, tab) {
var indent = this.$getIndent(line);
if (state == "start") {
var match = line.match(/^.*[\{\(\[]\s*$/);
if (match) {
indent += tab;
}
}
return indent;
};
this.checkOutdent = function(state, line, input) {
return this.$outdent.checkOutdent(line, input);
};
this.autoOutdent = function(state, doc, row) {
this.$outdent.autoOutdent(doc, row);
};
this.$id = "ace/mode/yaml";
}).call(Mode.prototype);
exports.Mode = Mode;
});
ace.define('ace/mode/yaml_highlight_rules', ['require', 'exports', 'module' , 'ace/lib/oop', 'ace/mode/text_highlight_rules'], function(require, exports, module) {
var oop = require("../lib/oop");
var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules;
var YamlHighlightRules = function() {
this.$rules = {
"start" : [
{
token : "comment",
regex : "#.*$"
}, {
token : "list.markup",
regex : /^(?:-{3}|\.{3})\s*(?=#|$)/
}, {
token : "list.markup",
regex : /^\s*[\-?](?:$|\s)/
}, {
token: "constant",
regex: "!![\\w//]+"
}, {
token: "constant.language",
regex: "[&\\*][a-zA-Z0-9-_]+"
}, {
token: ["meta.tag", "keyword"],
regex: /^(\s*\w.*?)(\:(?:\s+|$))/
},{
token: ["meta.tag", "keyword"],
regex: /(\w+?)(\s*\:(?:\s+|$))/
}, {
token : "keyword.operator",
regex : "<<\\w*:\\w*"
}, {
token : "keyword.operator",
regex : "-\\s*(?=[{])"
}, {
token : "string", // single line
regex : '["](?:(?:\\\\.)|(?:[^"\\\\]))*?["]'
}, {
token : "string", // multi line string start
regex : '[|>][-+\\d\\s]*$',
next : "qqstring"
}, {
token : "string", // single quoted string
regex : "['](?:(?:\\\\.)|(?:[^'\\\\]))*?[']"
}, {
token : "constant.numeric", // float
regex : /[+\-]?[\d_]+(?:(?:\.[\d_]*)?(?:[eE][+\-]?[\d_]+)?)?\b/
}, {
token : "constant.numeric", // other number
regex : /[+\-]?\.inf\b|NaN\b|0x[\dA-Fa-f_]+|0b[10_]+/
}, {
token : "constant.language.boolean",
regex : "(?:true|false|TRUE|FALSE|True|False|yes|no)\\b"
}, {
token : "invalid.illegal", // comments are not allowed
regex : "\\/\\/.*$"
}, {
token : "paren.lparen",
regex : "[[({]"
}, {
token : "paren.rparen",
regex : "[\\])}]"
}
],
"qqstring" : [
{
token : "string",
regex : '(?=(?:(?:\\\\.)|(?:[^:]))*?:)',
next : "start"
}, {
token : "string",
regex : '.+'
}
]};
};
oop.inherits(YamlHighlightRules, TextHighlightRules);
exports.YamlHighlightRules = YamlHighlightRules;
});
ace.define('ace/mode/matching_brace_outdent', ['require', 'exports', 'module' , 'ace/range'], function(require, exports, module) {
var Range = require("../range").Range;
var MatchingBraceOutdent = function() {};
(function() {
this.checkOutdent = function(line, input) {
if (! /^\s+$/.test(line))
return false;
return /^\s*\}/.test(input);
};
this.autoOutdent = function(doc, row) {
var line = doc.getLine(row);
var match = line.match(/^(\s*\})/);
if (!match) return 0;
var column = match[1].length;
var openBracePos = doc.findMatchingBracket({row: row, column: column});
if (!openBracePos || openBracePos.row == row) return 0;
var indent = this.$getIndent(doc.getLine(openBracePos.row));
doc.replace(new Range(row, 0, row, column-1), indent);
};
this.$getIndent = function(line) {
return line.match(/^\s*/)[0];
};
}).call(MatchingBraceOutdent.prototype);
exports.MatchingBraceOutdent = MatchingBraceOutdent;
});
ace.define('ace/mode/folding/coffee', ['require', 'exports', 'module' , 'ace/lib/oop', 'ace/mode/folding/fold_mode', 'ace/range'], function(require, exports, module) {
var oop = require("../../lib/oop");
var BaseFoldMode = require("./fold_mode").FoldMode;
var Range = require("../../range").Range;
var FoldMode = exports.FoldMode = function() {};
oop.inherits(FoldMode, BaseFoldMode);
(function() {
this.getFoldWidgetRange = function(session, foldStyle, row) {
var range = this.indentationBlock(session, row);
if (range)
return range;
var re = /\S/;
var line = session.getLine(row);
var startLevel = line.search(re);
if (startLevel == -1 || line[startLevel] != "#")
return;
var startColumn = line.length;
var maxRow = session.getLength();
var startRow = row;
var endRow = row;
while (++row < maxRow) {
line = session.getLine(row);
var level = line.search(re);
if (level == -1)
continue;
if (line[level] != "#")
break;
endRow = row;
}
if (endRow > startRow) {
var endColumn = session.getLine(endRow).length;
return new Range(startRow, startColumn, endRow, endColumn);
}
};
this.getFoldWidget = function(session, foldStyle, row) {
var line = session.getLine(row);
var indent = line.search(/\S/);
var next = session.getLine(row + 1);
var prev = session.getLine(row - 1);
var prevIndent = prev.search(/\S/);
var nextIndent = next.search(/\S/);
if (indent == -1) {
session.foldWidgets[row - 1] = prevIndent!= -1 && prevIndent < nextIndent ? "start" : "";
return "";
}
if (prevIndent == -1) {
if (indent == nextIndent && line[indent] == "#" && next[indent] == "#") {
session.foldWidgets[row - 1] = "";
session.foldWidgets[row + 1] = "";
return "start";
}
} else if (prevIndent == indent && line[indent] == "#" && prev[indent] == "#") {
if (session.getLine(row - 2).search(/\S/) == -1) {
session.foldWidgets[row - 1] = "start";
session.foldWidgets[row + 1] = "";
return "";
}
}
if (prevIndent!= -1 && prevIndent < indent)
session.foldWidgets[row - 1] = "start";
else
session.foldWidgets[row - 1] = "";
if (indent < nextIndent)
return "start";
else
return "";
};
}).call(FoldMode.prototype);
});

View file

@ -28,7 +28,7 @@ module.exports = function (config) {
{
expand: true,
cwd: '<%= kibanaCheckoutDir %>',
src: [ '**', '.jshintrc'],
src: [ '**', '.jshintrc', '.git/**'],
dest: '<%= buildTempDir %>'
},
{