mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 09:19:04 -04:00
Merge branch 'master' into feature/sort-dimensions-dragging
This commit is contained in:
commit
7bf698acc9
143 changed files with 4909 additions and 1285 deletions
|
@ -55,7 +55,7 @@ Please make sure you have signed the [Contributor License Agreement](http://www.
|
|||
npm run elasticsearch
|
||||
```
|
||||
|
||||
- Start the development server. _On Windows, you'll need you use Git Bash, Cygwin, or a similar shell that exposes the `sh` command._
|
||||
- Start the development server. _On Windows, you'll need you use Git Bash, Cygwin, or a similar shell that exposes the `sh` command. And to successfully build you'll need Cygwin optional packages zip, tar, and shasum._
|
||||
|
||||
```sh
|
||||
npm start
|
||||
|
|
|
@ -62,7 +62,8 @@ module.exports = function (grunt) {
|
|||
'postcss-unique-selectors': '1.0.0',
|
||||
'postcss-minify-selectors': '1.4.6',
|
||||
'postcss-single-charset': '0.3.0',
|
||||
'regenerator': '0.8.36'
|
||||
'regenerator': '0.8.36',
|
||||
'readable-stream': '2.1.0'
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -61,6 +61,10 @@
|
|||
# must be a positive integer.
|
||||
# elasticsearch.requestTimeout: 30000
|
||||
|
||||
# List of Kibana client-side headers to send to Elasticsearch. To send *no* client-side
|
||||
# headers, set this value to [] (an empty list).
|
||||
# elasticsearch.requestHeadersWhitelist: [ authorization ]
|
||||
|
||||
# Time in milliseconds for Elasticsearch to wait for responses from shards. Set to 0 to disable.
|
||||
# elasticsearch.shardTimeout: 0
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
[[kibana-settings-reference]]
|
||||
|
||||
WARNING: Modifying the following settings can signficantly affect Kibana's performance and cause problems that are
|
||||
difficult to diagnose. Setting a property's value to a blank field will revert to the default behavior, which may not be
|
||||
WARNING: Modifying the following settings can signficantly affect Kibana's performance and cause problems that are
|
||||
difficult to diagnose. Setting a property's value to a blank field will revert to the default behavior, which may not be
|
||||
compatible with other configuration settings. Deleting a custom setting removes it from Kibana permanently.
|
||||
|
||||
.Kibana Settings Reference
|
||||
|
@ -10,38 +10,39 @@ compatible with other configuration settings. Deleting a custom setting removes
|
|||
`sort:options`:: Options for the Elasticsearch https://www.elastic.co/guide/en/elasticsearch/reference/current/search-request-sort.html[sort] parameter.
|
||||
`dateFormat`:: The format to use for displaying pretty-formatted dates.
|
||||
`dateFormat:tz`:: The timezone that Kibana uses. The default value of `Browser` uses the timezone detected by the browser.
|
||||
`dateFormat:scaled`:: These values define the format used to render ordered time-based data. Formatted timestamps must
|
||||
`dateFormat:scaled`:: These values define the format used to render ordered time-based data. Formatted timestamps must
|
||||
`dateFormat:dow`:: This property defines what day weeks should start on.
|
||||
adapt to the interval between measurements. Keys are http://en.wikipedia.org/wiki/ISO_8601#Time_intervals[ISO8601 intervals].
|
||||
`defaultIndex`:: Default is `null`. This property specifies the default index.
|
||||
`metaFields`:: An array of fields outside of `_source`. Kibana merges these fields into the document when displaying the
|
||||
`metaFields`:: An array of fields outside of `_source`. Kibana merges these fields into the document when displaying the
|
||||
document.
|
||||
`defaultColumns`:: Default is `_source`. Defines the columns that appear by default on the Discover page.
|
||||
`discover:sampleSize`:: The number of rows to show in the Discover table.
|
||||
`doc_table:highlight`:: Highlight results in Discover and Saved Searches Dashboard. Highlighing makes request slow when
|
||||
`doc_table:highlight`:: Highlight results in Discover and Saved Searches Dashboard. Highlighing makes request slow when
|
||||
working on big documents. Set this property to `false` to disable highlighting.
|
||||
`courier:maxSegmentCount`:: Kibana splits requests in the Discover app into segments to limit the size of requests sent to
|
||||
the Elasticsearch cluster. This setting constrains the length of the segment list. Long segment lists can significantly
|
||||
`courier:maxSegmentCount`:: Kibana splits requests in the Discover app into segments to limit the size of requests sent to
|
||||
the Elasticsearch cluster. This setting constrains the length of the segment list. Long segment lists can significantly
|
||||
increase request processing time.
|
||||
`fields:popularLimit`:: This setting governs how many of the top most popular fields are shown.
|
||||
`histogram:barTarget`:: When date histograms use the `auto` interval, Kibana attempts to generate this number of bars.
|
||||
`histogram:maxBars`:: Date histograms are not generated with more bars than the value of this property, scaling values
|
||||
`histogram:maxBars`:: Date histograms are not generated with more bars than the value of this property, scaling values
|
||||
when necessary.
|
||||
`visualization:tileMap:maxPrecision`:: The maximum geoHash precision displayed on tile maps: 7 is high, 10 is very high,
|
||||
`visualization:tileMap:maxPrecision`:: The maximum geoHash precision displayed on tile maps: 7 is high, 10 is very high,
|
||||
12 is the maximum. http://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-geohashgrid-aggregation.html#_cell_dimensions_at_the_equator[Explanation of cell dimensions].
|
||||
`visualization:tileMap:WMSdefaults`:: Default properties for the WMS map server support in the tile map.
|
||||
`visualization:colorMapping`:: Maps values to specified colors within visualizations.
|
||||
`visualization:loadingDelay`:: Time to wait before dimming visualizations during query.
|
||||
`csv:separator`:: A string that serves as the separator for exported values.
|
||||
`csv:quoteValues`:: Set this property to `true` to quote exported values.
|
||||
`history:limit`:: In fields that have history, such as query inputs, the value of this property limits how many recent
|
||||
`history:limit`:: In fields that have history, such as query inputs, the value of this property limits how many recent
|
||||
values are shown.
|
||||
`shortDots:enable`:: Set this property to `true` to shorten long field names in visualizations. For example, instead of
|
||||
`shortDots:enable`:: Set this property to `true` to shorten long field names in visualizations. For example, instead of
|
||||
`foo.bar.baz`, show `f.b.baz`.
|
||||
`truncate:maxHeight`:: This property specifies the maximum height that a cell occupies in a table. A value of 0 disables
|
||||
`truncate:maxHeight`:: This property specifies the maximum height that a cell occupies in a table. A value of 0 disables
|
||||
truncation.
|
||||
`indexPattern:fieldMapping:lookBack`:: The value of this property sets the number of recent matching patterns to query the
|
||||
`indexPattern:fieldMapping:lookBack`:: The value of this property sets the number of recent matching patterns to query the
|
||||
field mapping for index patterns with names that contain timestamps.
|
||||
`format:defaultTypeMap`:: A map of the default format name for each field type. Field types that are not explicitly
|
||||
`format:defaultTypeMap`:: A map of the default format name for each field type. Field types that are not explicitly
|
||||
mentioned use "_default_".
|
||||
`format:number:defaultPattern`:: Default numeral format for the "number" format.
|
||||
`format:bytes:defaultPattern`:: Default numeral format for the "bytes" format.
|
||||
|
|
|
@ -29,7 +29,9 @@ to `false`.
|
|||
wait for Elasticsearch to respond to pings.
|
||||
`elasticsearch.requestTimeout:`:: *Default: 300000* Time in milliseconds to wait for responses from the back end or
|
||||
Elasticsearch. This value must be a positive integer.
|
||||
`elasticsearch.shardTimeout:`:: *Default: 0* Time in milliseconds for Elasticsearch to wait for responses from shards. Set
|
||||
`elasticsearch.requestHeadersWhitelist:`:: *Default: `[ 'authorization' ]`* List of Kibana client-side headers to send to Elasticsearch.
|
||||
To send *no* client-side headers, set this value to [] (an empty list).
|
||||
`elasticsearch.shardTimeout:`:: *Default: 0* Time in milliseconds for Elasticsearch to wait for responses from shards. Set
|
||||
to 0 to disable.
|
||||
`elasticsearch.startupTimeout:`:: *Default: 5000* Time in milliseconds to wait for Elasticsearch at Kibana startup before
|
||||
retrying.
|
||||
|
|
|
@ -376,6 +376,10 @@ deprecated[4.2, The names of several Kibana server properties changed in the 4.2
|
|||
+
|
||||
*default*: `500000`
|
||||
|
||||
`elasticsearch.requestHeadersWhitelist:` added[5.0]:: List of Kibana client-side headers to send to Elasticsearch. To send *no* client-side headers, set this value to [] (an empty list).
|
||||
+
|
||||
*default*: `[ 'authorization' ]`
|
||||
|
||||
`elasticsearch.shardTimeout` added[4.2]:: How long Elasticsearch should wait for responses from shards. Set to 0 to disable.
|
||||
+
|
||||
*alias*: `shard_timeout` deprecated[4.2]
|
||||
|
|
|
@ -67,6 +67,7 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"@bigfunger/decompress-zip": "0.2.0-stripfix2",
|
||||
"@elastic/datemath": "2.2.0",
|
||||
"@spalger/angular-bootstrap": "0.12.1",
|
||||
"@spalger/filesaver": "1.1.2",
|
||||
"@spalger/leaflet-draw": "0.2.3",
|
||||
|
@ -189,6 +190,7 @@
|
|||
"simple-git": "1.8.0",
|
||||
"sinon": "1.17.2",
|
||||
"source-map": "0.4.4",
|
||||
"source-map-support": "0.4.0",
|
||||
"supertest-as-promised": "2.0.2"
|
||||
},
|
||||
"engines": {
|
||||
|
|
|
@ -5,6 +5,7 @@ import glob from 'glob-all';
|
|||
import rimraf from 'rimraf';
|
||||
import mkdirp from 'mkdirp';
|
||||
import Logger from '../../lib/logger';
|
||||
import { UnsupportedProtocolError } from '../../lib/errors';
|
||||
import { download, _downloadSingle } from '../download';
|
||||
import { join } from 'path';
|
||||
|
||||
|
@ -74,12 +75,12 @@ describe('kibana cli', function () {
|
|||
});
|
||||
});
|
||||
|
||||
it('should throw an ENOTFOUND error for an invalid url', function () {
|
||||
it('should throw an UnsupportedProtocolError for an invalid url', function () {
|
||||
const sourceUrl = 'i am an invalid url';
|
||||
|
||||
return _downloadSingle(settings, logger, sourceUrl)
|
||||
.then(shouldReject, function (err) {
|
||||
expect(err.message).to.match(/ENOTFOUND/);
|
||||
expect(err).to.be.an(UnsupportedProtocolError);
|
||||
expectWorkingPathEmpty();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import downloadHttpFile from './downloaders/http';
|
||||
import downloadLocalFile from './downloaders/file';
|
||||
import { UnsupportedProtocolError } from '../lib/errors';
|
||||
import { parse } from 'url';
|
||||
|
||||
export function _downloadSingle(settings, logger, sourceUrl) {
|
||||
|
@ -8,8 +9,10 @@ export function _downloadSingle(settings, logger, sourceUrl) {
|
|||
|
||||
if (/^file/.test(urlInfo.protocol)) {
|
||||
downloadPromise = downloadLocalFile(logger, decodeURI(urlInfo.path), settings.tempArchiveFile);
|
||||
} else {
|
||||
} else if (/^https?/.test(urlInfo.protocol)) {
|
||||
downloadPromise = downloadHttpFile(logger, sourceUrl, settings.tempArchiveFile, settings.timeout);
|
||||
} else {
|
||||
downloadPromise = Promise.reject(new UnsupportedProtocolError());
|
||||
}
|
||||
|
||||
return downloadPromise;
|
||||
|
@ -29,7 +32,9 @@ export function download(settings, logger) {
|
|||
|
||||
return _downloadSingle(settings, logger, sourceUrl)
|
||||
.catch((err) => {
|
||||
if (err.message === 'ENOTFOUND') {
|
||||
const isUnsupportedProtocol = err instanceof UnsupportedProtocolError;
|
||||
const isDownloadResourceNotFound = err.message === 'ENOTFOUND';
|
||||
if (isUnsupportedProtocol || isDownloadResourceNotFound) {
|
||||
return tryNext();
|
||||
}
|
||||
throw (err);
|
||||
|
|
|
@ -87,8 +87,9 @@ async function mergePackageData(settings, packages) {
|
|||
*/
|
||||
async function extractArchive(settings) {
|
||||
const filter = {
|
||||
paths: [ settings.plugins[0].folder ]
|
||||
paths: [ `kibana/${settings.plugins[0].folder}` ]
|
||||
};
|
||||
|
||||
await extractFiles(settings.tempArchiveFile, settings.workingPath, 2, filter);
|
||||
}
|
||||
|
||||
|
|
1
src/cli_plugin/lib/errors.js
Normal file
1
src/cli_plugin/lib/errors.js
Normal file
|
@ -0,0 +1 @@
|
|||
export class UnsupportedProtocolError extends Error {};
|
54
src/plugins/console/api_server/es_5_0.js
Normal file
54
src/plugins/console/api_server/es_5_0.js
Normal file
|
@ -0,0 +1,54 @@
|
|||
let _ = require("lodash");
|
||||
let Api = require('./api');
|
||||
let parts = [
|
||||
require('./es_5_0/aliases'),
|
||||
require('./es_5_0/aggregations'),
|
||||
require('./es_5_0/cat'),
|
||||
require('./es_5_0/cluster'),
|
||||
require('./es_5_0/count'),
|
||||
require('./es_5_0/document'),
|
||||
require('./es_5_0/field_stats'),
|
||||
require('./es_5_0/filter'),
|
||||
require('./es_5_0/nodes'),
|
||||
require('./es_5_0/globals'),
|
||||
require('./es_5_0/indices'),
|
||||
require('./es_5_0/mappings'),
|
||||
require('./es_5_0/percolator'),
|
||||
require('./es_5_0/query'),
|
||||
require('./es_5_0/snapshot_restore'),
|
||||
require('./es_5_0/search'),
|
||||
require('./es_5_0/settings'),
|
||||
require('./es_5_0/templates')
|
||||
];
|
||||
|
||||
function ES_5_0() {
|
||||
Api.call(this, "es_5_0");
|
||||
_.each(parts, function (apiSection) {
|
||||
apiSection(this);
|
||||
}, this);
|
||||
}
|
||||
|
||||
ES_5_0.prototype = _.create(Api.prototype, {'constructor': ES_5_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);
|
||||
};
|
||||
})(ES_5_0.prototype);
|
||||
|
||||
module.exports = new ES_5_0();
|
436
src/plugins/console/api_server/es_5_0/aggregations.js
Normal file
436
src/plugins/console/api_server/es_5_0/aggregations.js
Normal file
|
@ -0,0 +1,436 @@
|
|||
var simple_metric = {
|
||||
__template: {field: ""},
|
||||
field: "{field}",
|
||||
missing: 0,
|
||||
script: {
|
||||
// populated by a global rule
|
||||
}
|
||||
}, field_metric = {
|
||||
__template: {field: ""},
|
||||
field: "{field}"
|
||||
}, gap_policy = {
|
||||
__one_of: ["skip", "insert_zeros"]
|
||||
}, simple_pipeline = {
|
||||
__template: {
|
||||
buckets_path: ""
|
||||
},
|
||||
buckets_path: "",
|
||||
format: "",
|
||||
gap_policy: gap_policy
|
||||
};
|
||||
var rules = {
|
||||
"*": {
|
||||
"aggs": {
|
||||
__template: {
|
||||
"NAME": {
|
||||
"AGG_TYPE": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
"min": simple_metric,
|
||||
"max": simple_metric,
|
||||
"avg": simple_metric,
|
||||
"sum": simple_metric,
|
||||
"stats": simple_metric,
|
||||
"extended_stats": simple_metric,
|
||||
"value_count": {
|
||||
__template: {
|
||||
"field": ""
|
||||
},
|
||||
"field": "{field}",
|
||||
"script": {
|
||||
// populated by a global rule
|
||||
}
|
||||
},
|
||||
"global": {},
|
||||
"filter": {},
|
||||
"filters": {
|
||||
__template: {
|
||||
"filters": {
|
||||
"NAME": {}
|
||||
}
|
||||
},
|
||||
"filters": {
|
||||
"*": {__scope_link: "GLOBAL.filter"}
|
||||
},
|
||||
"other_bucket": {__one_of: [true, false]},
|
||||
"other_bucket_key": ""
|
||||
},
|
||||
"missing": field_metric,
|
||||
"nested": {
|
||||
__template: {
|
||||
"path": ""
|
||||
},
|
||||
"path": ""
|
||||
},
|
||||
"reverse_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": {
|
||||
// populated by a global rule
|
||||
},
|
||||
"include": ".*",
|
||||
"exclude": ".*",
|
||||
"execution_hint": {__one_of: ["map", "global_ordinals", "global_ordinals_hash", "global_ordinals_low_cardinality"]},
|
||||
"show_term_doc_count_error": {__one_of: [true, false]},
|
||||
"collect_mode": {__one_of: ["depth_first", "breadth_first"]},
|
||||
"missing": ""
|
||||
},
|
||||
"significant_terms": {
|
||||
__template: {
|
||||
"field": ""
|
||||
},
|
||||
"field": "{field}",
|
||||
"size": 10,
|
||||
"shard_size": 10,
|
||||
"shard_min_doc_count": 10,
|
||||
"min_doc_count": 10,
|
||||
"include": {__one_of: ["*", {pattern: "", flags: ""}]},
|
||||
"exclude": {__one_of: ["*", {pattern: "", flags: ""}]},
|
||||
"execution_hint": {__one_of: ["map", "global_ordinals", "global_ordinals_hash"]},
|
||||
"background_filter": {
|
||||
__scope_link: "GLOBAL.filter"
|
||||
},
|
||||
"mutual_information": {
|
||||
"include_negatives": {__one_of: [true, false]}
|
||||
},
|
||||
"chi_square": {
|
||||
"include_negatives": {__one_of: [true, false]},
|
||||
"background_is_superset": {__one_of: [true, false]}
|
||||
},
|
||||
"percentage": {},
|
||||
"gnd": {
|
||||
"background_is_superset": {__one_of: [true, false]}
|
||||
},
|
||||
"script_heuristic": {
|
||||
__template: {
|
||||
"script": "_subset_freq/(_superset_freq - _subset_freq + 1)"
|
||||
},
|
||||
"script": {
|
||||
// populated by a global rule
|
||||
}
|
||||
}
|
||||
},
|
||||
"range": {
|
||||
__template: {
|
||||
"field": "",
|
||||
"ranges": [
|
||||
{"from": 50, "to": 100},
|
||||
]
|
||||
},
|
||||
"field": "{field}",
|
||||
"ranges": [
|
||||
{"to": 50, "from": 100, "key": ""}
|
||||
],
|
||||
"keyed": {__one_of: [true, false]},
|
||||
"script": {
|
||||
// populated by a global rule
|
||||
}
|
||||
},
|
||||
"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": {
|
||||
// populated by a global rule
|
||||
}
|
||||
},
|
||||
"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": {
|
||||
// populated by a global rule
|
||||
}
|
||||
},
|
||||
"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]},
|
||||
"missing": 0
|
||||
},
|
||||
"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",
|
||||
"time_zone": "00:00",
|
||||
"missing": ""
|
||||
},
|
||||
"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
|
||||
},
|
||||
"percentiles": {
|
||||
__template: {
|
||||
"field": "",
|
||||
"percents": [1.0, 5.0, 25.0, 50.0, 75.0, 95.0, 99.0]
|
||||
},
|
||||
"field": "{field}",
|
||||
"percents": {
|
||||
__template: [1.0, 5.0, 25.0, 50.0, 75.0, 95.0, 99.0],
|
||||
// mark type as list
|
||||
__any_of: []
|
||||
},
|
||||
"script": {
|
||||
// populated by a global rule
|
||||
},
|
||||
"compression": 100,
|
||||
"method": {__one_of: ["hdr", "tdigest"]},
|
||||
missing: 0
|
||||
},
|
||||
"cardinality": {
|
||||
__template: {
|
||||
"field": ""
|
||||
},
|
||||
"precision_threshold": 100,
|
||||
"rehash": true,
|
||||
"script": {
|
||||
// populated by a global rule
|
||||
},
|
||||
missing: ""
|
||||
},
|
||||
"scripted_metric": {
|
||||
__template: {
|
||||
"init_script": "",
|
||||
"map_script": "",
|
||||
"combine_script": "",
|
||||
"reduce_script": ""
|
||||
},
|
||||
"init_script": {
|
||||
__scope_link: "GLOBAL.script"
|
||||
},
|
||||
"map_script": {
|
||||
__scope_link: "GLOBAL.script"
|
||||
},
|
||||
"combine_script": {
|
||||
__scope_link: "GLOBAL.script"
|
||||
},
|
||||
"reduce_script": {
|
||||
__scope_link: "GLOBAL.script"
|
||||
},
|
||||
"lang": "groovy",
|
||||
"params": {},
|
||||
"reduce_params": {}
|
||||
},
|
||||
"geo_bounds": {
|
||||
__template: {
|
||||
field: ""
|
||||
},
|
||||
field: "{field}",
|
||||
wrap_longitude: {__one_of: [true, false]}
|
||||
},
|
||||
"top_hits": {
|
||||
__template: {
|
||||
size: 10
|
||||
},
|
||||
from: 0,
|
||||
size: 10,
|
||||
sort: {
|
||||
__template: [],
|
||||
__scope_link: "_search.sort"
|
||||
},
|
||||
highlight: {},
|
||||
explain: {__one_of: [true, false]},
|
||||
_source: {
|
||||
__template: "",
|
||||
__scope_link: "_search._source"
|
||||
},
|
||||
script_fields: {
|
||||
__scope_link: "_search.script_fields"
|
||||
},
|
||||
fielddata_fields: ["{field}"],
|
||||
version: {__one_of: [true, false]}
|
||||
},
|
||||
"percentile_ranks": {
|
||||
__template: {
|
||||
field: "",
|
||||
values: [10, 15]
|
||||
},
|
||||
field: "{field}",
|
||||
values: [],
|
||||
"script": {
|
||||
// populated by a global rule
|
||||
},
|
||||
"compression": 100,
|
||||
"method": {__one_of: ["hdr", "tdigest"]},
|
||||
missing: 0
|
||||
},
|
||||
"sampler": {
|
||||
__template: {},
|
||||
"field": "{field}",
|
||||
"script": {
|
||||
// populated by a global rule
|
||||
},
|
||||
"shard_size": 100,
|
||||
"max_docs_per_value": 3,
|
||||
"execution_hint": {__one_of: ["map", "global_ordinals", "bytes_hash"]}
|
||||
},
|
||||
"children": {
|
||||
__template: {
|
||||
"type": "",
|
||||
},
|
||||
"type": ""
|
||||
},
|
||||
"derivative": simple_pipeline,
|
||||
"avg_bucket": simple_pipeline,
|
||||
"max_bucket": simple_pipeline,
|
||||
"min_bucket": simple_pipeline,
|
||||
"sum_bucket": simple_pipeline,
|
||||
"moving_avg": {
|
||||
__template: {
|
||||
buckets_path: ""
|
||||
},
|
||||
buckets_path: "",
|
||||
format: "",
|
||||
gap_policy: gap_policy,
|
||||
"window": 5,
|
||||
model: {__one_of: ["simple", "linear", "ewma", "holt", "holt_winters"]},
|
||||
settings: {
|
||||
type: {__one_of: ["add", "mult"]},
|
||||
alpha: 0.5,
|
||||
beta: 0.5,
|
||||
gamma: 0.5,
|
||||
period: 7
|
||||
}
|
||||
},
|
||||
"cumulative_sum": {
|
||||
__template: {
|
||||
buckets_path: ""
|
||||
},
|
||||
buckets_path: "",
|
||||
format: ""
|
||||
},
|
||||
"serial_diff": {
|
||||
__template: {
|
||||
buckets_path: "",
|
||||
lag: 7
|
||||
},
|
||||
lag: 7,
|
||||
gap_policy: gap_policy,
|
||||
buckets_path: "",
|
||||
format: ""
|
||||
},
|
||||
"bucket_script": {
|
||||
__template: {
|
||||
buckets_path: "",
|
||||
script: {}
|
||||
},
|
||||
buckets_path: "",
|
||||
format: "",
|
||||
gap_policy: gap_policy,
|
||||
script: {
|
||||
// populated by a global rule
|
||||
}
|
||||
},
|
||||
"bucket_selector": {
|
||||
__template: {
|
||||
buckets_path: "",
|
||||
script: {}
|
||||
},
|
||||
buckets_path: "",
|
||||
gap_policy: gap_policy,
|
||||
script: {
|
||||
// populated by a global rule
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
module.exports = function (api) {
|
||||
|
||||
api.addGlobalAutocompleteRules('aggregations', rules);
|
||||
api.addGlobalAutocompleteRules('aggs', rules);
|
||||
};
|
71
src/plugins/console/api_server/es_5_0/aliases.js
Normal file
71
src/plugins/console/api_server/es_5_0/aliases.js
Normal file
|
@ -0,0 +1,71 @@
|
|||
module.exports = function (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",
|
||||
]
|
||||
});
|
||||
|
||||
var aliasRules = {
|
||||
filter: {},
|
||||
routing: '1',
|
||||
search_routing: '1,2',
|
||||
index_routing: '1'
|
||||
};
|
||||
|
||||
api.addEndpointDescription('_post_alias', {
|
||||
methods: ["POST", "PUT"],
|
||||
patterns: [
|
||||
"{indices}/_alias/{name}"
|
||||
],
|
||||
data_autocomplete_rules: aliasRules
|
||||
});
|
||||
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}"
|
||||
]
|
||||
});
|
||||
|
||||
api.addGlobalAutocompleteRules('aliases', {
|
||||
'*': aliasRules
|
||||
});
|
||||
};
|
56
src/plugins/console/api_server/es_5_0/cat.js
Normal file
56
src/plugins/console/api_server/es_5_0/cat.js
Normal file
|
@ -0,0 +1,56 @@
|
|||
let _ = require("lodash");
|
||||
|
||||
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]
|
||||
});
|
||||
}
|
||||
|
||||
function addNodeattrsCat(api) {
|
||||
api.addEndpointDescription('_cat/nodeattrs', {
|
||||
methods: ['GET'],
|
||||
patterns: [
|
||||
"_cat/nodeattrs"
|
||||
],
|
||||
url_params: {
|
||||
help: "__flag__",
|
||||
v: "__flag__",
|
||||
h: ["node", "name", "id", "nodeId", "pid", "p", "host", "h", "ip", "i", "port", "po", "attr", "attr.name", "value", "attr.value"]
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = function (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);
|
||||
addSimpleCat('_cat/plugins', api);
|
||||
addSimpleCat('_cat/segments', api);
|
||||
addNodeattrsCat(api);
|
||||
};
|
142
src/plugins/console/api_server/es_5_0/cluster.js
Normal file
142
src/plugins/console/api_server/es_5_0/cluster.js
Normal file
|
@ -0,0 +1,142 @@
|
|||
module.exports = function (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", "routing_node", "metadata", "blocks"]
|
||||
}
|
||||
});
|
||||
api.addEndpointDescription('_cluster/health', {
|
||||
url_params: {
|
||||
"local": "__flag__",
|
||||
"level": ["indices", "shards"],
|
||||
"master_timeout": "30s",
|
||||
"timeout": "30s",
|
||||
"wait_for_status": ["yellow", "green"],
|
||||
"wait_for_relocating_shards": 0,
|
||||
"wait_for_active_shards": 0,
|
||||
"wait_for_nodes": 0
|
||||
}
|
||||
});
|
||||
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: {
|
||||
cluster: {
|
||||
routing: {
|
||||
'allocation.enable': {__one_of: ["all", "primaries", "new_primaries", "none"]},
|
||||
'allocation.disk.threshold_enabled': {__one_of: [false, true]},
|
||||
'allocation.disk.watermark.low': '85%',
|
||||
'allocation.disk.watermark.high': '90%',
|
||||
'allocation.disk.include_relocations': {__one_of: [true, false]},
|
||||
'allocation.disk.reroute_interval': '60s',
|
||||
'allocation.exclude': {
|
||||
'_ip': "",
|
||||
'_name': "",
|
||||
'_host': "",
|
||||
'_id': ""
|
||||
},
|
||||
'allocation.include': {
|
||||
'_ip': "",
|
||||
'_name': "",
|
||||
'_host': "",
|
||||
'_id': ""
|
||||
},
|
||||
'allocation.require': {
|
||||
'_ip': "",
|
||||
'_name': "",
|
||||
'_host': "",
|
||||
'_id': ""
|
||||
},
|
||||
'allocation.awareness.attributes': [],
|
||||
'allocation.awareness.force': {
|
||||
'*': {
|
||||
'values': []
|
||||
}
|
||||
},
|
||||
'allocation.allow_rebalance': {__one_of: ['always', 'indices_primaries_active', 'indices_all_active']},
|
||||
'allocation.cluster_concurrent_rebalance': 2,
|
||||
'allocation.node_initial_primaries_recoveries': 4,
|
||||
'allocation.node_concurrent_recoveries': 2,
|
||||
'allocation.same_shard.host': {__one_of: [false, true]}
|
||||
}
|
||||
},
|
||||
indices: {
|
||||
breaker: {
|
||||
"total.limit": "70%",
|
||||
"fielddata.limit": "60%",
|
||||
"fielddata.overhead": 1.03,
|
||||
"request.limit": "40%",
|
||||
"request.overhead": 1.0
|
||||
}
|
||||
}
|
||||
},
|
||||
transient: {
|
||||
__scope_link: '.persistent'
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
api.addEndpointDescription('_cluster/reroute', {
|
||||
methods: ['POST'],
|
||||
url_params: {
|
||||
explain: "__flag__",
|
||||
dry_run: "__flag__"
|
||||
},
|
||||
data_autocomplete_rules: {
|
||||
commands: [
|
||||
{
|
||||
move: {
|
||||
__template: {
|
||||
index: "",
|
||||
shard: 0,
|
||||
from_node: "",
|
||||
to_node: ""
|
||||
},
|
||||
index: "{index}",
|
||||
shard: 0,
|
||||
from_node: "{node}",
|
||||
to_node: "{node}"
|
||||
},
|
||||
cancel: {
|
||||
__template: {
|
||||
index: "",
|
||||
shard: 0,
|
||||
node: ""
|
||||
},
|
||||
index: "{index}",
|
||||
shard: 0,
|
||||
node: "{node}",
|
||||
allow_primary: {__one_of: [true, false]}
|
||||
},
|
||||
allocate: {
|
||||
__template: {
|
||||
index: "",
|
||||
shard: 0,
|
||||
node: ""
|
||||
},
|
||||
index: "{index}",
|
||||
shard: 0,
|
||||
node: "{node}",
|
||||
allow_primary: {__one_of: [true, false]}
|
||||
}
|
||||
}
|
||||
],
|
||||
dry_run: {__one_of: [true, false]}
|
||||
}
|
||||
});
|
||||
};
|
22
src/plugins/console/api_server/es_5_0/count.js
Normal file
22
src/plugins/console/api_server/es_5_0/count.js
Normal file
|
@ -0,0 +1,22 @@
|
|||
module.exports = function (api) {
|
||||
api.addEndpointDescription('_count', {
|
||||
methods: ['GET', 'POST'],
|
||||
priority: 10, // collides with get doc by id
|
||||
patterns: [
|
||||
"{indices}/{types}/_count",
|
||||
"{indices}/_count",
|
||||
"_count"
|
||||
],
|
||||
url_params: {
|
||||
preference: ["_primary", "_primary_first", "_local", "_only_node:xyz", "_prefer_node:xyz", "_shards:2,3"],
|
||||
routing: "",
|
||||
min_score: 1.0,
|
||||
terminate_after: 10,
|
||||
},
|
||||
data_autocomplete_rules: {
|
||||
query: {
|
||||
// populated by a global rule
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
233
src/plugins/console/api_server/es_5_0/document.js
Normal file
233
src/plugins/console/api_server/es_5_0/document.js
Normal file
|
@ -0,0 +1,233 @@
|
|||
module.exports = function (api) {
|
||||
api.addEndpointDescription('_get_doc', {
|
||||
methods: ['GET'],
|
||||
patterns: [
|
||||
"{index}/{type}/{id}"
|
||||
],
|
||||
url_params: {
|
||||
"version": 1,
|
||||
"routing": "",
|
||||
"parent": "",
|
||||
"_source": "",
|
||||
"_source_exclude": "",
|
||||
"_source_include": ""
|
||||
}
|
||||
});
|
||||
api.addEndpointDescription('_get_doc_source', {
|
||||
methods: ['GET'],
|
||||
patterns: [
|
||||
"{index}/{type}/{id}/_source"
|
||||
],
|
||||
url_params: {
|
||||
"version": 1,
|
||||
"routing": "",
|
||||
"parent": "",
|
||||
"_source_exclude": "",
|
||||
"_source_include": ""
|
||||
}
|
||||
});
|
||||
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"],
|
||||
"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"],
|
||||
"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"],
|
||||
"refresh": "__flag__",
|
||||
"timeout": "1m"
|
||||
}
|
||||
});
|
||||
|
||||
api.addEndpointDescription('_update', {
|
||||
methods: ['POST'],
|
||||
patterns: [
|
||||
"{index}/{type}/{id}/_update"
|
||||
],
|
||||
url_params: {
|
||||
"version": 1,
|
||||
"version_type": ["force", "internal"],
|
||||
"routing": "",
|
||||
"parent": "",
|
||||
"timestamp": "",
|
||||
"consistency": ["qurom", "one", "all"],
|
||||
"refresh": "__flag__",
|
||||
"timeout": "1m",
|
||||
"retry_on_conflict": 3,
|
||||
"fields": ""
|
||||
},
|
||||
data_autocomplete_rules: {
|
||||
"script": {
|
||||
// populated by a global rule
|
||||
},
|
||||
"doc": {},
|
||||
"upsert": {},
|
||||
"scripted_upsert": {__one_of: [true, false]}
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
api.addEndpointDescription('_put_script', {
|
||||
methods: ['POST', 'PUT'],
|
||||
patterns: [
|
||||
"_scripts/{lang}/{id}",
|
||||
"_scripts/{lang}/{id}/_create"
|
||||
],
|
||||
url_components: {
|
||||
"lang": [
|
||||
"groovy",
|
||||
"expressions"
|
||||
]
|
||||
},
|
||||
data_autocomplete_rules: {
|
||||
"script": ""
|
||||
}
|
||||
});
|
||||
|
||||
api.addEndpointDescription('_termvectors', {
|
||||
methods: ['GET', 'POST'],
|
||||
patterns: [
|
||||
"{index}/{type}/_termvectors"
|
||||
],
|
||||
priority: 10, // collision with get doc
|
||||
url_params: {
|
||||
"fields": "",
|
||||
"offsets": "__flag__",
|
||||
"payloads": "__flag__",
|
||||
"positions": "__flag__",
|
||||
"term_statistics": "__flag__",
|
||||
"field_statistics": "__flag__",
|
||||
"routing": "",
|
||||
"version": 1,
|
||||
"version_type": ["external", "external_gt", "external_gte", "force", "internal"],
|
||||
"parent": "",
|
||||
"preference": ""
|
||||
},
|
||||
data_autocomplete_rules: {
|
||||
fields: [
|
||||
"{field}"
|
||||
],
|
||||
offsets: {__one_of: [false, true]},
|
||||
payloads: {__one_of: [false, true]},
|
||||
positions: {__one_of: [false, true]},
|
||||
term_statistics: {__one_of: [true, false]},
|
||||
field_statistics: {__one_of: [false, true]},
|
||||
per_field_analyzer: {
|
||||
__template: {"FIELD": ""},
|
||||
"{field}": ""
|
||||
},
|
||||
routing: "",
|
||||
version: 1,
|
||||
version_type: ["external", "external_gt", "external_gte", "force", "internal"],
|
||||
doc: {},
|
||||
filter: { // TODO: Exclude from global filter rules
|
||||
"max_num_terms": 1,
|
||||
"min_term_freq": 1,
|
||||
"max_term_freq": 1,
|
||||
"min_doc_freq": 1,
|
||||
"max_doc_freq": 1,
|
||||
"min_word_length": 1,
|
||||
"max_word_length": 1
|
||||
}
|
||||
}
|
||||
});
|
||||
api.addEndpointDescription('_termvectors_id', {
|
||||
methods: ['GET', 'POST'],
|
||||
patterns: [
|
||||
"{index}/{type}/{id}/_termvectors"
|
||||
],
|
||||
url_params: {
|
||||
"fields": "",
|
||||
"offsets": "__flag__",
|
||||
"payloads": "__flag__",
|
||||
"positions": "__flag__",
|
||||
"term_statistics": "__flag__",
|
||||
"field_statistics": "__flag__",
|
||||
"routing": "",
|
||||
"version": 1,
|
||||
"version_type": ["external", "external_gt", "external_gte", "force", "internal"],
|
||||
"parent": "",
|
||||
"preference": "",
|
||||
"dfs": "__flag__"
|
||||
},
|
||||
data_autocomplete_rules: {
|
||||
fields: [
|
||||
"{field}"
|
||||
],
|
||||
offsets: {__one_of: [false, true]},
|
||||
payloads: {__one_of: [false, true]},
|
||||
positions: {__one_of: [false, true]},
|
||||
term_statistics: {__one_of: [true, false]},
|
||||
field_statistics: {__one_of: [false, true]},
|
||||
dfs: {__one_of: [true, false]},
|
||||
per_field_analyzer: {
|
||||
__template: {"FIELD": ""},
|
||||
"{field}": ""
|
||||
},
|
||||
routing: "",
|
||||
version: 1,
|
||||
version_type: ["external", "external_gt", "external_gte", "force", "internal"],
|
||||
filter: { // TODO: Exclude from global filter rules
|
||||
"max_num_terms": 1,
|
||||
"min_term_freq": 1,
|
||||
"max_term_freq": 1,
|
||||
"min_doc_freq": 1,
|
||||
"max_doc_freq": 1,
|
||||
"min_word_length": 1,
|
||||
"max_word_length": 1
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
47
src/plugins/console/api_server/es_5_0/field_stats.js
Normal file
47
src/plugins/console/api_server/es_5_0/field_stats.js
Normal file
|
@ -0,0 +1,47 @@
|
|||
module.exports = function (api) {
|
||||
api.addEndpointDescription('_field_stats', {
|
||||
methods: ['GET', 'POST'],
|
||||
patterns: [
|
||||
"_field_stats",
|
||||
"{indices}/_field_stats"
|
||||
],
|
||||
url_params: {
|
||||
fields: [],
|
||||
level: ["cluster", "indices"],
|
||||
ignore_unavailable: ["true", "false"],
|
||||
allow_no_indices: [false, true],
|
||||
expand_wildcards: ["open", "closed", "none", "all"]
|
||||
},
|
||||
data_autocomplete_rules: {
|
||||
fields: [
|
||||
"{field}",
|
||||
],
|
||||
index_constraints: {
|
||||
"{field}": {
|
||||
min_value: {
|
||||
gt: "MIN",
|
||||
gte: "MAX",
|
||||
lt: "MIN",
|
||||
lte: "MAX"
|
||||
},
|
||||
max_value: {
|
||||
gt: "MIN",
|
||||
gte: "MAX",
|
||||
lt: "MIN",
|
||||
lte: "MAX"
|
||||
}
|
||||
},
|
||||
__template: {
|
||||
"FIELD": {
|
||||
min_value: {
|
||||
gt: "MIN"
|
||||
},
|
||||
max_value: {
|
||||
lt: "MAX"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
336
src/plugins/console/api_server/es_5_0/filter.js
Normal file
336
src/plugins/console/api_server/es_5_0/filter.js
Normal file
|
@ -0,0 +1,336 @@
|
|||
var filters = {};
|
||||
|
||||
filters.and = {
|
||||
__template: {
|
||||
filters: [
|
||||
{}
|
||||
]
|
||||
},
|
||||
filters: [
|
||||
{
|
||||
__scope_link: '.'
|
||||
}
|
||||
],
|
||||
};
|
||||
|
||||
|
||||
filters.bool = {
|
||||
__scope_link: 'GLOBAL.query'
|
||||
};
|
||||
|
||||
|
||||
filters.exists = {
|
||||
__template: {
|
||||
'field': 'FIELD_NAME'
|
||||
},
|
||||
'field': '{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']
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
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
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
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
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
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
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
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',
|
||||
filter: {}
|
||||
},
|
||||
type: '{type}',
|
||||
query: {},
|
||||
filter: {},
|
||||
_scope: '',
|
||||
min_children: 1,
|
||||
max_children: 10
|
||||
};
|
||||
|
||||
|
||||
filters.has_parent = {
|
||||
__template: {
|
||||
parent_type: 'TYPE',
|
||||
filter: {}
|
||||
},
|
||||
parent_type: '{type}',
|
||||
query: {},
|
||||
filter: {},
|
||||
_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: {}
|
||||
};
|
||||
|
||||
|
||||
filters.range = {
|
||||
__template: {
|
||||
'FIELD': {
|
||||
gte: 10,
|
||||
lte: 20
|
||||
}
|
||||
},
|
||||
"{field}": {
|
||||
gte: 1,
|
||||
gt: 1,
|
||||
lte: 20,
|
||||
lt: 20,
|
||||
time_zone: "+1:00",
|
||||
"format": "dd/MM/yyyy||yyyy",
|
||||
execution: {__one_of: ["index", "fielddata"]}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
filters.or = {
|
||||
__template: {
|
||||
filters: [
|
||||
{}
|
||||
]
|
||||
},
|
||||
filters: [
|
||||
{
|
||||
__scope_link: '.'
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
|
||||
filters.prefix = {
|
||||
__template: {
|
||||
'FIELD': 'VALUE'
|
||||
},
|
||||
'{field}': ''
|
||||
};
|
||||
|
||||
|
||||
filters.query = {
|
||||
// global query
|
||||
};
|
||||
|
||||
filters.script = {
|
||||
__template: {
|
||||
script: {}
|
||||
},
|
||||
script: {
|
||||
// populated by a global rule
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
filters.term = {
|
||||
__template: {
|
||||
'FIELD': 'VALUE'
|
||||
},
|
||||
'{field}': ''
|
||||
};
|
||||
|
||||
|
||||
filters.terms = {
|
||||
__template: {
|
||||
'FIELD': ['VALUE1', 'VALUE2']
|
||||
},
|
||||
field: ['{field}'],
|
||||
execution: {
|
||||
__one_of: ['plain', 'bool', 'and', 'or', 'bool_nocache', 'and_nocache', 'or_nocache']
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
filters.nested = {
|
||||
__template: {
|
||||
path: 'path_to_nested_doc',
|
||||
query: {}
|
||||
},
|
||||
query: {},
|
||||
path: '',
|
||||
_name: ''
|
||||
};
|
||||
|
||||
module.exports = function (api) {
|
||||
api.addGlobalAutocompleteRules('filter', filters);
|
||||
};
|
||||
|
24
src/plugins/console/api_server/es_5_0/globals.js
Normal file
24
src/plugins/console/api_server/es_5_0/globals.js
Normal file
|
@ -0,0 +1,24 @@
|
|||
module.exports = function (api) {
|
||||
api.addGlobalAutocompleteRules('highlight', {
|
||||
pre_tags: {},
|
||||
post_tags: {},
|
||||
tags_schema: {},
|
||||
fields: {
|
||||
'{field}': {
|
||||
fragment_size: 20,
|
||||
number_of_fragments: 3
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
api.addGlobalAutocompleteRules('script', {
|
||||
__template: {
|
||||
inline: "SCRIPT"
|
||||
},
|
||||
inline: "SCRIPT",
|
||||
file: "FILE_SCRIPT_NAME",
|
||||
id: "SCRIPT_ID",
|
||||
lang: "",
|
||||
params: {}
|
||||
});
|
||||
};
|
208
src/plugins/console/api_server/es_5_0/indices.js
Normal file
208
src/plugins/console/api_server/es_5_0/indices.js
Normal file
|
@ -0,0 +1,208 @@
|
|||
module.exports = function (api) {
|
||||
api.addEndpointDescription('_refresh', {
|
||||
methods: ['POST'],
|
||||
patterns: [
|
||||
"_refresh",
|
||||
"{indices}/_refresh"
|
||||
],
|
||||
});
|
||||
|
||||
api.addEndpointDescription('_flush', {
|
||||
methods: ['POST'],
|
||||
patterns: [
|
||||
"_flush",
|
||||
"{indices}/_flush"
|
||||
],
|
||||
url_params: {
|
||||
wait_if_ongoing: [true, false],
|
||||
force: [true, false]
|
||||
}
|
||||
});
|
||||
|
||||
api.addEndpointDescription('_flush_synced', {
|
||||
methods: ['POST'],
|
||||
patterns: [
|
||||
"_flush/synced",
|
||||
"{indices}/_flush/synced"
|
||||
]
|
||||
});
|
||||
|
||||
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",
|
||||
"percolate",
|
||||
"segments",
|
||||
"fielddata",
|
||||
"completion",
|
||||
"translog",
|
||||
"query_cache",
|
||||
"commit",
|
||||
"_all"
|
||||
]
|
||||
},
|
||||
url_params: {
|
||||
"fields": [],
|
||||
"types": [],
|
||||
"completion_fields": [],
|
||||
"fielddata_fields": [],
|
||||
"level": ["cluster", "indices", "shards"]
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
api.addEndpointDescription('_segments', {
|
||||
patterns: [
|
||||
"{indices}/_segments",
|
||||
"_segments"
|
||||
]
|
||||
});
|
||||
|
||||
api.addEndpointDescription('_recovery', {
|
||||
patterns: [
|
||||
"{indices}/_recovery",
|
||||
"_recovery"
|
||||
],
|
||||
url_params: {
|
||||
detailed: "__flag__",
|
||||
active_only: "__flag__",
|
||||
human: "__flag__"
|
||||
}
|
||||
});
|
||||
|
||||
api.addEndpointDescription('_analyze', {
|
||||
methods: ['GET', 'POST'],
|
||||
patterns: [
|
||||
"{indices}/_analyze",
|
||||
"_analyze"
|
||||
],
|
||||
url_params: {
|
||||
"analyzer": "",
|
||||
"char_filters": [],
|
||||
"field": "",
|
||||
"filters": [],
|
||||
"text": "",
|
||||
"tokenizer": ""
|
||||
}
|
||||
});
|
||||
|
||||
api.addEndpointDescription('_validate_query', {
|
||||
methods: ['GET', 'POST'],
|
||||
patterns: [
|
||||
"{indices}/_validate/query",
|
||||
"_validate/query"
|
||||
],
|
||||
url_params: {
|
||||
explain: "__flag__",
|
||||
rewrite: "__flag__"
|
||||
},
|
||||
data_autocomplete_rules: {
|
||||
query: {
|
||||
// populated by a global rule
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
api.addEndpointDescription('_shard_stores', {
|
||||
methods: ['GET'],
|
||||
patterns: [
|
||||
"{indices}/_shard_stores",
|
||||
"_shard_stores"
|
||||
],
|
||||
url_params: {
|
||||
status: ["green", "yellow", "red", "all"]
|
||||
}
|
||||
});
|
||||
|
||||
api.addEndpointDescription('__create_index__', {
|
||||
methods: ['PUT'],
|
||||
patterns: [
|
||||
"{index}"
|
||||
],
|
||||
data_autocomplete_rules: {
|
||||
mappings: {
|
||||
__scope_link: '_put_mapping'
|
||||
},
|
||||
settings: {
|
||||
__scope_link: '_put_settings'
|
||||
},
|
||||
aliases: {
|
||||
__template: {
|
||||
"NAME": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
api.addEndpointDescription('__delete_indices__', {
|
||||
methods: ['DELETE'],
|
||||
patterns: [
|
||||
"{indices}"
|
||||
]
|
||||
});
|
||||
|
||||
api.addEndpointDescription('_get_index_settings', {
|
||||
methods: ['GET',],
|
||||
patterns: [
|
||||
"{indices}/_settings",
|
||||
],
|
||||
url_params: {
|
||||
flat_settings: "__flag__"
|
||||
}
|
||||
});
|
||||
|
||||
api.addEndpointDescription('_get_index', {
|
||||
methods: ['GET',],
|
||||
patterns: [
|
||||
"{indices}",
|
||||
"{indices}/{feature}"
|
||||
],
|
||||
url_components: {
|
||||
"feature": [
|
||||
"_mappings",
|
||||
"_aliases"
|
||||
]
|
||||
}
|
||||
});
|
||||
|
||||
api.addEndpointDescription('_cache/clear', {
|
||||
patterns: [
|
||||
"_cache/clear",
|
||||
"{indices}/_cache/clear"
|
||||
]
|
||||
});
|
||||
|
||||
api.addEndpointDescription('_upgrade', {
|
||||
methods: ["POST"],
|
||||
patterns: [
|
||||
"_upgrade",
|
||||
"{indices}/_upgrade"
|
||||
],
|
||||
url_params: {
|
||||
wait_for_completion: "__flag__"
|
||||
}
|
||||
});
|
||||
|
||||
api.addEndpointDescription('_upgrade_status', {
|
||||
methods: ["GET"],
|
||||
patterns: [
|
||||
"_upgrade",
|
||||
"{indices}/_upgrade"
|
||||
]
|
||||
});
|
||||
};
|
218
src/plugins/console/api_server/es_5_0/mappings.js
Normal file
218
src/plugins/console/api_server/es_5_0/mappings.js
Normal file
|
@ -0,0 +1,218 @@
|
|||
let _ = require("lodash");
|
||||
|
||||
var BOOLEAN = {
|
||||
__one_of: [true, false]
|
||||
};
|
||||
|
||||
module.exports = function (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('_get_field_mapping', {
|
||||
methods: ['GET'],
|
||||
priority: 10, // collides with get doc by id
|
||||
patterns: [
|
||||
"{indices}/_mapping/field/{fields}",
|
||||
"{indices}/_mapping/{type}/field/{fields}"
|
||||
],
|
||||
url_params: {
|
||||
"include_defaults": "__flag__"
|
||||
}
|
||||
});
|
||||
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': {}
|
||||
}
|
||||
},
|
||||
'_source': {
|
||||
'enabled': BOOLEAN
|
||||
},
|
||||
'_all': {
|
||||
'enabled': BOOLEAN
|
||||
},
|
||||
'_field_names': {
|
||||
'index': BOOLEAN
|
||||
},
|
||||
'_routing': {
|
||||
'required': BOOLEAN,
|
||||
},
|
||||
'_index': {
|
||||
'enabled': BOOLEAN
|
||||
},
|
||||
'_parent': {
|
||||
__template: {
|
||||
'type': ''
|
||||
},
|
||||
'type': '{type}'
|
||||
},
|
||||
'_timestamp': {
|
||||
'enabled': BOOLEAN,
|
||||
'format': 'YYYY-MM-dd',
|
||||
'default': ""
|
||||
},
|
||||
'dynamic_date_formats': ['yyyy-MM-dd'],
|
||||
'date_detection': BOOLEAN,
|
||||
'numeric_detection': BOOLEAN,
|
||||
'properties': {
|
||||
'*': {
|
||||
type: {
|
||||
__one_of: ['text', 'keyword', 'float', 'double', 'byte', 'short', 'integer', 'long', 'date', 'boolean',
|
||||
'binary', 'object', 'nested', "geo_point", "geo_shape"
|
||||
]
|
||||
},
|
||||
|
||||
// strings
|
||||
store: BOOLEAN,
|
||||
index: BOOLEAN,
|
||||
term_vector: {
|
||||
__one_of: ['no', 'yes', 'with_offsets', 'with_positions', 'with_positions_offsets']
|
||||
},
|
||||
boost: 1.0,
|
||||
null_value: '',
|
||||
|
||||
norms: BOOLEAN,
|
||||
|
||||
index_options: {
|
||||
__one_of: ['docs', 'freqs', 'positions']
|
||||
},
|
||||
analyzer: 'standard',
|
||||
search_analyzer: 'standard',
|
||||
include_in_all: {
|
||||
__one_of: [false, true]
|
||||
},
|
||||
ignore_above: 10,
|
||||
position_increment_gap: 0,
|
||||
|
||||
// numeric
|
||||
precision_step: 4,
|
||||
ignore_malformed: BOOLEAN,
|
||||
|
||||
// geo_point
|
||||
lat_lon: {
|
||||
__one_of: [true, false]
|
||||
},
|
||||
geohash: {
|
||||
__one_of: [true, false]
|
||||
},
|
||||
geohash_precision: '1m',
|
||||
geohash_prefix: {
|
||||
__one_of: [true, false]
|
||||
},
|
||||
validate: {
|
||||
__one_of: [true, false]
|
||||
},
|
||||
validate_lat: {
|
||||
__one_of: [true, false]
|
||||
},
|
||||
validate_lon: {
|
||||
__one_of: [true, false]
|
||||
},
|
||||
normalize: {
|
||||
__one_of: [true, false]
|
||||
},
|
||||
normalize_lat: {
|
||||
__one_of: [true, false]
|
||||
},
|
||||
normalize_lon: {
|
||||
__one_of: [true, false]
|
||||
},
|
||||
|
||||
// geo_shape
|
||||
tree: {
|
||||
__one_of: ['geohash', 'quadtree']
|
||||
},
|
||||
precision: '5km',
|
||||
tree_levels: 12,
|
||||
distance_error_pct: 0.025,
|
||||
orientation: 'ccw',
|
||||
|
||||
// dates
|
||||
format: {
|
||||
__one_of: _.flatten([_.map(['date', 'date_time', 'date_time_no_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', 'week_date_time_no_millis'], function (s) {
|
||||
return ['basic_' + s, 'strict_' + s];
|
||||
}),
|
||||
[
|
||||
'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', 'epoch_millis', 'epoch_second'
|
||||
]])
|
||||
},
|
||||
|
||||
fielddata: {
|
||||
filter: {
|
||||
regex: '',
|
||||
frequency: {
|
||||
min: 0.001,
|
||||
max: 0.1,
|
||||
min_segment_size: 500
|
||||
}
|
||||
}
|
||||
},
|
||||
similarity: {
|
||||
__one_of: ['default', 'BM25']
|
||||
},
|
||||
|
||||
// objects
|
||||
properties: {
|
||||
__scope_link: '_put_mapping.{type}.properties'
|
||||
},
|
||||
|
||||
// multi_field
|
||||
fields: {
|
||||
'*': {
|
||||
__scope_link: '_put_mapping.type.properties.field'
|
||||
}
|
||||
},
|
||||
copy_to: {__one_of: ['{field}', ['{field}']]},
|
||||
|
||||
// nested
|
||||
include_in_parent: BOOLEAN,
|
||||
include_in_root: BOOLEAN
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
api.addEndpointDescription('_put_mapping', {
|
||||
methods: ['PUT'],
|
||||
patterns: [
|
||||
"{indices}/_mapping"
|
||||
],
|
||||
data_autocomplete_rules: {
|
||||
'{type}': {
|
||||
__scope_link: '_put_type_mapping'
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
76
src/plugins/console/api_server/es_5_0/nodes.js
Normal file
76
src/plugins/console/api_server/es_5_0/nodes.js
Normal file
|
@ -0,0 +1,76 @@
|
|||
module.exports = function (api) {
|
||||
api.addEndpointDescription('_nodes/hot_threads', {
|
||||
methods: ['GET'],
|
||||
patterns: [
|
||||
"_nodes/hot_threads",
|
||||
"_nodes/{nodes}/hot_threads"
|
||||
]
|
||||
});
|
||||
api.addEndpointDescription('_nodes/info', {
|
||||
patterns: [
|
||||
"_nodes",
|
||||
"_nodes/{metrics}",
|
||||
"_nodes/{nodes}",
|
||||
"_nodes/{nodes}/{metrics}",
|
||||
"_nodes/{nodes}/info/{metrics}"
|
||||
],
|
||||
url_components: {
|
||||
"metrics": [
|
||||
"settings",
|
||||
"os",
|
||||
"process",
|
||||
"jvm",
|
||||
"thread_pool",
|
||||
"network",
|
||||
"transport",
|
||||
"http",
|
||||
"plugins",
|
||||
"_all"
|
||||
]
|
||||
}
|
||||
});
|
||||
api.addEndpointDescription('_nodes/stats', {
|
||||
patterns: [
|
||||
"_nodes/stats",
|
||||
"_nodes/stats/{metrics}",
|
||||
"_nodes/stats/{metrics}/{index_metric}",
|
||||
"_nodes/{nodes}/stats",
|
||||
"_nodes/{nodes}/stats/{metrics}",
|
||||
"_nodes/{nodes}/stats/{metrics}/{index_metric}"
|
||||
],
|
||||
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",
|
||||
"fielddata",
|
||||
"docs",
|
||||
"warmer",
|
||||
"percolate",
|
||||
"completion",
|
||||
"segments",
|
||||
"translog",
|
||||
"query_cache",
|
||||
"_all"
|
||||
]
|
||||
}
|
||||
});
|
||||
};
|
90
src/plugins/console/api_server/es_5_0/percolator.js
Normal file
90
src/plugins/console/api_server/es_5_0/percolator.js
Normal file
|
@ -0,0 +1,90 @@
|
|||
module.exports = function (api) {
|
||||
api.addEndpointDescription('_put_percolator', {
|
||||
priority: 10, // to override doc
|
||||
methods: ['PUT', 'POST'],
|
||||
patterns: [
|
||||
"{index}/.percolator/{id}"
|
||||
],
|
||||
url_params: {
|
||||
"version": 1,
|
||||
"version_type": ["external", "internal"],
|
||||
"op_type": ["create"],
|
||||
"routing": "",
|
||||
"parent": "",
|
||||
"timestamp": "",
|
||||
"ttl": "5m",
|
||||
"consistency": ["qurom", "one", "all"],
|
||||
"refresh": "__flag__",
|
||||
"timeout": "1m"
|
||||
},
|
||||
data_autocomplete_rules: {
|
||||
query: {}
|
||||
}
|
||||
});
|
||||
api.addEndpointDescription('_percolate', {
|
||||
methods: ['GET', 'POST'],
|
||||
priority: 10, // to override doc
|
||||
patterns: [
|
||||
"{indices}/{type}/_percolate"
|
||||
],
|
||||
url_params: {
|
||||
preference: ["_primary", "_primary_first", "_local", "_only_node:xyz", "_prefer_node:xyz", "_shards:2,3"],
|
||||
routing: "",
|
||||
ignore_unavailable: ["true", "false"],
|
||||
percolate_format: ["ids"]
|
||||
},
|
||||
data_autocomplete_rules: {
|
||||
doc: {},
|
||||
query: {},
|
||||
filter: {},
|
||||
size: 10,
|
||||
track_scores: {__one_of: [true, false]},
|
||||
sort: "_score",
|
||||
aggs: {},
|
||||
highlight: {}
|
||||
}
|
||||
});
|
||||
api.addEndpointDescription('_percolate_id', {
|
||||
methods: ['GET', 'POST'],
|
||||
patterns: [
|
||||
"{indices}/{type}/{id}/_percolate"
|
||||
],
|
||||
url_params: {
|
||||
routing: "",
|
||||
ignore_unavailable: ["true", "false"],
|
||||
percolate_format: ["ids"],
|
||||
percolate_index: "{index}",
|
||||
percolate_type: "{type}",
|
||||
percolate_routing: "",
|
||||
percolate_preference: ["_primary", "_primary_first", "_local", "_only_node:xyz", "_prefer_node:xyz", "_shards:2,3"],
|
||||
version: 1,
|
||||
version_type: ["external", "internal"]
|
||||
},
|
||||
data_autocomplete_rules: {
|
||||
query: {},
|
||||
filter: {},
|
||||
size: 10,
|
||||
track_scores: {__one_of: [true, false]},
|
||||
sort: "_score",
|
||||
aggs: {},
|
||||
highlight: {}
|
||||
}
|
||||
});
|
||||
api.addEndpointDescription('_percolate_count', {
|
||||
methods: ['GET', 'POST'],
|
||||
patterns: [
|
||||
"{indices}/{type}/_percolate/count"
|
||||
],
|
||||
url_params: {
|
||||
preference: ["_primary", "_primary_first", "_local", "_only_node:xyz", "_prefer_node:xyz", "_shards:2,3"],
|
||||
routing: "",
|
||||
ignore_unavailable: ["true", "false"],
|
||||
percolate_format: ["ids"]
|
||||
},
|
||||
data_autocomplete_rules: {
|
||||
doc: {},
|
||||
query: {},
|
||||
filter: {}
|
||||
}
|
||||
});
|
||||
};
|
618
src/plugins/console/api_server/es_5_0/query.js
Normal file
618
src/plugins/console/api_server/es_5_0/query.js
Normal file
|
@ -0,0 +1,618 @@
|
|||
let _ = require("lodash");
|
||||
|
||||
var SPAN_QUERIES = {
|
||||
// TODO add one_of for objects
|
||||
span_first: {
|
||||
__scope_link: '.span_first'
|
||||
},
|
||||
span_near: {
|
||||
__scope_link: '.span_near'
|
||||
},
|
||||
span_or: {
|
||||
__scope_link: '.span_or'
|
||||
},
|
||||
span_not: {
|
||||
__scope_link: '.span_not'
|
||||
},
|
||||
span_term: {
|
||||
__scope_link: '.span_term'
|
||||
},
|
||||
span_containing: {
|
||||
__scope_link: '.span_containing'
|
||||
},
|
||||
span_within: {
|
||||
__scope_link: '.span_within'
|
||||
}
|
||||
};
|
||||
|
||||
var DECAY_FUNC_DESC = {
|
||||
__template: {
|
||||
"FIELD": {
|
||||
"origin": "",
|
||||
"scale": ""
|
||||
}
|
||||
},
|
||||
"{field}": {
|
||||
"origin": "",
|
||||
"scale": "",
|
||||
"offset": "",
|
||||
"decay": 0.5
|
||||
}
|
||||
},
|
||||
SCORING_FUNCS = {
|
||||
"script_score": {
|
||||
__template: {
|
||||
"script": "_score * doc['f'].value"
|
||||
},
|
||||
"script": {
|
||||
//populated by a global rule
|
||||
}
|
||||
},
|
||||
"boost_factor": 2.0,
|
||||
"random_score": {
|
||||
"seed": 314159265359
|
||||
},
|
||||
"linear": DECAY_FUNC_DESC,
|
||||
"exp": DECAY_FUNC_DESC,
|
||||
"gauss": DECAY_FUNC_DESC,
|
||||
"field_value_factor": {
|
||||
__template: {
|
||||
"field": ""
|
||||
},
|
||||
"field": "{field}",
|
||||
"factor": 1.2,
|
||||
"modifier": {
|
||||
__one_of: ["none", "log", "log1p", "log2p", "ln", "ln1p", "ln2p", "square", "sqrt", "reciprocal"]
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = function (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,
|
||||
type: {__one_of: ['best_fields', 'most_fields', 'cross_fields', 'phrase', 'phrase_prefix']}
|
||||
},
|
||||
bool: {
|
||||
must: [
|
||||
{
|
||||
__scope_link: '.'
|
||||
}
|
||||
],
|
||||
must_not: [
|
||||
{
|
||||
__scope_link: '.'
|
||||
}
|
||||
],
|
||||
should: [
|
||||
{
|
||||
__scope_link: '.'
|
||||
}
|
||||
],
|
||||
filter: {
|
||||
__scope_link: 'GLOBAL.filter'
|
||||
},
|
||||
minimum_number_should_match: 1,
|
||||
boost: 1.0
|
||||
},
|
||||
boosting: {
|
||||
positive: {
|
||||
__scope_link: '.'
|
||||
},
|
||||
negative: {
|
||||
__scope_link: '.'
|
||||
},
|
||||
negative_boost: 0.2
|
||||
},
|
||||
ids: {
|
||||
type: '',
|
||||
values: []
|
||||
},
|
||||
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: '.'
|
||||
}
|
||||
]
|
||||
},
|
||||
field: {
|
||||
'{field}': {
|
||||
query: '',
|
||||
boost: 2.0,
|
||||
enable_position_increments: {
|
||||
__template: false,
|
||||
__one_of: [true, false]
|
||||
}
|
||||
}
|
||||
},
|
||||
fuzzy: {
|
||||
'{field}': {
|
||||
'value': '',
|
||||
'boost': 1.0,
|
||||
'fuzziness': 0.5,
|
||||
'prefix_length': 0
|
||||
}
|
||||
},
|
||||
has_child: {
|
||||
__template: {
|
||||
type: 'TYPE',
|
||||
query: {}
|
||||
},
|
||||
'type': '{type}',
|
||||
'score_mode': {
|
||||
__one_of: ['none', 'max', 'sum', 'avg']
|
||||
},
|
||||
'_scope': '',
|
||||
'query': {},
|
||||
'min_children': 1,
|
||||
'max_children': 10
|
||||
},
|
||||
has_parent: {
|
||||
__template: {
|
||||
parent_type: 'TYPE',
|
||||
query: {}
|
||||
},
|
||||
'parent_type': '{type}',
|
||||
'score_mode': {
|
||||
__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: '',
|
||||
docs: [{
|
||||
_index: "{index}",
|
||||
_type: "{type}",
|
||||
_id: ""
|
||||
}],
|
||||
ids: [""]
|
||||
},
|
||||
mlt: {
|
||||
__template: {
|
||||
'fields': ['FIELD'],
|
||||
'like_text': 'text like this one',
|
||||
'min_term_freq': 1,
|
||||
'max_query_terms': 12
|
||||
},
|
||||
__scope_link: ".more_like_this"
|
||||
},
|
||||
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,
|
||||
fuzziness: 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,
|
||||
time_zone: "+1:00"
|
||||
},
|
||||
simple_query_string: {
|
||||
__template: {
|
||||
query: "",
|
||||
fields: []
|
||||
},
|
||||
query: "",
|
||||
fields: ["{field}"],
|
||||
default_operator: {__one_of: ["OR", "AND"]},
|
||||
analyzer: "",
|
||||
flags: "OR|AND|PREFIX",
|
||||
lowercase_expanded_terms: {__one_of: [true, false]},
|
||||
locale: "ROOT",
|
||||
lenient: {__one_of: [true, false]}
|
||||
},
|
||||
range: {
|
||||
__template: {
|
||||
'FIELD': {
|
||||
gte: 10,
|
||||
lte: 20
|
||||
}
|
||||
},
|
||||
'{field}': {
|
||||
__template: {
|
||||
gte: 10,
|
||||
lte: 20
|
||||
},
|
||||
gte: 10,
|
||||
gt: 10,
|
||||
lte: 20,
|
||||
lt: 20,
|
||||
time_zone: "+1:00",
|
||||
boost: 1.0,
|
||||
"format": "dd/MM/yyyy||yyyy"
|
||||
|
||||
}
|
||||
},
|
||||
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
|
||||
]
|
||||
},
|
||||
span_containing: {
|
||||
__template: {
|
||||
little: {
|
||||
span_term: {
|
||||
'FIELD': {
|
||||
'value': 'VALUE'
|
||||
}
|
||||
}
|
||||
},
|
||||
big: {
|
||||
span_near: {
|
||||
'clauses': [
|
||||
{
|
||||
span_term: {
|
||||
'FIELD': {
|
||||
'value': 'VALUE'
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
span_term: {
|
||||
'FIELD': {
|
||||
'value': 'VALUE'
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"slop": 5,
|
||||
"in_order": false
|
||||
}
|
||||
}
|
||||
},
|
||||
little: SPAN_QUERIES,
|
||||
big: SPAN_QUERIES
|
||||
},
|
||||
span_within: {
|
||||
__template: {
|
||||
little: {
|
||||
span_term: {
|
||||
'FIELD': {
|
||||
'value': 'VALUE'
|
||||
}
|
||||
}
|
||||
},
|
||||
big: {
|
||||
span_near: {
|
||||
'clauses': [
|
||||
{
|
||||
span_term: {
|
||||
'FIELD': {
|
||||
'value': 'VALUE'
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
span_term: {
|
||||
'FIELD': {
|
||||
'value': 'VALUE'
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"slop": 5,
|
||||
"in_order": false
|
||||
}
|
||||
}
|
||||
},
|
||||
little: SPAN_QUERIES,
|
||||
big: SPAN_QUERIES
|
||||
},
|
||||
term: {
|
||||
__template: {
|
||||
'FIELD': {
|
||||
value: 'VALUE'
|
||||
}
|
||||
},
|
||||
'{field}': {
|
||||
value: '',
|
||||
boost: 2.0
|
||||
}
|
||||
},
|
||||
terms: {
|
||||
__template: {
|
||||
'FIELD': ['VALUE1', 'VALUE2']
|
||||
},
|
||||
'{field}': ['']
|
||||
},
|
||||
wildcard: {
|
||||
__template: {
|
||||
'FIELD': {
|
||||
value: 'VALUE'
|
||||
}
|
||||
},
|
||||
'{field}': {
|
||||
value: '',
|
||||
boost: 2.0
|
||||
}
|
||||
},
|
||||
nested: {
|
||||
__template: {
|
||||
path: 'path_to_nested_doc',
|
||||
query: {}
|
||||
},
|
||||
path: '',
|
||||
query: {},
|
||||
score_mode: {
|
||||
__one_of: ['avg', 'total', 'max', 'none']
|
||||
}
|
||||
},
|
||||
custom_filters_score: {
|
||||
__template: {
|
||||
query: {},
|
||||
filters: [
|
||||
{
|
||||
filter: {}
|
||||
}
|
||||
]
|
||||
},
|
||||
query: {},
|
||||
filters: [
|
||||
{
|
||||
filter: {},
|
||||
boost: 2.0,
|
||||
script: {
|
||||
//populated by a global rule
|
||||
}
|
||||
}
|
||||
],
|
||||
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: '.'
|
||||
}
|
||||
},
|
||||
geo_shape: {
|
||||
__template: {
|
||||
location: {},
|
||||
relation: 'within'
|
||||
},
|
||||
__scope_link: '.filter.geo_shape'
|
||||
},
|
||||
// js hint gets confused here
|
||||
/* jshint -W015 */
|
||||
function_score: _.defaults({
|
||||
__template: {
|
||||
query: {},
|
||||
functions: [
|
||||
{}
|
||||
]
|
||||
},
|
||||
query: {},
|
||||
functions: [
|
||||
_.defaults(
|
||||
{
|
||||
filter: {},
|
||||
weight: 1.0
|
||||
},
|
||||
SCORING_FUNCS
|
||||
)
|
||||
],
|
||||
boost: 1.0,
|
||||
boost_mode: {__one_of: ["multiply", "replace", "sum", "avg", "max", "min"]},
|
||||
score_mode: {__one_of: ["multiply", "sum", "first", "avg", "max", "min"]},
|
||||
max_boost: 10,
|
||||
min_score: 1.0
|
||||
},
|
||||
SCORING_FUNCS
|
||||
)
|
||||
|
||||
});
|
||||
};
|
255
src/plugins/console/api_server/es_5_0/search.js
Normal file
255
src/plugins/console/api_server/es_5_0/search.js
Normal file
|
@ -0,0 +1,255 @@
|
|||
module.exports = function (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"],
|
||||
terminate_after: 10,
|
||||
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: "",
|
||||
request_cache: ["true", "false"]
|
||||
},
|
||||
data_autocomplete_rules: {
|
||||
query: {
|
||||
// populated by a global rule
|
||||
},
|
||||
aggs: {
|
||||
__template: {
|
||||
"NAME": {
|
||||
"AGG_TYPE": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
post_filter: {
|
||||
__scope_link: 'GLOBAL.filter'
|
||||
},
|
||||
size: {
|
||||
__template: 20
|
||||
},
|
||||
from: 0,
|
||||
sort: {
|
||||
__template: [
|
||||
{
|
||||
'FIELD': {
|
||||
'order': 'desc'
|
||||
}
|
||||
}
|
||||
],
|
||||
__any_of: [
|
||||
{
|
||||
'{field}': {
|
||||
'order': {
|
||||
__one_of: ['desc', 'asc']
|
||||
},
|
||||
missing: {
|
||||
__one_of: ['_last', '_first']
|
||||
},
|
||||
mode: {
|
||||
__one_of: ['min', 'max', 'avg', 'sum']
|
||||
},
|
||||
nested_path: "",
|
||||
nested_filter: {
|
||||
__scope_link: "GLOBAL.filter"
|
||||
}
|
||||
}
|
||||
},
|
||||
'{field}',
|
||||
'_score',
|
||||
{
|
||||
'_geo_distance': {
|
||||
__template: {
|
||||
"FIELD": {
|
||||
lat: 40,
|
||||
lon: -70
|
||||
},
|
||||
order: "asc"
|
||||
},
|
||||
"{field}": {
|
||||
__one_of: [
|
||||
{
|
||||
__template: {
|
||||
lat: 40,
|
||||
lon: -70
|
||||
},
|
||||
lat: 40,
|
||||
lon: -70
|
||||
},
|
||||
[
|
||||
{
|
||||
__template: {
|
||||
lat: 40,
|
||||
lon: -70
|
||||
},
|
||||
lat: 40,
|
||||
lon: -70
|
||||
}
|
||||
],
|
||||
[""],
|
||||
""
|
||||
]
|
||||
},
|
||||
distance_type: {__one_of: ["sloppy_arc", "arc", "plane"]},
|
||||
sort_mode: {__one_of: ["min", "max", "avg"]},
|
||||
order: {__one_of: ["asc", "desc"]},
|
||||
unit: "km"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
fields: ['{field}'],
|
||||
fielddata_fields: ["{field}"],
|
||||
script_fields: {
|
||||
__template: {
|
||||
'FIELD': {
|
||||
'script': {
|
||||
// populated by a global rule
|
||||
}
|
||||
}
|
||||
},
|
||||
'*': {
|
||||
__scope_link: 'GLOBAL.script'
|
||||
}
|
||||
},
|
||||
partial_fields: {
|
||||
__template: {
|
||||
'NAME': {
|
||||
include: []
|
||||
}
|
||||
},
|
||||
'*': {
|
||||
include: [],
|
||||
exclude: []
|
||||
}
|
||||
},
|
||||
highlight: {
|
||||
// populated by a global rule
|
||||
},
|
||||
_source: {
|
||||
__one_of: [
|
||||
"{field}",
|
||||
["{field}"],
|
||||
{
|
||||
"include": {
|
||||
__one_of: [
|
||||
"{field}",
|
||||
["{field}"]
|
||||
]
|
||||
},
|
||||
"exclude": {
|
||||
__one_of: [
|
||||
"{field}",
|
||||
["{field}"]
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
explain: {
|
||||
__one_of: [true, false]
|
||||
},
|
||||
stats: [''],
|
||||
timeout: "1s",
|
||||
version: {__one_of: [true, false]}
|
||||
}
|
||||
});
|
||||
|
||||
api.addEndpointDescription('_search_template', {
|
||||
methods: ['GET'],
|
||||
patterns: [
|
||||
"{indices}/{types}/_search/template",
|
||||
"{indices}/_search/template",
|
||||
"_search/template"
|
||||
],
|
||||
data_autocomplete_rules: {
|
||||
"template": {
|
||||
__one_of: [
|
||||
{__scope_link: "_search"},
|
||||
{__scope_link: "GLOBAL.script"}
|
||||
]
|
||||
},
|
||||
"params": {}
|
||||
}
|
||||
});
|
||||
|
||||
api.addEndpointDescription('_render_search_template', {
|
||||
methods: ['GET'],
|
||||
patterns: [
|
||||
"_render/template"
|
||||
],
|
||||
data_autocomplete_rules: {
|
||||
__one_of: [
|
||||
{"inline": {__scope_link: "_search"}},
|
||||
{__scope_link: "GLOBAL.script"}
|
||||
],
|
||||
"params": {}
|
||||
}
|
||||
});
|
||||
|
||||
api.addEndpointDescription('_render_search_template_with_id', {
|
||||
methods: ['GET'],
|
||||
patterns: [
|
||||
"_render/template/{id}"
|
||||
],
|
||||
data_autocomplete_rules: {
|
||||
"params": {}
|
||||
}
|
||||
});
|
||||
|
||||
api.addEndpointDescription('_get_delete_search_template', {
|
||||
methods: ['GET', 'DELETE'],
|
||||
patterns: [
|
||||
"_search/template/{id}"
|
||||
]
|
||||
});
|
||||
|
||||
api.addEndpointDescription('_put_search_template', {
|
||||
methods: ['PUT'],
|
||||
patterns: [
|
||||
"_search/template/{id}"
|
||||
],
|
||||
data_autocomplete_rules: {
|
||||
"template": {
|
||||
__scope_link: "_search"
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
api.addEndpointDescription('_search_shards', {
|
||||
methods: ['GET'],
|
||||
priority: 10, // collides with get doc by id
|
||||
patterns: [
|
||||
"{indices}/{types}/_search_shards",
|
||||
"{indices}/_search_shards",
|
||||
"_search_shards"
|
||||
],
|
||||
url_params: {
|
||||
preference: ["_primary", "_primary_first", "_local", "_only_node:xyz", "_prefer_node:xyz", "_shards:2,3"],
|
||||
routing: "",
|
||||
local: "__flag__"
|
||||
}
|
||||
});
|
||||
};
|
86
src/plugins/console/api_server/es_5_0/settings.js
Normal file
86
src/plugins/console/api_server/es_5_0/settings.js
Normal file
|
@ -0,0 +1,86 @@
|
|||
module.exports = function (api) {
|
||||
|
||||
api.addEndpointDescription('_get_settings', {
|
||||
patterns: [
|
||||
"{indices}/_settings",
|
||||
"_settings"
|
||||
],
|
||||
url_params: {
|
||||
flat_settings: "__flag__"
|
||||
}
|
||||
});
|
||||
api.addEndpointDescription('_put_settings', {
|
||||
methods: ['PUT'],
|
||||
patterns: [
|
||||
"{indices}/_settings",
|
||||
"_settings"
|
||||
],
|
||||
data_autocomplete_rules: {
|
||||
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: {}
|
||||
},
|
||||
'cache.query.enable': {
|
||||
__one_of: [true, false]
|
||||
},
|
||||
shadow_replicas: {
|
||||
__one_of: [true, false]
|
||||
},
|
||||
shared_filesystem: {
|
||||
__one_of: [true, false]
|
||||
},
|
||||
data_path: 'path',
|
||||
codec: {
|
||||
__one_of: ['default', 'best_compression', 'lucene_default']
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
153
src/plugins/console/api_server/es_5_0/snapshot_restore.js
Normal file
153
src/plugins/console/api_server/es_5_0/snapshot_restore.js
Normal file
|
@ -0,0 +1,153 @@
|
|||
module.exports = function (api) {
|
||||
api.addEndpointDescription('restore_snapshot', {
|
||||
methods: ['POST'],
|
||||
patterns: [
|
||||
'_snapshot/{id}/{id}/_restore'
|
||||
],
|
||||
url_params: {
|
||||
wait_for_completion: "__flag__"
|
||||
},
|
||||
data_autocomplete_rules: {
|
||||
indices: "*",
|
||||
ignore_unavailable: {__one_of: [true, false]},
|
||||
include_global_state: false,
|
||||
rename_pattern: "index_(.+)",
|
||||
rename_replacement: "restored_index_$1"
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
api.addEndpointDescription('single_snapshot', {
|
||||
methods: ['GET', 'DELETE'],
|
||||
patterns: [
|
||||
'_snapshot/{id}/{id}'
|
||||
]
|
||||
});
|
||||
|
||||
api.addEndpointDescription('all_snapshots', {
|
||||
methods: ['GET'],
|
||||
patterns: [
|
||||
'_snapshot/{id}/_all'
|
||||
]
|
||||
});
|
||||
|
||||
api.addEndpointDescription('put_snapshot', {
|
||||
methods: ['PUT'],
|
||||
patterns: [
|
||||
'_snapshot/{id}/{id}'
|
||||
],
|
||||
url_params: {
|
||||
wait_for_completion: "__flag__"
|
||||
},
|
||||
data_autocomplete_rules: {
|
||||
indices: "*",
|
||||
ignore_unavailable: {__one_of: [true, false]},
|
||||
include_global_state: {__one_of: [true, false]},
|
||||
partial: {__one_of: [true, false]}
|
||||
}
|
||||
});
|
||||
|
||||
api.addEndpointDescription('_snapshot_status', {
|
||||
methods: ['GET'],
|
||||
patterns: [
|
||||
'_snapshot/_status',
|
||||
'_snapshot/{id}/_status',
|
||||
'_snapshot/{id}/{ids}/_status'
|
||||
]
|
||||
});
|
||||
|
||||
|
||||
function getRepositoryType(context, editor) {
|
||||
var iter = editor.iterForCurrentLoc();
|
||||
// for now just iterate back to the first "type" key
|
||||
var t = iter.getCurrentToken();
|
||||
var type;
|
||||
while (t && t.type.indexOf("url") < 0) {
|
||||
if (t.type === 'variable' && t.value === '"type"') {
|
||||
t = editor.parser.nextNonEmptyToken(iter);
|
||||
if (!t || t.type !== "punctuation.colon") {
|
||||
// weird place to be in, but safe choice..
|
||||
break;
|
||||
}
|
||||
t = editor.parser.nextNonEmptyToken(iter);
|
||||
if (t && t.type === "string") {
|
||||
type = t.value.replace(/"/g, '');
|
||||
}
|
||||
break;
|
||||
}
|
||||
t = editor.parser.prevNonEmptyToken(iter);
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
api.addEndpointDescription('put_repository', {
|
||||
methods: ['PUT'],
|
||||
patterns: [
|
||||
'_snapshot/{id}'
|
||||
],
|
||||
data_autocomplete_rules: {
|
||||
__template: {"type": ""},
|
||||
|
||||
"type": {
|
||||
__one_of: ["fs", "url", "s3", "hdfs"]
|
||||
},
|
||||
"settings": {
|
||||
__one_of: [{
|
||||
//fs
|
||||
__condition: {
|
||||
lines_regex: String.raw`type["']\s*:\s*["']fs`
|
||||
},
|
||||
__template: {
|
||||
location: "path"
|
||||
},
|
||||
location: "path",
|
||||
compress: {__one_of: [true, false]},
|
||||
concurrent_streams: 5,
|
||||
chunk_size: "10m",
|
||||
max_restore_bytes_per_sec: "20mb",
|
||||
max_snapshot_bytes_per_sec: "20mb"
|
||||
},
|
||||
{// url
|
||||
__condition: {
|
||||
lines_regex: String.raw`type["']\s*:\s*["']url`
|
||||
},
|
||||
__template: {
|
||||
url: ""
|
||||
},
|
||||
url: "",
|
||||
concurrent_streams: 5
|
||||
},
|
||||
{ //s3
|
||||
__condition: {
|
||||
lines_regex: String.raw`type["']\s*:\s*["']s3`
|
||||
},
|
||||
__template: {
|
||||
bucket: ""
|
||||
},
|
||||
bucket: "",
|
||||
region: "",
|
||||
base_path: "",
|
||||
concurrent_streams: 5,
|
||||
chunk_size: "10m",
|
||||
compress: {__one_of: [true, false]}
|
||||
},
|
||||
{// hdfs
|
||||
__condition: {
|
||||
lines_regex: String.raw`type["']\s*:\s*["']hdfs`
|
||||
},
|
||||
__template: {
|
||||
path: ""
|
||||
},
|
||||
uri: "",
|
||||
path: "some/path",
|
||||
load_defaults: {__one_of: [true, false]},
|
||||
conf_location: "cfg.xml",
|
||||
concurrent_streams: 5,
|
||||
compress: {__one_of: [true, false]},
|
||||
chunk_size: "10m"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
27
src/plugins/console/api_server/es_5_0/templates.js
Normal file
27
src/plugins/console/api_server/es_5_0/templates.js
Normal file
|
@ -0,0 +1,27 @@
|
|||
module.exports = function (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: {__scope_link: '_put_mapping'},
|
||||
settings: {__scope_link: '_put_settings'}
|
||||
}
|
||||
});
|
||||
};
|
|
@ -239,21 +239,19 @@ function setActiveApi(api) {
|
|||
}
|
||||
|
||||
es.addServerChangeListener(function () {
|
||||
var version = es.getVersion(), api;
|
||||
if (!version || version.length == 0) {
|
||||
api = "es_1_0";
|
||||
}
|
||||
else if (version[0] === "1") {
|
||||
api = "es_1_0";
|
||||
}
|
||||
else if (version[0] === "2") {
|
||||
api = "es_2_0";
|
||||
}
|
||||
else if (version[0] === "3") {
|
||||
api = "es_2_0"; // TODO: change :)
|
||||
}
|
||||
else {
|
||||
api = "es_1_0";
|
||||
var version = es.getVersion() || [];
|
||||
var api;
|
||||
|
||||
switch (version[0]) {
|
||||
case '5':
|
||||
api = 'es_5_0';
|
||||
break;
|
||||
case '2':
|
||||
api = 'es_2_0';
|
||||
break;
|
||||
case '1':
|
||||
default:
|
||||
api = 'es_1_0';
|
||||
}
|
||||
|
||||
if (api) {
|
||||
|
|
|
@ -5,6 +5,8 @@ import healthCheck from './lib/health_check';
|
|||
import exposeClient from './lib/expose_client';
|
||||
import createProxy, { createPath } from './lib/create_proxy';
|
||||
|
||||
const DEFAULT_REQUEST_HEADERS = [ 'authorization' ];
|
||||
|
||||
module.exports = function ({ Plugin }) {
|
||||
return new Plugin({
|
||||
require: ['kibana'],
|
||||
|
@ -20,6 +22,7 @@ module.exports = function ({ Plugin }) {
|
|||
password: string(),
|
||||
shardTimeout: number().default(0),
|
||||
requestTimeout: number().default(30000),
|
||||
requestHeadersWhitelist: array().items().single().default(DEFAULT_REQUEST_HEADERS),
|
||||
pingTimeout: number().default(ref('requestTimeout')),
|
||||
startupTimeout: number().default(5000),
|
||||
ssl: object({
|
||||
|
|
76
src/plugins/elasticsearch/lib/__tests__/map_uri.js
Normal file
76
src/plugins/elasticsearch/lib/__tests__/map_uri.js
Normal file
|
@ -0,0 +1,76 @@
|
|||
import expect from 'expect.js';
|
||||
import mapUri from '../map_uri';
|
||||
import sinon from 'sinon';
|
||||
|
||||
describe('plugins/elasticsearch', function () {
|
||||
describe('lib/map_uri', function () {
|
||||
|
||||
let request;
|
||||
|
||||
beforeEach(function () {
|
||||
request = {
|
||||
path: '/elasticsearch/some/path',
|
||||
headers: {
|
||||
cookie: 'some_cookie_string',
|
||||
'accept-encoding': 'gzip, deflate',
|
||||
origin: 'https://localhost:5601',
|
||||
'content-type': 'application/json',
|
||||
'x-my-custom-header': '42',
|
||||
accept: 'application/json, text/plain, */*',
|
||||
authorization: '2343d322eda344390fdw42'
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
it('only sends the whitelisted request headers', function () {
|
||||
|
||||
const get = sinon.stub()
|
||||
.withArgs('elasticsearch.url').returns('http://foobar:9200')
|
||||
.withArgs('elasticsearch.requestHeadersWhitelist').returns(['x-my-custom-HEADER', 'Authorization']);
|
||||
const config = function () { return { get: get }; };
|
||||
const server = {
|
||||
config: config
|
||||
};
|
||||
|
||||
mapUri(server)(request, function (err, upstreamUri, upstreamHeaders) {
|
||||
expect(err).to.be(null);
|
||||
expect(upstreamHeaders).to.have.property('authorization');
|
||||
expect(upstreamHeaders).to.have.property('x-my-custom-header');
|
||||
expect(Object.keys(upstreamHeaders).length).to.be(2);
|
||||
});
|
||||
});
|
||||
|
||||
it('sends no headers if whitelist is set to []', function () {
|
||||
|
||||
const get = sinon.stub()
|
||||
.withArgs('elasticsearch.url').returns('http://foobar:9200')
|
||||
.withArgs('elasticsearch.requestHeadersWhitelist').returns([]);
|
||||
const config = function () { return { get: get }; };
|
||||
const server = {
|
||||
config: config
|
||||
};
|
||||
|
||||
mapUri(server)(request, function (err, upstreamUri, upstreamHeaders) {
|
||||
expect(err).to.be(null);
|
||||
expect(Object.keys(upstreamHeaders).length).to.be(0);
|
||||
});
|
||||
});
|
||||
|
||||
it('sends no headers if whitelist is set to no value', function () {
|
||||
|
||||
const get = sinon.stub()
|
||||
.withArgs('elasticsearch.url').returns('http://foobar:9200')
|
||||
.withArgs('elasticsearch.requestHeadersWhitelist').returns([ null ]); // This is how Joi returns it
|
||||
const config = function () { return { get: get }; };
|
||||
const server = {
|
||||
config: config
|
||||
};
|
||||
|
||||
mapUri(server)(request, function (err, upstreamUri, upstreamHeaders) {
|
||||
expect(err).to.be(null);
|
||||
expect(Object.keys(upstreamHeaders).length).to.be(0);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
});
|
|
@ -3,12 +3,12 @@ import Promise from 'bluebird';
|
|||
import Boom from 'boom';
|
||||
import getBasicAuthRealm from './get_basic_auth_realm';
|
||||
import toPath from 'lodash/internal/toPath';
|
||||
import filterHeaders from './filter_headers';
|
||||
|
||||
module.exports = (client) => {
|
||||
module.exports = (server, client) => {
|
||||
return (req, endpoint, params = {}) => {
|
||||
if (req.headers.authorization) {
|
||||
_.set(params, 'headers.authorization', req.headers.authorization);
|
||||
}
|
||||
const filteredHeaders = filterHeaders(req.headers, server.config().get('elasticsearch.requestHeadersWhitelist'));
|
||||
_.set(params, 'headers', filteredHeaders);
|
||||
const path = toPath(endpoint);
|
||||
const api = _.get(client, path);
|
||||
let apiContext = _.get(client, path.slice(0, -1));
|
||||
|
|
|
@ -16,10 +16,12 @@ function createProxy(server, method, route, config) {
|
|||
handler: {
|
||||
proxy: {
|
||||
mapUri: mapUri(server),
|
||||
passThrough: true,
|
||||
agent: createAgent(server),
|
||||
xforward: true,
|
||||
timeout: server.config().get('elasticsearch.requestTimeout')
|
||||
timeout: server.config().get('elasticsearch.requestTimeout'),
|
||||
onResponse: function (err, responseFromUpstream, request, reply) {
|
||||
reply(err, responseFromUpstream);
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
|
|
|
@ -78,8 +78,8 @@ module.exports = function (server) {
|
|||
server.expose('ElasticsearchClientLogging', ElasticsearchClientLogging);
|
||||
server.expose('client', client);
|
||||
server.expose('createClient', createClient);
|
||||
server.expose('callWithRequestFactory', callWithRequest);
|
||||
server.expose('callWithRequest', callWithRequest(noAuthClient));
|
||||
server.expose('callWithRequestFactory', _.partial(callWithRequest, server));
|
||||
server.expose('callWithRequest', callWithRequest(server, noAuthClient));
|
||||
server.expose('errors', elasticsearch.errors);
|
||||
|
||||
return client;
|
||||
|
|
22
src/plugins/elasticsearch/lib/filter_headers.js
Normal file
22
src/plugins/elasticsearch/lib/filter_headers.js
Normal file
|
@ -0,0 +1,22 @@
|
|||
import _ from 'lodash';
|
||||
|
||||
export default function (originalHeaders, headersToKeep) {
|
||||
|
||||
const normalizeHeader = function (header) {
|
||||
if (!header) {
|
||||
return '';
|
||||
}
|
||||
header = header.toString();
|
||||
return header.trim().toLowerCase();
|
||||
};
|
||||
|
||||
// Normalize list of headers we want to allow in upstream request
|
||||
const headersToKeepNormalized = headersToKeep.map(normalizeHeader);
|
||||
|
||||
// Normalize original headers in request
|
||||
const originalHeadersNormalized = _.mapKeys(originalHeaders, function (headerValue, headerName) {
|
||||
return normalizeHeader(headerName);
|
||||
});
|
||||
|
||||
return _.pick(originalHeaders, headersToKeepNormalized);
|
||||
}
|
|
@ -1,6 +1,9 @@
|
|||
import querystring from 'querystring';
|
||||
import { resolve } from 'url';
|
||||
import filterHeaders from './filter_headers';
|
||||
|
||||
module.exports = function mapUri(server, prefix) {
|
||||
|
||||
const config = server.config();
|
||||
return function (request, done) {
|
||||
const path = request.path.replace('/elasticsearch', '');
|
||||
|
@ -11,6 +14,7 @@ module.exports = function mapUri(server, prefix) {
|
|||
}
|
||||
const query = querystring.stringify(request.query);
|
||||
if (query) url += '?' + query;
|
||||
done(null, url);
|
||||
const filteredHeaders = filterHeaders(request.headers, server.config().get('elasticsearch.requestHeadersWhitelist'));
|
||||
done(null, url, filteredHeaders);
|
||||
};
|
||||
};
|
||||
|
|
|
@ -106,6 +106,8 @@ describe('docViews', function () {
|
|||
expect($scope.filter.calledOnce).to.be(true);
|
||||
cell.find('.fa-search-minus').first().click();
|
||||
expect($scope.filter.calledTwice).to.be(true);
|
||||
cell.find('.fa-asterisk').first().click();
|
||||
expect($scope.filter.calledThrice).to.be(true);
|
||||
});
|
||||
|
||||
it('should NOT apply a filter when clicking non-filterable fields', function () {
|
||||
|
@ -115,6 +117,8 @@ describe('docViews', function () {
|
|||
expect($scope.filter.calledOnce).to.be(false);
|
||||
cell.find('.fa-search-minus').first().click();
|
||||
expect($scope.filter.calledTwice).to.be(false);
|
||||
cell.find('.fa-asterisk').first().click();
|
||||
expect($scope.filter.calledOnce).to.be(true);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -27,6 +27,15 @@
|
|||
tooltip-append-to-body="1"
|
||||
class="fa fa-columns"></i>
|
||||
</span>
|
||||
<span ng-if="!indexPattern.metaFields.includes(field)">
|
||||
<i ng-click="filter('_exists_', field, '+')"
|
||||
tooltip="Filter for field present"
|
||||
tooltip-append-to-body="1"
|
||||
class="fa fa-asterisk"></i>
|
||||
</span>
|
||||
<span ng-if="indexPattern.metaFields.includes(field)" tooltip="Unable to filter for presence of meta fields">
|
||||
<i class="fa fa-asterisk text-muted"></i>
|
||||
</span>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
|
|
|
@ -83,14 +83,15 @@ app.directive('dashboardGrid', function ($compile, Notifier) {
|
|||
});
|
||||
|
||||
$scope.$on('$destroy', function () {
|
||||
safeLayout.cancel();
|
||||
$window.off('resize', safeLayout);
|
||||
|
||||
if (!gridster) return;
|
||||
gridster.$widgets.each(function (i, el) {
|
||||
const panel = getPanelFor(el);
|
||||
removePanel(panel);
|
||||
// stop any animations
|
||||
panel.$el.stop();
|
||||
removePanel(panel, true);
|
||||
// not that we will, but lets be safe
|
||||
makePanelSerializeable(panel);
|
||||
});
|
||||
|
@ -125,9 +126,9 @@ app.directive('dashboardGrid', function ($compile, Notifier) {
|
|||
}
|
||||
|
||||
// tell gridster to remove the panel, and cleanup our metadata
|
||||
function removePanel(panel) {
|
||||
function removePanel(panel, silent) {
|
||||
// remove from grister 'silently' (don't reorganize after)
|
||||
gridster.remove_widget(panel.$el);
|
||||
gridster.remove_widget(panel.$el, silent);
|
||||
|
||||
// destroy the scope
|
||||
panel.$scope.$destroy();
|
||||
|
|
|
@ -3,7 +3,7 @@ import angular from 'angular';
|
|||
import moment from 'moment';
|
||||
import getSort from 'ui/doc_table/lib/get_sort';
|
||||
import rison from 'rison-node';
|
||||
import dateMath from 'ui/utils/date_math';
|
||||
import dateMath from '@elastic/datemath';
|
||||
import 'ui/doc_table';
|
||||
import 'ui/visualize';
|
||||
import 'ui/notify';
|
||||
|
|
|
@ -3,7 +3,11 @@
|
|||
<div class="header">
|
||||
<h2 class="title">Edit Saved Objects</h2>
|
||||
<button class="btn btn-default controls" ng-click="exportAll()"><i aria-hidden="true" class="fa fa-download"></i> Export Everything</button>
|
||||
<button file-upload="importAll(fileContents)" class="btn btn-default controls" ng-click><i aria-hidden="true" class="fa fa-upload"></i> Import</button>
|
||||
<file-upload on-read="importAll(fileContents)" upload-selector="button.upload">
|
||||
<button class="btn btn-default controls upload" ng-click>
|
||||
<i aria-hidden="true" class="fa fa-upload"></i> Import
|
||||
</button>
|
||||
</file-upload>
|
||||
</div>
|
||||
<p>
|
||||
From here you can delete saved objects, such as saved searches. You can also edit the raw data of saved objects. Typically objects are only modified via their associated application, which is probably what you should use instead of this screen. Each tab is limited to 100 results. You can use the filter to find objects not in the default list.
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
import { saveAs } from '@spalger/filesaver';
|
||||
import _ from 'lodash';
|
||||
import { extend, find, flattenDeep, partialRight, pick, pluck, sortBy } from 'lodash';
|
||||
import angular from 'angular';
|
||||
import registry from 'plugins/kibana/settings/saved_object_registry';
|
||||
import objectIndexHTML from 'plugins/kibana/settings/sections/objects/_objects.html';
|
||||
import 'ui/directives/file_upload';
|
||||
import uiRoutes from 'ui/routes';
|
||||
import uiModules from 'ui/modules';
|
||||
const MAX_SIZE = Math.pow(2, 31) - 1;
|
||||
|
||||
const MAX_SIZE = Math.pow(2, 31) - 1;
|
||||
|
||||
uiRoutes
|
||||
.when('/settings/objects', {
|
||||
|
@ -41,9 +41,9 @@ uiModules.get('apps/settings')
|
|||
});
|
||||
|
||||
$q.all(services).then(function (data) {
|
||||
$scope.services = _.sortBy(data, 'title');
|
||||
$scope.services = sortBy(data, 'title');
|
||||
let tab = $scope.services[0];
|
||||
if ($state.tab) $scope.currentTab = tab = _.find($scope.services, {title: $state.tab});
|
||||
if ($state.tab) $scope.currentTab = tab = find($scope.services, {title: $state.tab});
|
||||
|
||||
$scope.$watch('state.tab', function (tab) {
|
||||
if (!tab) $scope.changeTab($scope.services[0]);
|
||||
|
@ -83,23 +83,23 @@ uiModules.get('apps/settings')
|
|||
};
|
||||
|
||||
$scope.bulkDelete = function () {
|
||||
$scope.currentTab.service.delete(_.pluck($scope.selectedItems, 'id')).then(refreshData).then(function () {
|
||||
$scope.currentTab.service.delete(pluck($scope.selectedItems, 'id')).then(refreshData).then(function () {
|
||||
$scope.selectedItems.length = 0;
|
||||
});
|
||||
};
|
||||
|
||||
$scope.bulkExport = function () {
|
||||
const objs = $scope.selectedItems.map(_.partialRight(_.extend, {type: $scope.currentTab.type}));
|
||||
const objs = $scope.selectedItems.map(partialRight(extend, {type: $scope.currentTab.type}));
|
||||
retrieveAndExportDocs(objs);
|
||||
};
|
||||
|
||||
$scope.exportAll = () => {
|
||||
Promise.map($scope.services, (service) =>
|
||||
service.service.scanAll('').then((results) =>
|
||||
results.hits.map((hit) => _.extend(hit, {type: service.type}))
|
||||
)
|
||||
).then((results) => retrieveAndExportDocs(_.flattenDeep(results)));
|
||||
};
|
||||
$scope.exportAll = () => Promise
|
||||
.map($scope.services, service => service.service
|
||||
.scanAll('')
|
||||
.then(result => result.hits.map(hit => extend(hit, { type: service.type })))
|
||||
)
|
||||
.then(results => retrieveAndExportDocs(flattenDeep(results)))
|
||||
.catch(error => notify.error(error));
|
||||
|
||||
function retrieveAndExportDocs(objs) {
|
||||
if (!objs.length) return notify.error('No saved objects to export.');
|
||||
|
@ -108,7 +108,7 @@ uiModules.get('apps/settings')
|
|||
body: {docs: objs.map(transformToMget)}
|
||||
})
|
||||
.then(function (response) {
|
||||
saveToFile(response.docs.map(_.partialRight(_.pick, '_id', '_type', '_source')));
|
||||
saveToFile(response.docs.map(partialRight(pick, '_id', '_type', '_source')));
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -131,7 +131,7 @@ uiModules.get('apps/settings')
|
|||
}
|
||||
|
||||
return Promise.map(docs, function (doc) {
|
||||
const service = _.find($scope.services, {type: doc._type}).service;
|
||||
const service = find($scope.services, {type: doc._type}).service;
|
||||
return service.get().then(function (obj) {
|
||||
obj.id = doc._id;
|
||||
return obj.applyESResp(doc).then(function () {
|
||||
|
|
|
@ -7,6 +7,7 @@ import tabifyPm from 'ui/agg_response/tabify/tabify';
|
|||
import AggResponseTabifyTableGroupProvider from 'ui/agg_response/tabify/_table_group';
|
||||
import VisProvider from 'ui/vis';
|
||||
import FixturesStubbedLogstashIndexPatternProvider from 'fixtures/stubbed_logstash_index_pattern';
|
||||
import StateManagementAppStateProvider from 'ui/state_management/app_state';
|
||||
describe('Controller', function () {
|
||||
|
||||
let $rootScope;
|
||||
|
@ -17,6 +18,7 @@ describe('Controller', function () {
|
|||
let $el;
|
||||
let Vis;
|
||||
let fixtures;
|
||||
let AppState;
|
||||
|
||||
beforeEach(ngMock.module('kibana', 'kibana/table_vis'));
|
||||
beforeEach(ngMock.inject(function ($injector) {
|
||||
|
@ -24,6 +26,7 @@ describe('Controller', function () {
|
|||
$rootScope = $injector.get('$rootScope');
|
||||
$compile = $injector.get('$compile');
|
||||
fixtures = require('fixtures/fake_hierarchical_data');
|
||||
AppState = Private(StateManagementAppStateProvider);
|
||||
TableGroup = Private(AggResponseTabifyTableGroupProvider);
|
||||
Vis = Private(VisProvider);
|
||||
}));
|
||||
|
@ -57,6 +60,7 @@ describe('Controller', function () {
|
|||
vis.aggs.forEach(function (agg, i) { agg.id = 'agg_' + (i + 1); });
|
||||
|
||||
$rootScope.vis = vis;
|
||||
$rootScope.uiState = new AppState({uiState: {}}).makeStateful('uiState');
|
||||
$rootScope.newScope = function (scope) { $scope = scope; };
|
||||
|
||||
$el = $('<div>')
|
||||
|
@ -103,6 +107,23 @@ describe('Controller', function () {
|
|||
expect(!$scope.tableGroups).to.be.ok();
|
||||
});
|
||||
|
||||
it('sets the sort on the scope when it is passed as a vis param', function () {
|
||||
const sortObj = {
|
||||
columnIndex: 1,
|
||||
direction: 'asc'
|
||||
};
|
||||
initController(new OneRangeVis({sort: sortObj}));
|
||||
|
||||
// modify the data to not have any buckets
|
||||
const resp = _.cloneDeep(fixtures.oneRangeBucket);
|
||||
resp.aggregations.agg_2.buckets = {};
|
||||
|
||||
attachEsResponseToScope(resp);
|
||||
|
||||
expect($scope.sort.columnIndex).to.equal(sortObj.columnIndex);
|
||||
expect($scope.sort.direction).to.equal(sortObj.direction);
|
||||
});
|
||||
|
||||
it('sets #hasSomeRows properly if the table group is empty', function () {
|
||||
initController(new OneRangeVis());
|
||||
|
||||
|
|
|
@ -8,7 +8,8 @@
|
|||
<kbn-agg-table-group
|
||||
group="tableGroups"
|
||||
export-title="vis.title"
|
||||
per-page="vis.params.perPage">
|
||||
per-page="vis.params.perPage"
|
||||
sort="sort">
|
||||
</kbn-agg-table-group>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -38,7 +38,11 @@ function TableVisTypeProvider(Private) {
|
|||
defaults: {
|
||||
perPage: 10,
|
||||
showPartialRows: false,
|
||||
showMeticsAtAllLevels: false
|
||||
showMeticsAtAllLevels: false,
|
||||
sort: {
|
||||
columnIndex: null,
|
||||
direction: null
|
||||
}
|
||||
},
|
||||
editor: '<table-vis-params></table-vis-params>'
|
||||
},
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import AggResponseTabifyTabifyProvider from 'ui/agg_response/tabify/tabify';
|
||||
import uiModules from 'ui/modules';
|
||||
import { assign } from 'lodash';
|
||||
|
||||
// get the kibana/table_vis module, and make sure that it requires the "kibana" module if it
|
||||
// didn't already
|
||||
|
@ -10,6 +11,14 @@ const module = uiModules.get('kibana/table_vis', ['kibana']);
|
|||
module.controller('KbnTableVisController', function ($scope, Private) {
|
||||
const tabifyAggResponse = Private(AggResponseTabifyTabifyProvider);
|
||||
|
||||
var uiStateSort = ($scope.uiState) ? $scope.uiState.get('vis.params.sort') : {};
|
||||
assign($scope.vis.params.sort, uiStateSort);
|
||||
|
||||
$scope.sort = $scope.vis.params.sort;
|
||||
$scope.$watchCollection('sort', function (newSort) {
|
||||
$scope.uiState.set('vis.params.sort', newSort);
|
||||
});
|
||||
|
||||
$scope.$watch('esResponse', function (resp, oldResp) {
|
||||
let tableGroups = $scope.tableGroups = null;
|
||||
let hasSomeRows = $scope.hasSomeRows = null;
|
||||
|
|
|
@ -19,21 +19,21 @@ export default (kibana) => {
|
|||
let config = kibana.config;
|
||||
|
||||
const testGlobs = ['src/ui/public/**/*.js'];
|
||||
const testingPluginId = config.get('tests_bundle.pluginId');
|
||||
const testingPluginIds = config.get('tests_bundle.pluginId');
|
||||
|
||||
if (testingPluginId) {
|
||||
const plugin = plugins.byId[testingPluginId];
|
||||
if (!plugin) throw new Error('Invalid testingPluginId :: unknown plugin ' + testingPluginId);
|
||||
if (testingPluginIds) {
|
||||
testGlobs.push('!src/ui/public/**/__tests__/**/*');
|
||||
testingPluginIds.split(',').forEach((pluginId) => {
|
||||
const plugin = plugins.byId[pluginId];
|
||||
if (!plugin) throw new Error('Invalid testingPluginId :: unknown plugin ' + pluginId);
|
||||
|
||||
// add the modules from all of this plugins apps
|
||||
for (let app of plugin.apps) {
|
||||
modules = union(modules, app.getModules());
|
||||
}
|
||||
// add the modules from all of this plugins apps
|
||||
for (let app of plugin.apps) {
|
||||
modules = union(modules, app.getModules());
|
||||
}
|
||||
|
||||
testGlobs.push(
|
||||
'!src/ui/public/**/__tests__/**/*',
|
||||
`${plugin.publicDir}/**/__tests__/**/*.js`
|
||||
);
|
||||
testGlobs.push(`${plugin.publicDir}/**/__tests__/**/*.js`);
|
||||
});
|
||||
} else {
|
||||
|
||||
// add the modules from all of the apps
|
||||
|
|
|
@ -110,8 +110,12 @@ module.exports = async function (kbnServer, server, config) {
|
|||
method: 'GET',
|
||||
path: '/goto/{urlId}',
|
||||
handler: async function (request, reply) {
|
||||
const url = await shortUrlLookup.getUrl(request.params.urlId);
|
||||
reply().redirect(config.get('server.basePath') + url);
|
||||
try {
|
||||
const url = await shortUrlLookup.getUrl(request.params.urlId);
|
||||
reply().redirect(config.get('server.basePath') + url);
|
||||
} catch (err) {
|
||||
reply(err);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -119,8 +123,12 @@ module.exports = async function (kbnServer, server, config) {
|
|||
method: 'POST',
|
||||
path: '/shorten',
|
||||
handler: async function (request, reply) {
|
||||
const urlId = await shortUrlLookup.generateUrlId(request.payload.url);
|
||||
reply(urlId);
|
||||
try {
|
||||
const urlId = await shortUrlLookup.generateUrlId(request.payload.url);
|
||||
reply(urlId);
|
||||
} catch (err) {
|
||||
reply(err);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -3,10 +3,11 @@ import crypto from 'crypto';
|
|||
export default function (server) {
|
||||
async function updateMetadata(urlId, urlDoc) {
|
||||
const client = server.plugins.elasticsearch.client;
|
||||
const kibanaIndex = server.config().get('kibana.index');
|
||||
|
||||
try {
|
||||
await client.update({
|
||||
index: '.kibana',
|
||||
index: kibanaIndex,
|
||||
type: 'url',
|
||||
id: urlId,
|
||||
body: {
|
||||
|
@ -25,9 +26,10 @@ export default function (server) {
|
|||
async function getUrlDoc(urlId) {
|
||||
const urlDoc = await new Promise((resolve, reject) => {
|
||||
const client = server.plugins.elasticsearch.client;
|
||||
const kibanaIndex = server.config().get('kibana.index');
|
||||
|
||||
client.get({
|
||||
index: '.kibana',
|
||||
index: kibanaIndex,
|
||||
type: 'url',
|
||||
id: urlId
|
||||
})
|
||||
|
@ -45,9 +47,10 @@ export default function (server) {
|
|||
async function createUrlDoc(url, urlId) {
|
||||
const newUrlId = await new Promise((resolve, reject) => {
|
||||
const client = server.plugins.elasticsearch.client;
|
||||
const kibanaIndex = server.config().get('kibana.index');
|
||||
|
||||
client.index({
|
||||
index: '.kibana',
|
||||
index: kibanaIndex,
|
||||
type: 'url',
|
||||
id: urlId,
|
||||
body: {
|
||||
|
@ -79,7 +82,6 @@ export default function (server) {
|
|||
return {
|
||||
async generateUrlId(url) {
|
||||
const urlId = createUrlId(url);
|
||||
|
||||
const urlDoc = await getUrlDoc(urlId);
|
||||
if (urlDoc) return urlId;
|
||||
|
||||
|
|
|
@ -47,5 +47,9 @@ module.exports = Promise.method(function (kbnServer, server, config) {
|
|||
// resend SIGINT
|
||||
process.kill(process.pid, 'SIGINT');
|
||||
});
|
||||
|
||||
process.on('unhandledRejection', function (reason, promise) {
|
||||
server.log(['warning'], `Detected an unhandled Promise rejection.\n${reason}`);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
77
src/server/plugins/__tests__/plugin_init.js
Normal file
77
src/server/plugins/__tests__/plugin_init.js
Normal file
|
@ -0,0 +1,77 @@
|
|||
import {values} from 'lodash';
|
||||
import expect from 'expect.js';
|
||||
import sinon from 'auto-release-sinon';
|
||||
import pluginInit from '../plugin_init';
|
||||
|
||||
describe('Plugin init', () => {
|
||||
const getPluginCollection = (plugins) => ({
|
||||
byId: plugins,
|
||||
toArray: () => values(plugins)
|
||||
});
|
||||
|
||||
it('should call preInit before init', async () => {
|
||||
const plugins = {
|
||||
foo: {
|
||||
id: 'foo',
|
||||
init: sinon.spy(),
|
||||
preInit: sinon.spy(),
|
||||
requiredIds: []
|
||||
},
|
||||
bar: {
|
||||
id: 'bar',
|
||||
init: sinon.spy(),
|
||||
preInit: sinon.spy(),
|
||||
requiredIds: []
|
||||
},
|
||||
baz: {
|
||||
id: 'baz',
|
||||
init: sinon.spy(),
|
||||
preInit: sinon.spy(),
|
||||
requiredIds: []
|
||||
}
|
||||
};
|
||||
|
||||
await pluginInit(getPluginCollection(plugins));
|
||||
|
||||
expect(plugins.foo.preInit.calledBefore(plugins.foo.init)).to.be.ok();
|
||||
expect(plugins.foo.preInit.calledBefore(plugins.bar.init)).to.be.ok();
|
||||
expect(plugins.foo.preInit.calledBefore(plugins.baz.init)).to.be.ok();
|
||||
|
||||
expect(plugins.bar.preInit.calledBefore(plugins.foo.init)).to.be.ok();
|
||||
expect(plugins.bar.preInit.calledBefore(plugins.bar.init)).to.be.ok();
|
||||
expect(plugins.bar.preInit.calledBefore(plugins.baz.init)).to.be.ok();
|
||||
|
||||
expect(plugins.baz.preInit.calledBefore(plugins.foo.init)).to.be.ok();
|
||||
expect(plugins.baz.preInit.calledBefore(plugins.bar.init)).to.be.ok();
|
||||
expect(plugins.baz.preInit.calledBefore(plugins.baz.init)).to.be.ok();
|
||||
});
|
||||
|
||||
it('should call preInits in correct order based on requirements', async () => {
|
||||
const plugins = {
|
||||
foo: {
|
||||
id: 'foo',
|
||||
init: sinon.spy(),
|
||||
preInit: sinon.spy(),
|
||||
requiredIds: ['bar', 'baz']
|
||||
},
|
||||
bar: {
|
||||
id: 'bar',
|
||||
init: sinon.spy(),
|
||||
preInit: sinon.spy(),
|
||||
requiredIds: []
|
||||
},
|
||||
baz: {
|
||||
id: 'baz',
|
||||
init: sinon.spy(),
|
||||
preInit: sinon.spy(),
|
||||
requiredIds: ['bar']
|
||||
}
|
||||
};
|
||||
|
||||
await pluginInit(getPluginCollection(plugins));
|
||||
|
||||
expect(plugins.bar.preInit.firstCall.calledBefore(plugins.foo.init.firstCall)).to.be.ok();
|
||||
expect(plugins.bar.preInit.firstCall.calledBefore(plugins.baz.init.firstCall)).to.be.ok();
|
||||
expect(plugins.baz.preInit.firstCall.calledBefore(plugins.foo.init.firstCall)).to.be.ok();
|
||||
});
|
||||
});
|
|
@ -1,4 +1,5 @@
|
|||
import { includes, keys } from 'lodash';
|
||||
import pluginInit from './plugin_init';
|
||||
|
||||
module.exports = async function (kbnServer, server, config) {
|
||||
|
||||
if (!config.get('plugins.initialize')) {
|
||||
|
@ -17,30 +18,5 @@ module.exports = async function (kbnServer, server, config) {
|
|||
|
||||
});
|
||||
|
||||
|
||||
let path = [];
|
||||
const initialize = async function (id) {
|
||||
let plugin = plugins.byId[id];
|
||||
|
||||
if (includes(path, id)) {
|
||||
throw new Error(`circular dependencies found: "${path.concat(id).join(' -> ')}"`);
|
||||
}
|
||||
|
||||
path.push(id);
|
||||
|
||||
for (let reqId of plugin.requiredIds) {
|
||||
if (!plugins.byId[reqId]) {
|
||||
throw new Error(`Unmet requirement "${reqId}" for plugin "${id}"`);
|
||||
}
|
||||
|
||||
await initialize(reqId);
|
||||
}
|
||||
|
||||
await plugin.init();
|
||||
path.pop();
|
||||
};
|
||||
|
||||
for (let {id} of plugins) {
|
||||
await initialize(id);
|
||||
}
|
||||
await pluginInit(plugins);
|
||||
};
|
||||
|
|
|
@ -59,9 +59,11 @@ module.exports = class Plugin {
|
|||
this.uiExportsSpecs = opts.uiExports || {};
|
||||
this.requiredIds = opts.require || [];
|
||||
this.version = opts.version || pkg.version;
|
||||
this.externalPreInit = opts.preInit || _.noop;
|
||||
this.externalInit = opts.init || _.noop;
|
||||
this.configPrefix = opts.configPrefix || this.id;
|
||||
this.getConfigSchema = opts.config || _.noop;
|
||||
this.preInit = _.once(this.preInit);
|
||||
this.init = _.once(this.init);
|
||||
this[extendInitFns] = [];
|
||||
|
||||
|
@ -100,6 +102,10 @@ module.exports = class Plugin {
|
|||
}
|
||||
}
|
||||
|
||||
async preInit() {
|
||||
return await this.externalPreInit(this.kbnServer.server);
|
||||
}
|
||||
|
||||
async init() {
|
||||
let { id, version, kbnServer, configPrefix } = this;
|
||||
let { config } = kbnServer;
|
||||
|
|
35
src/server/plugins/plugin_init.js
Normal file
35
src/server/plugins/plugin_init.js
Normal file
|
@ -0,0 +1,35 @@
|
|||
import { includes } from 'lodash';
|
||||
|
||||
export default async (plugins) => {
|
||||
let path = [];
|
||||
|
||||
const initialize = async function (id, fn) {
|
||||
let plugin = plugins.byId[id];
|
||||
|
||||
if (includes(path, id)) {
|
||||
throw new Error(`circular dependencies found: "${path.concat(id).join(' -> ')}"`);
|
||||
}
|
||||
|
||||
path.push(id);
|
||||
|
||||
for (let reqId of plugin.requiredIds) {
|
||||
if (!plugins.byId[reqId]) {
|
||||
throw new Error(`Unmet requirement "${reqId}" for plugin "${id}"`);
|
||||
}
|
||||
|
||||
await initialize(reqId, fn);
|
||||
}
|
||||
|
||||
await plugin[fn]();
|
||||
path.pop();
|
||||
};
|
||||
|
||||
const collection = plugins.toArray();
|
||||
for (let {id} of collection) {
|
||||
await initialize(id, 'preInit');
|
||||
}
|
||||
|
||||
for (let {id} of collection) {
|
||||
await initialize(id, 'init');
|
||||
}
|
||||
};
|
|
@ -36,6 +36,10 @@ describe('AggTableGroup Directive', function () {
|
|||
it('renders a simple split response properly', function () {
|
||||
let vis = new Vis(indexPattern, 'table');
|
||||
$scope.group = tabifyAggResponse(vis, fixtures.metricOnly);
|
||||
$scope.sort = {
|
||||
columnIndex: null,
|
||||
direction: null
|
||||
};
|
||||
let $el = $('<kbn-agg-table-group group="group"></kbn-agg-table-group>');
|
||||
|
||||
$compile($el)($scope);
|
||||
|
|
|
@ -2,7 +2,8 @@
|
|||
ng-if="rows.length"
|
||||
rows="rows"
|
||||
columns="formattedColumns"
|
||||
per-page="perPage">
|
||||
per-page="perPage"
|
||||
sort="sort">
|
||||
|
||||
<div class="agg-table-controls">
|
||||
<small>Export:</small>
|
||||
|
|
|
@ -15,6 +15,7 @@ uiModules
|
|||
scope: {
|
||||
table: '=',
|
||||
perPage: '=?',
|
||||
sort: '=?',
|
||||
exportTitle: '=?'
|
||||
},
|
||||
controllerAs: 'aggTable',
|
||||
|
@ -26,7 +27,6 @@ uiModules
|
|||
controller: function ($scope) {
|
||||
let self = this;
|
||||
|
||||
self.sort = null;
|
||||
self._saveAs = require('@spalger/filesaver').saveAs;
|
||||
self.csv = {
|
||||
separator: config.get('csv:separator'),
|
||||
|
|
|
@ -9,12 +9,13 @@
|
|||
<tbody ng-repeat-end>
|
||||
<tr>
|
||||
<td>
|
||||
<kbn-agg-table-group ng-if="table.tables" group="table" per-page="perPage"></kbn-agg-table-group>
|
||||
<kbn-agg-table-group ng-if="table.tables" group="table" per-page="perPage" sort="sort"></kbn-agg-table-group>
|
||||
<kbn-agg-table
|
||||
ng-if="table.rows"
|
||||
table="table"
|
||||
export-title="exportTitle"
|
||||
per-page="perPage">
|
||||
per-page="perPage"
|
||||
sort="sort">
|
||||
</kbn-agg-table>
|
||||
</td>
|
||||
</tr>
|
||||
|
@ -32,12 +33,13 @@
|
|||
<tbody>
|
||||
<tr>
|
||||
<td ng-repeat="table in columns">
|
||||
<kbn-agg-table-group ng-if="table.tables" group="table" per-page="perPage"></kbn-agg-table-group>
|
||||
<kbn-agg-table-group ng-if="table.tables" group="table" per-page="perPage" sort="sort"></kbn-agg-table-group>
|
||||
<kbn-agg-table
|
||||
ng-if="table.rows"
|
||||
table="table"
|
||||
export-title="exportTitle"
|
||||
per-page="perPage">
|
||||
per-page="perPage"
|
||||
sort="sort">
|
||||
</kbn-agg-table>
|
||||
</td>
|
||||
</tr>
|
||||
|
|
|
@ -12,6 +12,7 @@ uiModules
|
|||
scope: {
|
||||
group: '=',
|
||||
perPage: '=?',
|
||||
sort: '=?',
|
||||
exportTitle: '=?'
|
||||
},
|
||||
compile: function ($el) {
|
||||
|
|
|
@ -75,6 +75,9 @@ describe('AggConfig Filters', function () {
|
|||
expect(fieldParams).to.have.property('lte');
|
||||
expect(fieldParams.lte).to.be.a('number');
|
||||
|
||||
expect(fieldParams).to.have.property('format');
|
||||
expect(fieldParams.format).to.be('epoch_millis');
|
||||
|
||||
expect(fieldParams.gte).to.be.lessThan(fieldParams.lte);
|
||||
|
||||
expect(filter).to.have.property('meta');
|
||||
|
|
61
src/ui/public/agg_types/__tests__/metrics/median.js
Normal file
61
src/ui/public/agg_types/__tests__/metrics/median.js
Normal file
|
@ -0,0 +1,61 @@
|
|||
import expect from 'expect.js';
|
||||
import ngMock from 'ng_mock';
|
||||
import AggTypeMetricMedianProvider from 'ui/agg_types/metrics/median';
|
||||
import VisProvider from 'ui/vis';
|
||||
import FixturesStubbedLogstashIndexPatternProvider from 'fixtures/stubbed_logstash_index_pattern';
|
||||
|
||||
describe('AggTypeMetricMedianProvider class', function () {
|
||||
|
||||
let vis;
|
||||
let indexPattern;
|
||||
let aggTypeMetricMedian;
|
||||
let aggDsl;
|
||||
|
||||
beforeEach(ngMock.module('kibana'));
|
||||
beforeEach(ngMock.inject(function (Private) {
|
||||
const Vis = Private(VisProvider);
|
||||
indexPattern = Private(FixturesStubbedLogstashIndexPatternProvider);
|
||||
aggTypeMetricMedian = Private(AggTypeMetricMedianProvider);
|
||||
|
||||
let vis = new Vis(indexPattern, {
|
||||
'title': 'New Visualization',
|
||||
'type': 'metric',
|
||||
'params': {
|
||||
'fontSize': 60,
|
||||
'handleNoResults': true
|
||||
},
|
||||
'aggs': [
|
||||
{
|
||||
'id': '1',
|
||||
'type': 'median',
|
||||
'schema': 'metric',
|
||||
'params': {
|
||||
'field': 'bytes',
|
||||
'percents': [
|
||||
50
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
'listeners': {}
|
||||
});
|
||||
|
||||
// Grab the aggConfig off the vis (we don't actually use the vis for
|
||||
// anything else)
|
||||
let aggConfig = vis.aggs[0];
|
||||
aggDsl = aggConfig.toDsl();
|
||||
}));
|
||||
|
||||
it('requests the percentiles aggregation in the Elasticsearch query DSL', function () {
|
||||
expect(Object.keys(aggDsl)[0]).to.be('percentiles');
|
||||
});
|
||||
|
||||
it ('asks Elasticsearch for the 50th percentile', function () {
|
||||
expect(aggDsl.percentiles.percents).to.eql([50]);
|
||||
});
|
||||
|
||||
it ('asks Elasticsearch for array-based values in the aggregation response', function () {
|
||||
expect(aggDsl.percentiles.keyed).to.be(false);
|
||||
});
|
||||
|
||||
});
|
|
@ -0,0 +1,40 @@
|
|||
import expect from 'expect.js';
|
||||
import ngMock from 'ng_mock';
|
||||
import AggTypeMetricPercentileRanksProvider from 'ui/agg_types/metrics/percentile_ranks';
|
||||
import VisProvider from 'ui/vis';
|
||||
import FixturesStubbedLogstashIndexPatternProvider from 'fixtures/stubbed_logstash_index_pattern';
|
||||
|
||||
describe('AggTypeMetricPercentileRanksProvider class', function () {
|
||||
|
||||
let Vis;
|
||||
let indexPattern;
|
||||
let aggTypeMetricPercentileRanks;
|
||||
|
||||
beforeEach(ngMock.module('kibana'));
|
||||
beforeEach(ngMock.inject(function (Private) {
|
||||
Vis = Private(VisProvider);
|
||||
indexPattern = Private(FixturesStubbedLogstashIndexPatternProvider);
|
||||
aggTypeMetricPercentileRanks = Private(AggTypeMetricPercentileRanksProvider);
|
||||
}));
|
||||
|
||||
it('uses the custom label if it is set', function () {
|
||||
const vis = new Vis(indexPattern, {});
|
||||
|
||||
// Grab the aggConfig off the vis (we don't actually use the vis for
|
||||
// anything else)
|
||||
const aggConfig = vis.aggs[0];
|
||||
aggConfig.params.customLabel = 'my custom field label';
|
||||
aggConfig.params.values = [ 5000, 10000 ];
|
||||
aggConfig.params.field = {
|
||||
displayName: 'bytes'
|
||||
};
|
||||
|
||||
const responseAggs = aggTypeMetricPercentileRanks.getResponseAggs(aggConfig);
|
||||
const percentileRankLabelFor5kBytes = responseAggs[0].makeLabel();
|
||||
const percentileRankLabelFor10kBytes = responseAggs[1].makeLabel();
|
||||
|
||||
expect(percentileRankLabelFor5kBytes).to.be('Percentile rank 5,000 of "my custom field label"');
|
||||
expect(percentileRankLabelFor10kBytes).to.be('Percentile rank 10,000 of "my custom field label"');
|
||||
});
|
||||
|
||||
});
|
38
src/ui/public/agg_types/__tests__/metrics/percentiles.js
Normal file
38
src/ui/public/agg_types/__tests__/metrics/percentiles.js
Normal file
|
@ -0,0 +1,38 @@
|
|||
import expect from 'expect.js';
|
||||
import ngMock from 'ng_mock';
|
||||
import AggTypeMetricPercentilesProvider from 'ui/agg_types/metrics/percentiles';
|
||||
import VisProvider from 'ui/vis';
|
||||
import FixturesStubbedLogstashIndexPatternProvider from 'fixtures/stubbed_logstash_index_pattern';
|
||||
|
||||
describe('AggTypeMetricPercentilesProvider class', function () {
|
||||
|
||||
let Vis;
|
||||
let indexPattern;
|
||||
let aggTypeMetricPercentiles;
|
||||
|
||||
beforeEach(ngMock.module('kibana'));
|
||||
beforeEach(ngMock.inject(function (Private) {
|
||||
Vis = Private(VisProvider);
|
||||
indexPattern = Private(FixturesStubbedLogstashIndexPatternProvider);
|
||||
aggTypeMetricPercentiles = Private(AggTypeMetricPercentilesProvider);
|
||||
}));
|
||||
|
||||
it('uses the custom label if it is set', function () {
|
||||
const vis = new Vis(indexPattern, {});
|
||||
|
||||
// Grab the aggConfig off the vis (we don't actually use the vis for
|
||||
// anything else)
|
||||
const aggConfig = vis.aggs[0];
|
||||
aggConfig.params.customLabel = 'prince';
|
||||
aggConfig.params.percents = [ 95 ];
|
||||
aggConfig.params.field = {
|
||||
displayName: 'bytes'
|
||||
};
|
||||
|
||||
const responseAggs = aggTypeMetricPercentiles.getResponseAggs(aggConfig);
|
||||
const ninetyFifthPercentileLabel = responseAggs[0].makeLabel();
|
||||
|
||||
expect(ninetyFifthPercentileLabel).to.be('95th percentile of prince');
|
||||
});
|
||||
|
||||
});
|
|
@ -33,9 +33,29 @@ describe('AggTypeMetricStandardDeviationProvider class', function () {
|
|||
let avgLabel = responseAggs[1].makeLabel();
|
||||
let upperStdDevLabel = responseAggs[2].makeLabel();
|
||||
|
||||
expect(lowerStdDevLabel).to.be('Lower custom label of memory');
|
||||
expect(lowerStdDevLabel).to.be('Lower custom label');
|
||||
expect(avgLabel).to.be('Average of memory'); // not expected to use custom label
|
||||
expect(upperStdDevLabel).to.be('Upper custom label of memory');
|
||||
expect(upperStdDevLabel).to.be('Upper custom label');
|
||||
});
|
||||
|
||||
it('uses the default labels if custom label is not set', function () {
|
||||
let vis = new Vis(indexPattern, {});
|
||||
|
||||
// Grab the aggConfig off the vis (we don't actually use the vis for
|
||||
// anything else)
|
||||
let aggConfig = vis.aggs[0];
|
||||
aggConfig.params.field = {
|
||||
displayName: 'memory'
|
||||
};
|
||||
|
||||
let responseAggs = aggTypeMetricStandardDeviation.getResponseAggs(aggConfig);
|
||||
let lowerStdDevLabel = responseAggs[0].makeLabel();
|
||||
let avgLabel = responseAggs[1].makeLabel();
|
||||
let upperStdDevLabel = responseAggs[2].makeLabel();
|
||||
|
||||
expect(lowerStdDevLabel).to.be('Lower Standard Deviation of memory');
|
||||
expect(avgLabel).to.be('Average of memory'); // not expected to use custom label
|
||||
expect(upperStdDevLabel).to.be('Upper Standard Deviation of memory');
|
||||
});
|
||||
|
||||
});
|
||||
|
|
|
@ -8,7 +8,8 @@ export default function createDateHistogramFilterProvider(Private) {
|
|||
|
||||
return buildRangeFilter(agg.params.field, {
|
||||
gte: start.valueOf(),
|
||||
lte: start.add(interval).subtract(1, 'ms').valueOf()
|
||||
lte: start.add(interval).subtract(1, 'ms').valueOf(),
|
||||
format: 'epoch_millis'
|
||||
}, agg.vis.indexPattern);
|
||||
};
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ import _ from 'lodash';
|
|||
import AggTypesMetricsMetricAggTypeProvider from 'ui/agg_types/metrics/metric_agg_type';
|
||||
import AggTypesMetricsGetResponseAggConfigClassProvider from 'ui/agg_types/metrics/get_response_agg_config_class';
|
||||
import AggTypesMetricsPercentilesProvider from 'ui/agg_types/metrics/percentiles';
|
||||
export default function AggTypeMetricMaxProvider(Private) {
|
||||
export default function AggTypeMetricMedianProvider(Private) {
|
||||
let MetricAggType = Private(AggTypesMetricsMetricAggTypeProvider);
|
||||
let getResponseAggConfigClass = Private(AggTypesMetricsGetResponseAggConfigClassProvider);
|
||||
let percentiles = Private(AggTypesMetricsPercentilesProvider);
|
||||
|
@ -22,6 +22,11 @@ export default function AggTypeMetricMaxProvider(Private) {
|
|||
{
|
||||
name: 'percents',
|
||||
default: [50]
|
||||
},
|
||||
{
|
||||
write(agg, output) {
|
||||
output.params.keyed = false;
|
||||
}
|
||||
}
|
||||
],
|
||||
getResponseAggs: percentiles.getResponseAggs,
|
||||
|
|
|
@ -17,8 +17,9 @@ export default function AggTypeMetricPercentileRanksProvider(Private) {
|
|||
makeLabel: function () {
|
||||
let field = this.field();
|
||||
let format = (field && field.format) || fieldFormats.getDefaultInstance('number');
|
||||
const label = this.params.customLabel || this.fieldDisplayName();
|
||||
|
||||
return 'Percentile rank ' + format.convert(this.key, 'text') + ' of "' + this.fieldDisplayName() + '"';
|
||||
return 'Percentile rank ' + format.convert(this.key, 'text') + ' of "' + label + '"';
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -16,7 +16,8 @@ export default function AggTypeMetricPercentilesProvider(Private) {
|
|||
|
||||
let valueProps = {
|
||||
makeLabel: function () {
|
||||
return ordinalSuffix(this.key) + ' percentile of ' + this.fieldDisplayName();
|
||||
const label = this.params.customLabel || this.fieldDisplayName();
|
||||
return ordinalSuffix(this.key) + ' percentile of ' + label;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -11,11 +11,12 @@ export default function AggTypeMetricStandardDeviationProvider(Private) {
|
|||
return details.valProp;
|
||||
},
|
||||
makeLabel: function () {
|
||||
let details = this.keyedDetails(this.params.customLabel)[this.key];
|
||||
return details.title + ' of ' + this.fieldDisplayName();
|
||||
const fieldDisplayName = this.fieldDisplayName();
|
||||
const details = this.keyedDetails(this.params.customLabel, fieldDisplayName);
|
||||
return _.get(details, [this.key, 'title']);
|
||||
},
|
||||
keyedDetails: function (customLabel) {
|
||||
const label = customLabel ? customLabel : 'Standard Deviation';
|
||||
keyedDetails: function (customLabel, fieldDisplayName) {
|
||||
const label = customLabel ? customLabel : 'Standard Deviation of ' + fieldDisplayName;
|
||||
return {
|
||||
std_lower: {
|
||||
valProp: ['std_deviation_bounds', 'lower'],
|
||||
|
@ -23,7 +24,7 @@ export default function AggTypeMetricStandardDeviationProvider(Private) {
|
|||
},
|
||||
avg: {
|
||||
valProp: 'avg',
|
||||
title: 'Average'
|
||||
title: 'Average of ' + fieldDisplayName
|
||||
},
|
||||
std_upper: {
|
||||
valProp: ['std_deviation_bounds', 'upper'],
|
||||
|
|
31
src/ui/public/chrome/api/angular.js
vendored
31
src/ui/public/chrome/api/angular.js
vendored
|
@ -1,5 +1,11 @@
|
|||
import _ from 'lodash';
|
||||
import { format as formatUrl, parse as parseUrl } from 'url';
|
||||
|
||||
import modules from 'ui/modules';
|
||||
import Notifier from 'ui/notify/notifier';
|
||||
import { UrlOverflowServiceProvider } from '../../error_url_overflow';
|
||||
|
||||
const URL_LIMIT_WARN_WITHIN = 150;
|
||||
|
||||
module.exports = function (chrome, internals) {
|
||||
|
||||
|
@ -26,7 +32,7 @@ module.exports = function (chrome, internals) {
|
|||
return a.href;
|
||||
}()))
|
||||
.config(chrome.$setupXsrfRequestInterceptor)
|
||||
.run(($location) => {
|
||||
.run(($location, $rootScope, Private) => {
|
||||
chrome.getFirstPathSegment = () => {
|
||||
return $location.path().split('/')[1];
|
||||
};
|
||||
|
@ -34,6 +40,29 @@ module.exports = function (chrome, internals) {
|
|||
chrome.getBreadcrumbs = () => {
|
||||
return $location.path().split('/').slice(1);
|
||||
};
|
||||
|
||||
const notify = new Notifier();
|
||||
const urlOverflow = Private(UrlOverflowServiceProvider);
|
||||
const check = (event) => {
|
||||
if ($location.path() === '/error/url-overflow') return;
|
||||
|
||||
try {
|
||||
if (urlOverflow.check($location.absUrl()) <= URL_LIMIT_WARN_WITHIN) {
|
||||
notify.warning(`
|
||||
The URL has gotten big and may cause Kibana
|
||||
to stop working. Please simplify the data on screen.
|
||||
`);
|
||||
}
|
||||
} catch (e) {
|
||||
const { host, path, search, protocol } = parseUrl(window.location.href);
|
||||
// rewrite the entire url to force the browser to reload and
|
||||
// discard any potentially unstable state from before
|
||||
window.location.href = formatUrl({ host, path, search, protocol, hash: '#/error/url-overflow' });
|
||||
}
|
||||
};
|
||||
|
||||
$rootScope.$on('$routeUpdate', check);
|
||||
$rootScope.$on('$routeChangeStart', check);
|
||||
});
|
||||
|
||||
require('../directives')(chrome, internals);
|
||||
|
|
|
@ -2,8 +2,10 @@ import moment from 'moment-timezone';
|
|||
import _ from 'lodash';
|
||||
|
||||
export default function configDefaultsProvider() {
|
||||
// wrapped in provider so that a new instance is given to each app/test
|
||||
const weekdays = moment.weekdays().slice();
|
||||
const [defaultWeekday] = weekdays;
|
||||
|
||||
// wrapped in provider so that a new instance is given to each app/test
|
||||
return {
|
||||
'buildNum': {
|
||||
readonly: true
|
||||
|
@ -46,6 +48,12 @@ export default function configDefaultsProvider() {
|
|||
' <a href="http://en.wikipedia.org/wiki/ISO_8601#Time_intervals" target="_blank">' +
|
||||
'ISO8601 intervals.</a>'
|
||||
},
|
||||
'dateFormat:dow': {
|
||||
value: defaultWeekday,
|
||||
description: 'What day should weeks start on?',
|
||||
type: 'select',
|
||||
options: weekdays
|
||||
},
|
||||
'defaultIndex': {
|
||||
value: null,
|
||||
description: 'The index to access if no index is set',
|
||||
|
@ -228,6 +236,6 @@ export default function configDefaultsProvider() {
|
|||
value: 5000,
|
||||
description: 'The time in milliseconds which an information notification ' +
|
||||
'will be displayed on-screen for. Setting to Infinity will disable.'
|
||||
}
|
||||
},
|
||||
};
|
||||
};
|
||||
|
|
|
@ -1,32 +1,80 @@
|
|||
import _ from 'lodash';
|
||||
import $ from 'jquery';
|
||||
import uiModules from 'ui/modules';
|
||||
let module = uiModules.get('kibana');
|
||||
|
||||
module.directive('fileUpload', function ($parse) {
|
||||
let html = '<span class="dropzone" ng-transclude></span>';
|
||||
|
||||
module.directive('fileUpload', function () {
|
||||
return {
|
||||
restrict: 'A',
|
||||
restrict: 'E',
|
||||
transclude: true,
|
||||
scope: {
|
||||
onRead: '&',
|
||||
onLocate: '&',
|
||||
uploadSelector: '@'
|
||||
},
|
||||
template: html,
|
||||
link: function ($scope, $elem, attrs) {
|
||||
let onUpload = $parse(attrs.fileUpload);
|
||||
let $button = $elem.find($scope.uploadSelector);
|
||||
let $dropzone = $elem.find('.dropzone');
|
||||
|
||||
let $fileInput = $('<input type="file" style="opacity: 0" id="testfile" />');
|
||||
$elem.after($fileInput);
|
||||
const handleFile = (file) => {
|
||||
if (_.isUndefined(file)) return;
|
||||
|
||||
$fileInput.on('change', function (e) {
|
||||
let reader = new FileReader();
|
||||
reader.onload = function (e) {
|
||||
$scope.$apply(function () {
|
||||
onUpload($scope, {fileContents: e.target.result});
|
||||
});
|
||||
};
|
||||
if ($scope.onRead) {
|
||||
let reader = new FileReader();
|
||||
reader.onload = function (e) {
|
||||
$scope.$apply(function () {
|
||||
$scope.onRead({fileContents: e.target.result});
|
||||
});
|
||||
};
|
||||
reader.readAsText(file);
|
||||
}
|
||||
|
||||
let target = e.srcElement || e.target;
|
||||
if (target && target.files && target.files.length) reader.readAsText(target.files[0]);
|
||||
if ($scope.onLocate) {
|
||||
$scope.onLocate({ file });
|
||||
}
|
||||
};
|
||||
|
||||
$dropzone.on('dragover', function (e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
}
|
||||
);
|
||||
|
||||
$dropzone.on('dragenter', function (e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
}
|
||||
);
|
||||
|
||||
$dropzone.on('drop', function (e) {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
const file = _.get(e, 'originalEvent.dataTransfer.files[0]');
|
||||
|
||||
if (file) {
|
||||
handleFile(file);
|
||||
}
|
||||
});
|
||||
|
||||
$elem.on('click', function (e) {
|
||||
$fileInput.val(null);
|
||||
$fileInput.trigger('click');
|
||||
});
|
||||
if ($button) {
|
||||
const $fileInput = $('<input type="file" style="opacity: 0; position:absolute; right: -999999999px" id="testfile" />');
|
||||
$elem.append($fileInput);
|
||||
|
||||
$fileInput.on('change', function (e) {
|
||||
let target = e.srcElement || e.target;
|
||||
if (_.get(target, 'files.length')) {
|
||||
handleFile(target.files[0]);
|
||||
}
|
||||
});
|
||||
|
||||
$button.on('click', function (e) {
|
||||
$fileInput.val(null);
|
||||
$fileInput.trigger('click');
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import _ from 'lodash';
|
||||
import dateMath from 'ui/utils/date_math';
|
||||
import dateMath from '@elastic/datemath';
|
||||
import moment from 'moment';
|
||||
import 'ui/timepicker/quick_ranges';
|
||||
import 'ui/timepicker/time_units';
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import _ from 'lodash';
|
||||
import dateMath from 'ui/utils/date_math';
|
||||
import dateMath from '@elastic/datemath';
|
||||
import uiModules from 'ui/modules';
|
||||
|
||||
uiModules.get('kibana').directive('validateDateMath', function () {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<%
|
||||
let attributes = '';
|
||||
var attributes = '';
|
||||
if (timefield) {
|
||||
attributes='class="discover-table-timefield" width="1%"';
|
||||
} else if (sourcefield) {
|
||||
|
|
18
src/ui/public/error_url_overflow/error_url_overflow.html
Normal file
18
src/ui/public/error_url_overflow/error_url_overflow.html
Normal file
|
@ -0,0 +1,18 @@
|
|||
<div class="app-container error-url-overflow-app">
|
||||
<h3>
|
||||
<i aria-hidden="true" class="fa fa-warning text-danger"></i> Woah there!
|
||||
</h3>
|
||||
<p>
|
||||
That's a big URL you have there. I have some unfortunate news: Your browser doesn't play nice with Kibana's bacon-double-cheese-burger-with-extra-fries sized URL. To keep you from running into problems Kibana limits URLs in your browser to {{controller.limit}} characters for your safety.
|
||||
</p>
|
||||
|
||||
<h3>Ok, how do I fix this?</h3>
|
||||
<p>This usually only happens with big, complex dashboards, so you have some options:</p>
|
||||
<ol>
|
||||
<li>Remove some stuff from your dashboard. This will reduce the length of the URL and keep IE in a good place.</li>
|
||||
<li>Don't use IE. Every other supported browser we know of doesn't have this limit.</li>
|
||||
</ol>
|
||||
<br>
|
||||
<br>
|
||||
<p><small>Foot note: Party size candy bars are tiny. Party size sub sandwiches are massive. Really makes you think.</small></p>
|
||||
</div>
|
30
src/ui/public/error_url_overflow/error_url_overflow.js
Normal file
30
src/ui/public/error_url_overflow/error_url_overflow.js
Normal file
|
@ -0,0 +1,30 @@
|
|||
import uiRoutes from 'ui/routes';
|
||||
import uiModules from 'ui/modules';
|
||||
import KbnUrlProvider from 'ui/url';
|
||||
|
||||
import './error_url_overflow.less';
|
||||
import template from './error_url_overflow.html';
|
||||
import { UrlOverflowServiceProvider } from './url_overflow_service';
|
||||
|
||||
export * from './url_overflow_service';
|
||||
|
||||
uiRoutes
|
||||
.when('/error/url-overflow', {
|
||||
template,
|
||||
controllerAs: 'controller',
|
||||
controller: class OverflowController {
|
||||
constructor(Private, config, $scope) {
|
||||
const kbnUrl = Private(KbnUrlProvider);
|
||||
const urlOverflow = Private(UrlOverflowServiceProvider);
|
||||
|
||||
if (!urlOverflow.get()) {
|
||||
kbnUrl.redirectPath('/');
|
||||
return;
|
||||
}
|
||||
|
||||
this.url = urlOverflow.get();
|
||||
this.limit = urlOverflow.failLength();
|
||||
$scope.$on('$destroy', () => urlOverflow.clear());
|
||||
}
|
||||
}
|
||||
});
|
7
src/ui/public/error_url_overflow/error_url_overflow.less
Normal file
7
src/ui/public/error_url_overflow/error_url_overflow.less
Normal file
|
@ -0,0 +1,7 @@
|
|||
.error-url-overflow-app {
|
||||
padding: 25px;
|
||||
|
||||
pre {
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
}
|
65
src/ui/public/error_url_overflow/url_overflow_service.js
Normal file
65
src/ui/public/error_url_overflow/url_overflow_service.js
Normal file
|
@ -0,0 +1,65 @@
|
|||
const URL_MAX_IE = 2000;
|
||||
const URL_MAX_OTHERS = 25000;
|
||||
const IE_REGEX = /(;MSIE |Edge\/\d)/;
|
||||
|
||||
export class UrlOverflowService {
|
||||
constructor() {
|
||||
const key = 'error/url-overflow/url';
|
||||
const store = window.sessionStorage || {
|
||||
getItem() {},
|
||||
setItem() {},
|
||||
removeItem() {},
|
||||
};
|
||||
|
||||
// FIXME: Couldn't find a way to test for browser compatibility without
|
||||
// complex redirect and cookie based "feature-detection" page, so going
|
||||
// with user-agent detection for now.
|
||||
this._ieLike = IE_REGEX.test(window.navigator.userAgent);
|
||||
|
||||
this._val = store.getItem(key);
|
||||
this._sync = () => {
|
||||
if (this._val == null) store.removeItem(key);
|
||||
else store.setItem(key, this._val);
|
||||
};
|
||||
}
|
||||
|
||||
failLength() {
|
||||
return this._ieLike ? URL_MAX_IE : URL_MAX_OTHERS;
|
||||
}
|
||||
|
||||
set(v) {
|
||||
this._val = v;
|
||||
this._sync();
|
||||
}
|
||||
|
||||
get() {
|
||||
return this._val;
|
||||
}
|
||||
|
||||
check(absUrl) {
|
||||
if (!this.get()) {
|
||||
const urlLength = absUrl.length;
|
||||
const remaining = this.failLength() - urlLength;
|
||||
|
||||
if (remaining > 0) {
|
||||
return remaining;
|
||||
}
|
||||
|
||||
this.set(absUrl);
|
||||
}
|
||||
|
||||
throw new Error(`
|
||||
The URL has gotten too big and kibana can no longer
|
||||
continue. Please refresh to return to your previous state.
|
||||
`);
|
||||
}
|
||||
|
||||
clear() {
|
||||
this._val = undefined;
|
||||
this._sync();
|
||||
}
|
||||
}
|
||||
|
||||
export function UrlOverflowServiceProvider() {
|
||||
return new UrlOverflowService();
|
||||
}
|
|
@ -1,110 +1,32 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
id="Layer_1"
|
||||
data-name="Layer 1"
|
||||
viewBox="0 0 141.37 51"
|
||||
version="1.1"
|
||||
inkscape:version="0.91 r13725"
|
||||
sodipodi:docname="kibana.svg">
|
||||
<metadata
|
||||
id="metadata31">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title>Kibana-Full-Logo</dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<sodipodi:namedview
|
||||
pagecolor="#515151"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="1"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="1796"
|
||||
inkscape:window-height="1079"
|
||||
id="namedview29"
|
||||
showgrid="false"
|
||||
inkscape:zoom="2.0725756"
|
||||
inkscape:cx="70.684998"
|
||||
inkscape:cy="25.5"
|
||||
inkscape:window-x="349"
|
||||
inkscape:window-y="210"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="Layer_1" />
|
||||
<defs
|
||||
id="defs3">
|
||||
<style
|
||||
id="style5">.cls-1,.cls-2,.cls-3,.cls-4{fill:#fff;}.cls-1{opacity:0.6;}.cls-2{opacity:0.4;}.cls-3{opacity:0.9;}</style>
|
||||
</defs>
|
||||
<title
|
||||
id="title7">Kibana-Full-Logo</title>
|
||||
<path
|
||||
class="cls-1"
|
||||
d="M409.68,273.59a38.94,38.94,0,0,1,18.71,4.76L448.2,254.5H408.94v19.11Z"
|
||||
transform="translate(-408.94 -254.5)"
|
||||
id="path9" />
|
||||
<path
|
||||
class="cls-1"
|
||||
d="M428.39,278.35l-19.45,23.42v3.73h39.2A39.2,39.2,0,0,0,428.39,278.35Z"
|
||||
transform="translate(-408.94 -254.5)"
|
||||
id="path11" />
|
||||
<path
|
||||
class="cls-2"
|
||||
d="M428.39,278.35l-19.45,23.42v3.73h7l18.87-22.77s-1.25-1.06-3-2.3C430.41,279.46,428.39,278.35,428.39,278.35Z"
|
||||
transform="translate(-408.94 -254.5)"
|
||||
id="path13" />
|
||||
<path
|
||||
class="cls-3"
|
||||
d="M409.68,273.59l-0.74,0v28.17l19.45-23.42A38.94,38.94,0,0,0,409.68,273.59Z"
|
||||
transform="translate(-408.94 -254.5)"
|
||||
id="path15" />
|
||||
<g
|
||||
style="font-style:normal;font-weight:normal;font-size:33.04906845px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:0.92528737;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
id="text4159"
|
||||
transform="translate(0,-13.509761)">
|
||||
<path
|
||||
d="m 53.346838,50.53812 0,-6.74201 2.14819,-0.231343 4.031986,6.973353 4.065036,0 -5.023459,-8.791052 4.759066,-7.733482 -4.031986,0 -3.89979,6.444568 -2.049043,0.198295 0,-13.517069 -3.602348,0 0,23.39874 3.602348,0 z"
|
||||
style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:Titillium;-inkscape-font-specification:'Titillium Semi-Bold';fill:#ffffff;fill-opacity:0.92528737"
|
||||
id="path4891"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
d="m 66.269024,50.53812 3.602349,0 0,-16.524534 -3.602349,0 0,16.524534 z m 0,-19.333705 3.602349,0 0,-3.800643 -3.602349,0 0,3.800643 z"
|
||||
style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:Titillium;-inkscape-font-specification:'Titillium Semi-Bold';fill:#ffffff;fill-opacity:0.92528737"
|
||||
id="path4893"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
d="m 81.973529,33.650046 c -1.850747,0 -4.131133,0.991472 -4.131133,0.991472 l 0,-7.502138 -3.5693,0 0,23.365691 c 0,0 4.296379,0.396589 6.04798,0.396589 5.915783,0 8.063973,-2.015993 8.063973,-8.85715 0,-6.180176 -1.916846,-8.394464 -6.41152,-8.394464 z M 80.321076,47.6959 c -0.660981,0 -2.47868,-0.132196 -2.47868,-0.132196 l 0,-10.046917 c 0,0 1.949895,-0.660981 3.701495,-0.660981 2.214288,0 3.172711,1.454159 3.172711,5.188704 0,4.031986 -0.727079,5.65139 -4.395526,5.65139 z"
|
||||
style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:Titillium;-inkscape-font-specification:'Titillium Semi-Bold';fill:#ffffff;fill-opacity:0.92528737"
|
||||
id="path4895"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
d="m 104.18766,39.103143 c 0,-3.767594 -1.65245,-5.453097 -5.684435,-5.453097 -3.040515,0 -6.642863,0.859276 -6.642863,0.859276 l 0.132196,2.544778 c 0,0 3.998938,-0.33049 6.213225,-0.33049 1.619405,0 2.412587,0.561834 2.412587,2.379533 l 0,1.189766 -4.263335,0.36354 c -3.53625,0.297441 -5.453096,1.487208 -5.453096,4.990409 0,3.437103 1.652453,5.254802 4.924311,5.254802 2.676975,0 5.3209,-1.222816 5.3209,-1.222816 1.22282,0.958423 2.37953,1.222816 4.39553,1.222816 l 0.0991,-2.743073 c -0.95842,-0.132196 -1.38806,-0.528785 -1.45416,-1.520257 l 0,-7.535187 z m -3.56929,3.734544 0,4.395526 c 0,0 -2.214292,0.72708 -4.098089,0.72708 -1.388061,0 -2.015993,-0.925374 -2.015993,-2.412582 0,-1.487208 0.760128,-2.214288 2.280385,-2.346484 l 3.833697,-0.36354 z"
|
||||
style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:Titillium;-inkscape-font-specification:'Titillium Semi-Bold';fill:#ffffff;fill-opacity:0.92528737"
|
||||
id="path4897"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
d="m 112.28004,50.53812 0,-12.823038 c 0,0 1.8177,-0.859276 3.73454,-0.859276 2.51173,0 2.94137,1.619404 2.94137,4.924311 l 0,8.758003 3.5693,0 0,-8.85715 c 0,-5.420047 -1.12367,-8.030924 -5.71749,-8.030924 -2.14819,0 -4.56077,1.388061 -4.56077,1.388061 l 0,-1.024521 -3.5693,0 0,16.524534 3.60235,0 z"
|
||||
style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:Titillium;-inkscape-font-specification:'Titillium Semi-Bold';fill:#ffffff;fill-opacity:0.92528737"
|
||||
id="path4899"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
d="m 138.91501,39.103143 c 0,-3.767594 -1.65246,-5.453097 -5.68444,-5.453097 -3.04052,0 -6.64287,0.859276 -6.64287,0.859276 l 0.1322,2.544778 c 0,0 3.99894,-0.33049 6.21322,-0.33049 1.61941,0 2.41259,0.561834 2.41259,2.379533 l 0,1.189766 -4.26333,0.36354 c -3.53625,0.297441 -5.4531,1.487208 -5.4531,4.990409 0,3.437103 1.65245,5.254802 4.92431,5.254802 2.67698,0 5.3209,-1.222816 5.3209,-1.222816 1.22282,0.958423 2.37953,1.222816 4.39553,1.222816 l 0.0991,-2.743073 c -0.95842,-0.132196 -1.38806,-0.528785 -1.45415,-1.520257 l 0,-7.535187 z m -3.5693,3.734544 0,4.395526 c 0,0 -2.21429,0.72708 -4.09809,0.72708 -1.38806,0 -2.01599,-0.925374 -2.01599,-2.412582 0,-1.487208 0.76013,-2.214288 2.28038,-2.346484 l 3.8337,-0.36354 z"
|
||||
style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:Titillium;-inkscape-font-specification:'Titillium Semi-Bold';fill:#ffffff;fill-opacity:0.92528737"
|
||||
id="path4901"
|
||||
inkscape:connector-curvature="0" />
|
||||
</g>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<svg xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" id="Layer_1" inkscape:version="0.91 r13725" sodipodi:docname="kibana.svg" x="0px" y="0px" viewBox="0 0 141.4 51" style="enable-background:new 0 0 141.4 51;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#FFFFFF;fill-opacity:0.9253;}
|
||||
.st1{opacity:0.7;fill:#FFFFFF;}
|
||||
.st2{opacity:0.5;fill:#FFFFFF;}
|
||||
.st3{fill:#FFFFFF;}
|
||||
</style>
|
||||
<sodipodi:namedview bordercolor="#666666" borderopacity="1" gridtolerance="10" guidetolerance="10" id="namedview29" inkscape:current-layer="Layer_1" inkscape:cx="70.684998" inkscape:cy="25.5" inkscape:pageopacity="1" inkscape:pageshadow="2" inkscape:window-height="1079" inkscape:window-maximized="0" inkscape:window-width="1796" inkscape:window-x="349" inkscape:window-y="210" inkscape:zoom="2.0725756" objecttolerance="10" pagecolor="#515151" showgrid="false">
|
||||
</sodipodi:namedview>
|
||||
<title id="title7">Kibana-Full-Logo</title>
|
||||
<g id="text4159" transform="translate(0,-13.509761)">
|
||||
<path id="path4891" inkscape:connector-curvature="0" class="st0" d="M53.3,50.5v-6.7l2.1-0.2l4,7h4.1l-5-8.8l4.8-7.7h-4l-3.9,6.4 l-2,0.2V27.1h-3.6v23.4C49.7,50.5,53.3,50.5,53.3,50.5z"/>
|
||||
<path id="path4893" inkscape:connector-curvature="0" class="st0" d="M66.3,50.5h3.6V34h-3.6C66.3,34,66.3,50.5,66.3,50.5z M66.3,31.2h3.6v-3.8h-3.6V31.2z"/>
|
||||
<path id="path4895" inkscape:connector-curvature="0" class="st0" d="M82,33.7c-1.9,0-4.1,1-4.1,1v-7.5h-3.6v23.4 c0,0,4.3,0.4,6,0.4c5.9,0,8.1-2,8.1-8.9C88.4,35.9,86.5,33.7,82,33.7z M80.3,47.7c-0.7,0-2.5-0.1-2.5-0.1v-10c0,0,1.9-0.7,3.7-0.7 c2.2,0,3.2,1.5,3.2,5.2C84.7,46.1,84,47.7,80.3,47.7z"/>
|
||||
<path id="path4897" inkscape:connector-curvature="0" class="st0" d="M104.2,39.1c0-3.8-1.7-5.5-5.7-5.5c-3,0-6.6,0.9-6.6,0.9 l0.1,2.5c0,0,4-0.3,6.2-0.3c1.6,0,2.4,0.6,2.4,2.4v1.2l-4.3,0.4c-3.5,0.3-5.5,1.5-5.5,5c0,3.4,1.7,5.3,4.9,5.3 c2.7,0,5.3-1.2,5.3-1.2c1.2,1,2.4,1.2,4.4,1.2l0.1-2.7c-1-0.1-1.4-0.5-1.5-1.5L104.2,39.1L104.2,39.1z M100.6,42.8v4.4 c0,0-2.2,0.7-4.1,0.7c-1.4,0-2-0.9-2-2.4s0.8-2.2,2.3-2.3L100.6,42.8z"/>
|
||||
<path id="path4899" inkscape:connector-curvature="0" class="st0" d="M112.3,50.5V37.7c0,0,1.8-0.9,3.7-0.9c2.5,0,2.9,1.6,2.9,4.9 v8.8h3.6v-8.9c0-5.4-1.1-8-5.7-8c-2.1,0-4.6,1.4-4.6,1.4v-1h-3.6v16.5C108.7,50.5,112.3,50.5,112.3,50.5z"/>
|
||||
<path id="path4901" inkscape:connector-curvature="0" class="st0" d="M138.9,39.1c0-3.8-1.7-5.5-5.7-5.5c-3,0-6.6,0.9-6.6,0.9 l0.1,2.5c0,0,4-0.3,6.2-0.3c1.6,0,2.4,0.6,2.4,2.4v1.2l-4.3,0.4c-3.5,0.3-5.5,1.5-5.5,5c0,3.4,1.7,5.3,4.9,5.3 c2.7,0,5.3-1.2,5.3-1.2c1.2,1,2.4,1.2,4.4,1.2l0.1-2.7c-1-0.1-1.4-0.5-1.5-1.5L138.9,39.1L138.9,39.1z M135.3,42.8v4.4 c0,0-2.2,0.7-4.1,0.7c-1.4,0-2-0.9-2-2.4s0.8-2.2,2.3-2.3L135.3,42.8z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path class="st1" d="M19.4,23.8L39.3,0H0v19.1c0.2,0,0.5,0,0.7,0C7.5,19.1,13.9,20.8,19.4,23.8z"/>
|
||||
<polygon class="st1" points="0,47.3 0,47.3 19.4,23.8 "/>
|
||||
<path class="st1" d="M24.5,27.1c0.2,0.2,0.4,0.3,0.5,0.4C24.9,27.4,24.7,27.3,24.5,27.1z"/>
|
||||
<path class="st1" d="M23,26c0.1,0.1,0.2,0.1,0.3,0.2C23.2,26.2,23.1,26.1,23,26z"/>
|
||||
<path class="st1" d="M25.8,28.2L7,51h32.2C37.5,41.9,32.7,33.9,25.8,28.2z"/>
|
||||
<path class="st2" d="M22.8,25.9c-1.4-1-3.4-2.1-3.4-2.1c1.2,0.7,2.4,1.4,3.6,2.2C22.9,26,22.9,26,22.8,25.9z"/>
|
||||
<path class="st2" d="M25.9,28.2c0,0-0.3-0.2-0.8-0.6C25.3,27.8,25.6,28,25.9,28.2L25.9,28.2z"/>
|
||||
<path class="st2" d="M23.3,26.3c0.4,0.3,0.8,0.6,1.2,0.9C24.2,26.9,23.8,26.6,23.3,26.3z"/>
|
||||
<path class="st2" d="M25.1,27.6c-0.2-0.1-0.3-0.3-0.5-0.4c-0.4-0.3-0.8-0.6-1.2-0.9c-0.1-0.1-0.2-0.1-0.3-0.2 c-1.1-0.8-2.3-1.5-3.6-2.2L0,47.3V51h7l18.9-22.8C25.6,28,25.3,27.8,25.1,27.6z"/>
|
||||
<path class="st3" d="M0.7,19.1c-0.2,0-0.5,0-0.7,0v28.2l19.4-23.4C13.9,20.8,7.5,19.1,0.7,19.1z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
|
Before Width: | Height: | Size: 6.9 KiB After Width: | Height: | Size: 4.1 KiB |
|
@ -87,8 +87,9 @@ export default function ($compile) {
|
|||
}
|
||||
|
||||
const $childScope = $scope.$new();
|
||||
const $el = $compile(templateToRender)($childScope);
|
||||
$element.find('#template_wrapper').html($el);
|
||||
const $el = $element.find('#template_wrapper').html(templateToRender).contents();
|
||||
$compile($el)($childScope);
|
||||
|
||||
this.rendered = { $childScope, $el, key: currentKey };
|
||||
}
|
||||
};
|
||||
|
|
|
@ -49,20 +49,19 @@ if (!!kbnIndex) {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Global Angular exception handler (NOT JUST UNCAUGHT EXCEPTIONS)
|
||||
*/
|
||||
// modules
|
||||
// .get('exceptionOverride')
|
||||
// .factory('$exceptionHandler', function () {
|
||||
// return function (exception, cause) {
|
||||
// rootNotifier.fatal(exception, cause);
|
||||
// };
|
||||
// });
|
||||
|
||||
window.onerror = function (err, url, line) {
|
||||
rootNotifier.fatal(new Error(err + ' (' + url + ':' + line + ')'));
|
||||
return true;
|
||||
};
|
||||
|
||||
if (window.addEventListener) {
|
||||
const notify = new Notifier({
|
||||
location: 'Promise'
|
||||
});
|
||||
|
||||
window.addEventListener('unhandledrejection', function (e) {
|
||||
notify.log(`Detected an unhandled Promise rejection.\n${e.reason}`);
|
||||
});
|
||||
}
|
||||
|
||||
export default rootNotifier;
|
||||
|
|
|
@ -47,12 +47,13 @@ describe('paginated table', function () {
|
|||
};
|
||||
};
|
||||
|
||||
let renderTable = function (cols, rows, perPage) {
|
||||
let renderTable = function (cols, rows, perPage, sort) {
|
||||
$scope.cols = cols || [];
|
||||
$scope.rows = rows || [];
|
||||
$scope.perPage = perPage || defaultPerPage;
|
||||
$scope.sort = sort || {};
|
||||
|
||||
$el = $compile('<paginated-table columns="cols" rows="rows" per-page="perPage">')($scope);
|
||||
$el = $compile('<paginated-table columns="cols" rows="rows" per-page="perPage" sort="sort">')($scope);
|
||||
|
||||
$scope.$digest();
|
||||
};
|
||||
|
@ -160,6 +161,26 @@ describe('paginated table', function () {
|
|||
expect(tableRows.eq(0).find('td').eq(2).text()).to.be('zzzz');
|
||||
});
|
||||
|
||||
it('should set the sort direction to asc when it\'s not explicity set', function () {
|
||||
paginatedTable.sortColumn(1);
|
||||
$scope.$digest();
|
||||
|
||||
var tableRows = $el.find('tbody tr');
|
||||
expect(tableRows.eq(2).find('td').eq(1).text()).to.be('cccc');
|
||||
expect(tableRows.eq(1).find('td').eq(1).text()).to.be('bbbb');
|
||||
expect(tableRows.eq(0).find('td').eq(1).text()).to.be('aaaa');
|
||||
});
|
||||
|
||||
it('should allow you to explicitly set the sort direction', function () {
|
||||
paginatedTable.sortColumn(1, 'desc');
|
||||
$scope.$digest();
|
||||
|
||||
var tableRows = $el.find('tbody tr');
|
||||
expect(tableRows.eq(0).find('td').eq(1).text()).to.be('zzzz');
|
||||
expect(tableRows.eq(1).find('td').eq(1).text()).to.be('cccc');
|
||||
expect(tableRows.eq(2).find('td').eq(1).text()).to.be('bbbb');
|
||||
});
|
||||
|
||||
it('should sort ascending on first invocation', function () {
|
||||
// sortColumn
|
||||
paginatedTable.sortColumn(0);
|
||||
|
@ -289,35 +310,6 @@ describe('paginated table', function () {
|
|||
|
||||
});
|
||||
|
||||
describe('custom sorting', function () {
|
||||
let data;
|
||||
let paginatedTable;
|
||||
let sortHandler;
|
||||
|
||||
beforeEach(function () {
|
||||
sortHandler = sinon.spy();
|
||||
data = makeData(3, 3);
|
||||
$scope.cols = data.columns;
|
||||
$scope.rows = data.rows;
|
||||
$scope.perPage = defaultPerPage;
|
||||
$scope.sortHandler = sortHandler;
|
||||
|
||||
$el = $compile('<paginated-table columns="cols" rows="rows" per-page="perPage"' +
|
||||
'sort-handler="sortHandler">')($scope);
|
||||
|
||||
$scope.$digest();
|
||||
paginatedTable = $el.isolateScope().paginatedTable;
|
||||
});
|
||||
|
||||
// TODO: This is failing randomly
|
||||
it('should allow custom sorting handler', function () {
|
||||
let columnIndex = 1;
|
||||
paginatedTable.sortColumn(columnIndex);
|
||||
$scope.$digest();
|
||||
expect(sortHandler.callCount).to.be(1);
|
||||
expect(sortHandler.getCall(0).args[0]).to.be(columnIndex);
|
||||
});
|
||||
});
|
||||
|
||||
describe('object rows', function () {
|
||||
let cols;
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
import _ from 'lodash';
|
||||
|
||||
import uiModules from 'ui/modules';
|
||||
import paginatedTableTemplate from 'ui/paginated_table/paginated_table.html';
|
||||
uiModules
|
||||
.get('kibana')
|
||||
.directive('paginatedTable', function ($filter) {
|
||||
let orderBy = $filter('orderBy');
|
||||
const orderBy = $filter('orderBy');
|
||||
|
||||
return {
|
||||
restrict: 'E',
|
||||
|
@ -15,28 +16,25 @@ uiModules
|
|||
columns: '=',
|
||||
perPage: '=?',
|
||||
sortHandler: '=?',
|
||||
sort: '=?',
|
||||
showSelector: '=?'
|
||||
},
|
||||
controllerAs: 'paginatedTable',
|
||||
controller: function ($scope) {
|
||||
let self = this;
|
||||
const self = this;
|
||||
self.sort = {
|
||||
columnIndex: null,
|
||||
direction: null
|
||||
};
|
||||
|
||||
self.sortColumn = function (colIndex) {
|
||||
let col = $scope.columns[colIndex];
|
||||
self.sortColumn = function (colIndex, sortDirection = 'asc') {
|
||||
const col = $scope.columns[colIndex];
|
||||
|
||||
if (!col) return;
|
||||
if (col.sortable === false) return;
|
||||
|
||||
let sortDirection;
|
||||
|
||||
if (self.sort.columnIndex !== colIndex) {
|
||||
sortDirection = 'asc';
|
||||
} else {
|
||||
let directions = {
|
||||
if (self.sort.columnIndex === colIndex) {
|
||||
const directions = {
|
||||
null: 'asc',
|
||||
'asc': 'desc',
|
||||
'desc': null
|
||||
|
@ -46,42 +44,49 @@ uiModules
|
|||
|
||||
self.sort.columnIndex = colIndex;
|
||||
self.sort.direction = sortDirection;
|
||||
self._setSortGetter(colIndex);
|
||||
};
|
||||
|
||||
self._setSortGetter = function (index) {
|
||||
if (_.isFunction($scope.sortHandler)) {
|
||||
// use custom sort handler
|
||||
self.sort.getter = $scope.sortHandler(index);
|
||||
} else {
|
||||
// use generic sort handler
|
||||
self.sort.getter = function (row) {
|
||||
let value = row[index];
|
||||
if (value && value.value != null) value = value.value;
|
||||
if (typeof value === 'boolean') value = value ? 0 : 1;
|
||||
return value;
|
||||
};
|
||||
if ($scope.sort) {
|
||||
_.assign($scope.sort, self.sort);
|
||||
}
|
||||
};
|
||||
|
||||
// update the sordedRows result
|
||||
$scope.$watchMulti([
|
||||
'rows',
|
||||
'columns',
|
||||
'[]paginatedTable.sort'
|
||||
], function resortRows() {
|
||||
function valueGetter(row) {
|
||||
let value = row[self.sort.columnIndex];
|
||||
if (value && value.value != null) value = value.value;
|
||||
if (typeof value === 'boolean') value = value ? 0 : 1;
|
||||
return value;
|
||||
}
|
||||
|
||||
// Set the sort state if it is set
|
||||
if ($scope.sort && $scope.sort.columnIndex !== null) {
|
||||
self.sortColumn($scope.sort.columnIndex, $scope.sort.direction);
|
||||
}
|
||||
function resortRows() {
|
||||
const newSort = $scope.sort;
|
||||
if (newSort && !_.isEqual(newSort, self.sort)) {
|
||||
self.sortColumn(newSort.columnIndex, newSort.direction);
|
||||
}
|
||||
|
||||
if (!$scope.rows || !$scope.columns) {
|
||||
$scope.sortedRows = false;
|
||||
return;
|
||||
}
|
||||
|
||||
let sort = self.sort;
|
||||
const sort = self.sort;
|
||||
if (sort.direction == null) {
|
||||
$scope.sortedRows = $scope.rows.slice(0);
|
||||
} else {
|
||||
$scope.sortedRows = orderBy($scope.rows, sort.getter, sort.direction === 'desc');
|
||||
$scope.sortedRows = orderBy($scope.rows, valueGetter, sort.direction === 'desc');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// update the sortedRows result
|
||||
$scope.$watchMulti([
|
||||
'rows',
|
||||
'columns',
|
||||
'[]sort',
|
||||
'[]paginatedTable.sort'
|
||||
], resortRows);
|
||||
}
|
||||
};
|
||||
});
|
||||
|
|
|
@ -4,10 +4,11 @@ import applyDiff from 'ui/utils/diff_object';
|
|||
import qs from 'ui/utils/query_string';
|
||||
import EventsProvider from 'ui/events';
|
||||
import Notifier from 'ui/notify/notifier';
|
||||
import KbnUrlProvider from 'ui/url';
|
||||
|
||||
|
||||
const notify = new Notifier();
|
||||
export default function StateProvider(Private, $rootScope, $location) {
|
||||
let Events = Private(EventsProvider);
|
||||
const Events = Private(EventsProvider);
|
||||
|
||||
_.class(State).inherits(Events);
|
||||
function State(urlParam, defaults) {
|
||||
|
@ -27,10 +28,14 @@ export default function StateProvider(Private, $rootScope, $location) {
|
|||
// beginning of full route update, new app will be initialized before
|
||||
// $routeChangeSuccess or $routeChangeError
|
||||
$rootScope.$on('$routeChangeStart', function () {
|
||||
if (!self._persistAcrossApps) {
|
||||
self.destroy();
|
||||
}
|
||||
}),
|
||||
|
||||
$rootScope.$on('$routeChangeSuccess', function () {
|
||||
if (self._persistAcrossApps) {
|
||||
self.fetch();
|
||||
} else {
|
||||
self.destroy();
|
||||
}
|
||||
})
|
||||
]);
|
||||
|
@ -44,7 +49,6 @@ export default function StateProvider(Private, $rootScope, $location) {
|
|||
try {
|
||||
return search[this._urlParam] ? rison.decode(search[this._urlParam]) : null;
|
||||
} catch (e) {
|
||||
let notify = new Notifier();
|
||||
notify.error('Unable to parse URL');
|
||||
search[this._urlParam] = rison.encode(this._defaults);
|
||||
$location.search(search).replace();
|
||||
|
|
|
@ -9,6 +9,7 @@ export default function TemplateRenderbotFactory(Private, $compile, $rootScope)
|
|||
|
||||
this.$scope = $rootScope.$new();
|
||||
this.$scope.vis = vis;
|
||||
this.$scope.uiState = uiState;
|
||||
|
||||
$el.html($compile(this.vis.type.template)(this.$scope));
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import moment from 'moment';
|
||||
import dateMath from 'ui/utils/date_math';
|
||||
import dateMath from '@elastic/datemath';
|
||||
export default function () {
|
||||
|
||||
let unitsDesc = dateMath.unitsDesc;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import _ from 'lodash';
|
||||
import moment from 'moment';
|
||||
import dateMath from 'ui/utils/date_math';
|
||||
import dateMath from '@elastic/datemath';
|
||||
import parseInterval from 'ui/utils/parse_interval';
|
||||
import TimeBucketsCalcAutoIntervalProvider from 'ui/time_buckets/calc_auto_interval';
|
||||
import TimeBucketsCalcEsIntervalProvider from 'ui/time_buckets/calc_es_interval';
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import _ from 'lodash';
|
||||
import angular from 'angular';
|
||||
import moment from 'moment';
|
||||
import dateMath from 'ui/utils/date_math';
|
||||
import dateMath from '@elastic/datemath';
|
||||
import 'ui/state_management/global_state';
|
||||
import 'ui/config';
|
||||
import EventsProvider from 'ui/events';
|
||||
|
@ -19,11 +19,9 @@ uiRoutes
|
|||
uiModules
|
||||
.get('kibana')
|
||||
.service('timefilter', function (Private, globalState, $rootScope, config) {
|
||||
|
||||
let Events = Private(EventsProvider);
|
||||
let diff = Private(UtilsDiffTimePickerValsProvider);
|
||||
|
||||
|
||||
function convertISO8601(stringTime) {
|
||||
let obj = moment(stringTime, 'YYYY-MM-DDTHH:mm:ss.SSSZ', true);
|
||||
return obj.isValid() ? obj : stringTime;
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import moment from 'moment';
|
||||
import UiModules from 'ui/modules';
|
||||
import chromeNavControlsRegistry from 'ui/registry/chrome_nav_controls';
|
||||
import { once, clone } from 'lodash';
|
||||
|
@ -6,7 +7,7 @@ import toggleHtml from './kbn_global_timepicker.html';
|
|||
|
||||
UiModules
|
||||
.get('kibana')
|
||||
.directive('kbnGlobalTimepicker', (timefilter, globalState, $rootScope) => {
|
||||
.directive('kbnGlobalTimepicker', (timefilter, globalState, $rootScope, config) => {
|
||||
const listenForUpdates = once($scope => {
|
||||
$scope.$listen(timefilter, 'update', (newVal, oldVal) => {
|
||||
globalState.time = clone(timefilter.time);
|
||||
|
@ -18,6 +19,12 @@ UiModules
|
|||
return {
|
||||
template: toggleHtml,
|
||||
link: ($scope, $el, attrs) => {
|
||||
config.$bind($scope, 'dateFormat:dow', 'dateFormat_dow');
|
||||
$scope.$watch('dateFormat_dow', function (day) {
|
||||
const dow = moment.weekdays().indexOf(day);
|
||||
moment.locale(moment.locale(), { week: { dow } });
|
||||
});
|
||||
|
||||
listenForUpdates($rootScope);
|
||||
|
||||
$rootScope.timefilter = timefilter;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import html from 'ui/timepicker/timepicker.html';
|
||||
import _ from 'lodash';
|
||||
import dateMath from 'ui/utils/date_math';
|
||||
import dateMath from '@elastic/datemath';
|
||||
import moment from 'moment';
|
||||
import Notifier from 'ui/notify/notifier';
|
||||
import 'ui/directives/input_datetime';
|
||||
|
@ -15,7 +15,6 @@ let notify = new Notifier({
|
|||
location: 'timepicker',
|
||||
});
|
||||
|
||||
|
||||
module.directive('kbnTimepicker', function (quickRanges, timeUnits, refreshIntervals) {
|
||||
return {
|
||||
restrict: 'E',
|
||||
|
@ -28,10 +27,6 @@ module.directive('kbnTimepicker', function (quickRanges, timeUnits, refreshInter
|
|||
},
|
||||
template: html,
|
||||
controller: function ($scope) {
|
||||
let init = function () {
|
||||
$scope.setMode($scope.mode);
|
||||
};
|
||||
|
||||
$scope.format = 'MMMM Do YYYY, HH:mm:ss.SSS';
|
||||
$scope.modes = ['quick', 'relative', 'absolute'];
|
||||
$scope.activeTab = $scope.activeTab || 'filter';
|
||||
|
@ -115,7 +110,7 @@ module.directive('kbnTimepicker', function (quickRanges, timeUnits, refreshInter
|
|||
$scope.mode = thisMode;
|
||||
};
|
||||
|
||||
$scope.setQuick = function (from, to, description) {
|
||||
$scope.setQuick = function (from, to) {
|
||||
$scope.from = from;
|
||||
$scope.to = to;
|
||||
};
|
||||
|
@ -154,7 +149,7 @@ module.directive('kbnTimepicker', function (quickRanges, timeUnits, refreshInter
|
|||
$scope.interval = interval;
|
||||
};
|
||||
|
||||
init();
|
||||
$scope.setMode($scope.mode);
|
||||
}
|
||||
};
|
||||
});
|
||||
|
|
|
@ -1,143 +0,0 @@
|
|||
import dateMath from 'ui/utils/date_math';
|
||||
import expect from 'expect.js';
|
||||
import moment from 'moment';
|
||||
import _ from 'lodash';
|
||||
import sinon from 'auto-release-sinon';
|
||||
|
||||
describe('dateMath', function () {
|
||||
// Test each of these intervals when testing relative time
|
||||
let spans = ['s', 'm', 'h', 'd', 'w', 'M', 'y'];
|
||||
let anchor = '2014-01-01T06:06:06.666Z';
|
||||
let unix = moment(anchor).valueOf();
|
||||
let format = 'YYYY-MM-DDTHH:mm:ss.SSSZ';
|
||||
let clock;
|
||||
|
||||
describe('errors', function () {
|
||||
it('should return undefined if passed something falsy', function () {
|
||||
expect(dateMath.parse()).to.be(undefined);
|
||||
});
|
||||
|
||||
it('should return undefined if I pass an operator besides [+-/]', function () {
|
||||
expect(dateMath.parse('now&1d')).to.be(undefined);
|
||||
});
|
||||
|
||||
it('should return undefined if I pass a unit besides' + spans.toString(), function () {
|
||||
expect(dateMath.parse('now+5f')).to.be(undefined);
|
||||
});
|
||||
|
||||
it('should return undefined if rounding unit is not 1', function () {
|
||||
expect(dateMath.parse('now/2y')).to.be(undefined);
|
||||
expect(dateMath.parse('now/0.5y')).to.be(undefined);
|
||||
});
|
||||
|
||||
it('should not go into an infinite loop when missing a unit', function () {
|
||||
expect(dateMath.parse('now-0')).to.be(undefined);
|
||||
expect(dateMath.parse('now-00')).to.be(undefined);
|
||||
expect(dateMath.parse('now-000')).to.be(undefined);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('objects and strings', function () {
|
||||
let mmnt;
|
||||
let date;
|
||||
let string;
|
||||
let now;
|
||||
|
||||
beforeEach(function () {
|
||||
clock = sinon.useFakeTimers(unix);
|
||||
now = moment();
|
||||
mmnt = moment(anchor);
|
||||
date = mmnt.toDate();
|
||||
string = mmnt.format(format);
|
||||
});
|
||||
|
||||
it('should return the same moment if passed a moment', function () {
|
||||
expect(dateMath.parse(mmnt)).to.eql(mmnt);
|
||||
});
|
||||
|
||||
it('should return a moment if passed a date', function () {
|
||||
expect(dateMath.parse(date).format(format)).to.eql(mmnt.format(format));
|
||||
});
|
||||
|
||||
it('should return a moment if passed an ISO8601 string', function () {
|
||||
expect(dateMath.parse(string).format(format)).to.eql(mmnt.format(format));
|
||||
});
|
||||
|
||||
it('should return the current time if passed now', function () {
|
||||
expect(dateMath.parse('now').format(format)).to.eql(now.format(format));
|
||||
});
|
||||
});
|
||||
|
||||
describe('subtraction', function () {
|
||||
let now;
|
||||
let anchored;
|
||||
|
||||
beforeEach(function () {
|
||||
clock = sinon.useFakeTimers(unix);
|
||||
now = moment();
|
||||
anchored = moment(anchor);
|
||||
});
|
||||
|
||||
_.each(spans, function (span) {
|
||||
let nowEx = 'now-5' + span;
|
||||
let thenEx = anchor + '||-5' + span;
|
||||
|
||||
it('should return 5' + span + ' ago', function () {
|
||||
expect(dateMath.parse(nowEx).format(format)).to.eql(now.subtract(5, span).format(format));
|
||||
});
|
||||
|
||||
it('should return 5' + span + ' before ' + anchor, function () {
|
||||
expect(dateMath.parse(thenEx).format(format)).to.eql(anchored.subtract(5, span).format(format));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('addition', function () {
|
||||
let now;
|
||||
let anchored;
|
||||
|
||||
beforeEach(function () {
|
||||
clock = sinon.useFakeTimers(unix);
|
||||
now = moment();
|
||||
anchored = moment(anchor);
|
||||
});
|
||||
|
||||
_.each(spans, function (span) {
|
||||
let nowEx = 'now+5' + span;
|
||||
let thenEx = anchor + '||+5' + span;
|
||||
|
||||
it('should return 5' + span + ' from now', function () {
|
||||
expect(dateMath.parse(nowEx).format()).to.eql(now.add(5, span).format());
|
||||
});
|
||||
|
||||
it('should return 5' + span + ' after ' + anchor, function () {
|
||||
expect(dateMath.parse(thenEx).format()).to.eql(anchored.add(5, span).format());
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('rounding', function () {
|
||||
let now;
|
||||
let anchored;
|
||||
|
||||
beforeEach(function () {
|
||||
clock = sinon.useFakeTimers(unix);
|
||||
now = moment();
|
||||
anchored = moment(anchor);
|
||||
});
|
||||
|
||||
_.each(spans, function (span) {
|
||||
it('should round now to the beginning of the ' + span, function () {
|
||||
expect(dateMath.parse('now/' + span).format(format)).to.eql(now.startOf(span).format(format));
|
||||
});
|
||||
|
||||
it('should round now to the end of the ' + span, function () {
|
||||
expect(dateMath.parse('now/' + span, true).format(format)).to.eql(now.endOf(span).format(format));
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
|
@ -53,9 +53,22 @@ describe('Scanner', function () {
|
|||
scroll = sinon.stub(scanner.client, 'scroll', (req, cb) => cb(null, mockScroll));
|
||||
});
|
||||
|
||||
it('should reject when an error occurs', function (done) {
|
||||
search.restore();
|
||||
search = sinon.stub(scanner.client, 'search', (req, cb) => cb(new Error('fail.')));
|
||||
return scanner.scanAndMap('')
|
||||
.then(function (response) {
|
||||
done(new Error('should reject'));
|
||||
})
|
||||
.catch(function (error) {
|
||||
expect(error.message).to.be('fail.');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should search and then scroll for results', function () {
|
||||
return scanner.scanAndMap('')
|
||||
.then(function (error, response) {
|
||||
.then(function (response) {
|
||||
expect(search.called).to.be(true);
|
||||
expect(scroll.called).to.be(true);
|
||||
});
|
||||
|
|
|
@ -1,108 +0,0 @@
|
|||
import _ from 'lodash';
|
||||
import moment from 'moment';
|
||||
|
||||
let units = ['y', 'M', 'w', 'd', 'h', 'm', 's', 'ms'];
|
||||
let unitsAsc = _.sortBy(units, function (unit) {
|
||||
return moment.duration(1, unit).valueOf();
|
||||
});
|
||||
let unitsDesc = unitsAsc.reverse();
|
||||
|
||||
/* This is a simplified version of elasticsearch's date parser */
|
||||
function parse(text, roundUp) {
|
||||
if (!text) return undefined;
|
||||
if (moment.isMoment(text)) return text;
|
||||
if (_.isDate(text)) return moment(text);
|
||||
|
||||
let time;
|
||||
let mathString = '';
|
||||
let index;
|
||||
let parseString;
|
||||
|
||||
if (text.substring(0, 3) === 'now') {
|
||||
time = moment();
|
||||
mathString = text.substring('now'.length);
|
||||
} else {
|
||||
index = text.indexOf('||');
|
||||
if (index === -1) {
|
||||
parseString = text;
|
||||
mathString = ''; // nothing else
|
||||
} else {
|
||||
parseString = text.substring(0, index);
|
||||
mathString = text.substring(index + 2);
|
||||
}
|
||||
// We're going to just require ISO8601 timestamps, k?
|
||||
time = moment(parseString);
|
||||
}
|
||||
|
||||
if (!mathString.length) {
|
||||
return time;
|
||||
}
|
||||
|
||||
return parseDateMath(mathString, time, roundUp);
|
||||
}
|
||||
|
||||
function parseDateMath(mathString, time, roundUp) {
|
||||
let dateTime = time;
|
||||
let i = 0;
|
||||
let len = mathString.length;
|
||||
|
||||
while (i < len) {
|
||||
let c = mathString.charAt(i++);
|
||||
let type;
|
||||
let num;
|
||||
let unit;
|
||||
|
||||
if (c === '/') {
|
||||
type = 0;
|
||||
} else if (c === '+') {
|
||||
type = 1;
|
||||
} else if (c === '-') {
|
||||
type = 2;
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (isNaN(mathString.charAt(i))) {
|
||||
num = 1;
|
||||
} else if (mathString.length === 2) {
|
||||
num = mathString.charAt(i);
|
||||
} else {
|
||||
let numFrom = i;
|
||||
while (!isNaN(mathString.charAt(i))) {
|
||||
i++;
|
||||
if (i > 10) return undefined;
|
||||
}
|
||||
num = parseInt(mathString.substring(numFrom, i), 10);
|
||||
}
|
||||
|
||||
if (type === 0) {
|
||||
// rounding is only allowed on whole, single, units (eg M or 1M, not 0.5M or 2M)
|
||||
if (num !== 1) {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
unit = mathString.charAt(i++);
|
||||
|
||||
if (!_.contains(units, unit)) {
|
||||
return undefined;
|
||||
} else {
|
||||
if (type === 0) {
|
||||
if (roundUp) dateTime.endOf(unit);
|
||||
else dateTime.startOf(unit);
|
||||
} else if (type === 1) {
|
||||
dateTime.add(num, unit);
|
||||
} else if (type === 2) {
|
||||
dateTime.subtract(num, unit);
|
||||
}
|
||||
}
|
||||
}
|
||||
return dateTime;
|
||||
}
|
||||
|
||||
export default {
|
||||
parse: parse,
|
||||
|
||||
units: Object.freeze(units),
|
||||
unitsAsc: Object.freeze(unitsAsc),
|
||||
unitsDesc: Object.freeze(unitsDesc)
|
||||
};
|
|
@ -1,6 +1,6 @@
|
|||
import _ from 'lodash';
|
||||
import moment from 'moment';
|
||||
import dateMath from 'ui/utils/date_math';
|
||||
import dateMath from '@elastic/datemath';
|
||||
|
||||
// Assume interval is in the form (value)(unit), such as "1h"
|
||||
let INTERVAL_STRING_RE = new RegExp('^([0-9\\.]*)\\s*(' + dateMath.units.join('|') + ')$');
|
||||
|
|
|
@ -38,6 +38,10 @@ Scanner.prototype.scanAndMap = function (searchString, options, mapFn) {
|
|||
|
||||
return new Promise((resolve, reject) => {
|
||||
const getMoreUntilDone = (error, response) => {
|
||||
if (error) {
|
||||
reject(error);
|
||||
return;
|
||||
}
|
||||
const scanAllResults = opts.docCount === Infinity;
|
||||
allResults.total = scanAllResults ? response.hits.total : Math.min(response.hits.total, opts.docCount);
|
||||
scrollId = response._scroll_id || scrollId;
|
||||
|
|
|
@ -232,17 +232,25 @@ export default function MapFactory(Private) {
|
|||
// TODO: Different drawTypes need differ info. Need a switch on the object creation
|
||||
let bounds = e.layer.getBounds();
|
||||
|
||||
let SElng = bounds.getSouthEast().lng;
|
||||
if (SElng > 180) {
|
||||
SElng -= 360;
|
||||
}
|
||||
let NWlng = bounds.getNorthWest().lng;
|
||||
if (NWlng < -180) {
|
||||
NWlng += 360;
|
||||
}
|
||||
self._events.emit(drawType, {
|
||||
e: e,
|
||||
chart: self._chartData,
|
||||
bounds: {
|
||||
top_left: {
|
||||
lat: bounds.getNorthWest().lat,
|
||||
lon: bounds.getNorthWest().lng
|
||||
lon: NWlng
|
||||
},
|
||||
bottom_right: {
|
||||
lat: bounds.getSouthEast().lat,
|
||||
lon: bounds.getSouthEast().lng
|
||||
lon: SElng
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import d3 from 'd3';
|
||||
import dateMath from 'ui/utils/date_math';
|
||||
import dateMath from '@elastic/datemath';
|
||||
export default function TimeMarkerFactory() {
|
||||
|
||||
function TimeMarker(times, xScale, height) {
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue