mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
Merge branch 'master' into test-coverage
This commit is contained in:
commit
3018f82cf2
45 changed files with 333 additions and 293 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -10,8 +10,9 @@ target
|
|||
.idea
|
||||
*.iml
|
||||
*.log
|
||||
esvm
|
||||
/esvm
|
||||
.htpasswd
|
||||
installedPlugins
|
||||
disabledPlugins
|
||||
webpackstats.json
|
||||
config/kibana.dev.yml
|
||||
|
|
|
@ -59,15 +59,35 @@ Here are some hints for getting eslint setup in your favorite editor:
|
|||
|
||||
To ensure that your changes will not break other functionality, please run the test suite and build process before submitting your pull request.
|
||||
|
||||
Before running the tests you will need to install the projects dependencies as described below.
|
||||
Before running the tests you will need to install the projects dependencies as described above.
|
||||
|
||||
Once that is complete just run:
|
||||
|
||||
```sh
|
||||
./node_modules/.bin/grunt test build
|
||||
npm run test && npm run build
|
||||
```
|
||||
|
||||
Distributable, built packages can be found in `target/` after the build completes.
|
||||
Distributable packages can be found in `target/` after the build completes.
|
||||
|
||||
#### Debugging test failures
|
||||
|
||||
The standard `npm run test` task runs several sub tasks and can take several minutes to complete, making debugging failures pretty painful. In order to ease the pain specialized tasks provide alternate methods for running the tests.
|
||||
|
||||
<dl>
|
||||
<dt><code>npm run test:quick</code></dt>
|
||||
<dd>Runs both server and browser tests, but skips linting</dd>
|
||||
|
||||
<dt><code>npm run test:server</code> or <code>npm run test:browser</code></dt>
|
||||
<dd>Runs the tests for just the server or browser</dd>
|
||||
|
||||
<dt><code>npm run test:dev</code></dt>
|
||||
<dd>
|
||||
Initializes an environment for debugging the browser tests. Includes an dedicated instance of the kibana server for building the test bundle, and a karma server. When running this task the build is optimized for the first time and then a karma-owned instance of the browser is opened. Click the "debug" button to open a new tab that executes the unit tests.
|
||||
<br>
|
||||
<img src="http://i.imgur.com/DwHxgfq.png">
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
|
||||
### Submit a pull request
|
||||
|
||||
|
|
|
@ -16,6 +16,10 @@ module.exports = function (grunt) {
|
|||
configFile: __dirname + '/src/config/kibana.yml',
|
||||
|
||||
karmaBrowser: (function () {
|
||||
if (grunt.option('browser')) {
|
||||
return grunt.option('browser');
|
||||
}
|
||||
|
||||
switch (require('os').platform()) {
|
||||
case 'win32':
|
||||
return 'IE';
|
||||
|
|
|
@ -81,7 +81,7 @@ If you are using a self-signed certificate for Elasticsearch, set the `ca` prope
|
|||
|
||||
[source,text]
|
||||
----
|
||||
# If you need to provide a CA certificate for your Elasticsarech instance, put
|
||||
# If you need to provide a CA certificate for your Elasticsearch instance, put
|
||||
# the path of the pem file here.
|
||||
ca: /path/to/your/ca/cacert.pem
|
||||
----
|
||||
|
|
|
@ -1,72 +0,0 @@
|
|||
// Karma configuration
|
||||
// Generated on Mon Jul 27 2015 04:03:51 GMT-0700 (MST)
|
||||
|
||||
module.exports = function (config) {
|
||||
config.set({
|
||||
|
||||
// base path that will be used to resolve all patterns (eg. files, exclude)
|
||||
basePath: '',
|
||||
|
||||
captureTimeout: 30000,
|
||||
browserNoActivityTimeout: 120000,
|
||||
|
||||
// frameworks to use
|
||||
// available frameworks: https://npmjs.org/browse/keyword/karma-adapter
|
||||
frameworks: ['mocha'],
|
||||
|
||||
// list of files / patterns to load in the browser
|
||||
files: [
|
||||
'http://localhost:5601/bundles/commons.bundle.js',
|
||||
'http://localhost:5601/bundles/tests.bundle.js',
|
||||
'http://localhost:5601/bundles/commons.style.css',
|
||||
'http://localhost:5601/bundles/tests.style.css'
|
||||
],
|
||||
|
||||
proxies: {
|
||||
'/tests/': 'http://localhost:5601/tests/',
|
||||
'/bundles/': 'http://localhost:5601/bundles/'
|
||||
},
|
||||
|
||||
// test results reporter to use
|
||||
// possible values: 'dots', 'progress'
|
||||
// available reporters: https://npmjs.org/browse/keyword/karma-reporter
|
||||
reporters: ['progress', 'growl'],
|
||||
|
||||
|
||||
// web server port
|
||||
port: 9876,
|
||||
|
||||
|
||||
// enable / disable colors in the output (reporters and logs)
|
||||
colors: true,
|
||||
|
||||
|
||||
// level of logging
|
||||
// possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
|
||||
logLevel: config.LOG_INFO,
|
||||
|
||||
|
||||
// enable / disable watching file and executing tests whenever any file changes
|
||||
autoWatch: false,
|
||||
|
||||
|
||||
// start these browsers
|
||||
// available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
|
||||
browsers: [
|
||||
require('os').platform() === 'win32' ? 'IE' : 'Chrome'
|
||||
],
|
||||
|
||||
|
||||
// Continuous Integration mode
|
||||
// if true, Karma captures browsers, runs the tests and exits
|
||||
singleRun: false,
|
||||
|
||||
client: {
|
||||
mocha: {
|
||||
reporter: 'html', // change Karma's debug.html to the mocha web reporter
|
||||
timeout: 10000,
|
||||
slow: 5000
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
11
package.json
11
package.json
|
@ -34,7 +34,12 @@
|
|||
],
|
||||
"scripts": {
|
||||
"test": "grunt test",
|
||||
"start": "node ./src/server/cli/index.js --dev",
|
||||
"test:dev": "grunt test:dev",
|
||||
"test:quick": "grunt test:quick",
|
||||
"test:browser": "grunt test:browser",
|
||||
"test:server": "grunt test:server",
|
||||
"build": "grunt build",
|
||||
"start": "./bin/kibana --dev",
|
||||
"precommit": "grunt lintStagedFiles",
|
||||
"karma": "karma start"
|
||||
},
|
||||
|
@ -92,6 +97,7 @@
|
|||
"jquery": "^2.1.4",
|
||||
"js-yaml": "^3.2.5",
|
||||
"json-stringify-safe": "^5.0.1",
|
||||
"jstimezonedetect": "^1.0.5",
|
||||
"leaflet": "^0.7.3",
|
||||
"less": "^2.5.1",
|
||||
"less-loader": "^2.2.0",
|
||||
|
@ -131,7 +137,7 @@
|
|||
"grunt-cli": "0.1.13",
|
||||
"grunt-contrib-clean": "^0.6.0",
|
||||
"grunt-contrib-copy": "^0.8.0",
|
||||
"grunt-esvm": "^1.1.3",
|
||||
"grunt-esvm": "^1.1.5",
|
||||
"grunt-karma": "^0.12.0",
|
||||
"grunt-run": "spalger/grunt-run#master",
|
||||
"grunt-s3": "^0.2.0-alpha.3",
|
||||
|
@ -145,6 +151,7 @@
|
|||
"karma-growl-reporter": "^0.1.1",
|
||||
"karma-ie-launcher": "^0.2.0",
|
||||
"karma-mocha": "^0.2.0",
|
||||
"karma-safari-launcher": "^0.1.1",
|
||||
"libesvm": "^1.0.1",
|
||||
"license-checker": "^3.1.0",
|
||||
"load-grunt-config": "^0.7.0",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
let cluster = require('cluster');
|
||||
let { join } = require('path');
|
||||
let { startsWith, debounce, compact, invoke, bindAll, once } = require('lodash');
|
||||
let { debounce, compact, invoke, bindAll, once } = require('lodash');
|
||||
|
||||
let Log = require('../Log');
|
||||
let Worker = require('./Worker');
|
||||
|
@ -64,7 +64,7 @@ module.exports = class ClusterManager {
|
|||
'installedPlugins'
|
||||
], {
|
||||
cwd: fromRoot('.'),
|
||||
ignored: /[\\\/](node_modules|bower_components|public)[\\\/]/,
|
||||
ignored: /[\\\/](\..*|node_modules|bower_components|public|__tests__)[\\\/]/
|
||||
});
|
||||
|
||||
this.watcher.on('add', this.onWatcherAdd);
|
||||
|
@ -81,25 +81,32 @@ module.exports = class ClusterManager {
|
|||
}
|
||||
|
||||
setupManualRestart() {
|
||||
let input = '';
|
||||
let clear = () => input = '';
|
||||
let clearSoon = debounce(clear, 1250);
|
||||
let readline = require('readline');
|
||||
let rl = readline.createInterface(process.stdin, process.stdout);
|
||||
|
||||
process.stdin.on('data', chunk => {
|
||||
input += chunk.toString('utf8');
|
||||
let nls = 0;
|
||||
let clear = () => nls = 0;
|
||||
let clearSoon = debounce(clear, 2000);
|
||||
|
||||
if (input === '\n') {
|
||||
// wait for final \n
|
||||
rl.setPrompt('');
|
||||
rl.prompt();
|
||||
|
||||
rl.on('line', line => {
|
||||
nls = line.trim() ? 0 : nls + 1;
|
||||
if (nls >= 2) {
|
||||
clearSoon.cancel();
|
||||
clear();
|
||||
this.server.start();
|
||||
} else {
|
||||
clearSoon();
|
||||
}
|
||||
else if (startsWith(input, '\n\n')) {
|
||||
clearSoon.cancel();
|
||||
this.server.start();
|
||||
clear();
|
||||
}
|
||||
else {
|
||||
clear();
|
||||
}
|
||||
|
||||
rl.prompt();
|
||||
});
|
||||
|
||||
rl.on('SIGINT', () => {
|
||||
rl.pause();
|
||||
process.kill(process.pid, 'SIGINT');
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
var _ = require('lodash');
|
||||
var zlib = require('zlib');
|
||||
var Promise = require('bluebird');
|
||||
var url = require('url');
|
||||
var fs = require('fs');
|
||||
var request = require('request');
|
||||
var tar = require('tar');
|
||||
var progressReporter = require('./progressReporter');
|
||||
|
@ -17,7 +19,7 @@ module.exports = function (settings, logger) {
|
|||
throw new Error('Not a valid url.');
|
||||
}
|
||||
|
||||
logger.log('attempting to download ' + sourceUrl);
|
||||
logger.log('Attempting to extract from ' + sourceUrl);
|
||||
|
||||
return Promise.try(function () {
|
||||
return downloadSingle(sourceUrl, settings.workingPath, settings.timeout, logger)
|
||||
|
@ -26,7 +28,7 @@ module.exports = function (settings, logger) {
|
|||
return tryNext();
|
||||
}
|
||||
if (err.message === 'EEXTRACT') {
|
||||
throw (new Error('Error extracting the plugin archive'));
|
||||
throw (new Error('Error extracting the plugin archive... is this a valid tar.gz file?'));
|
||||
}
|
||||
throw (err);
|
||||
});
|
||||
|
@ -54,10 +56,10 @@ module.exports = function (settings, logger) {
|
|||
}
|
||||
|
||||
return wrappedRequest(requestOptions)
|
||||
.then(function (req) {
|
||||
var reporter = progressReporter(logger, req);
|
||||
.then(function (fileStream) {
|
||||
var reporter = progressReporter(logger, fileStream);
|
||||
|
||||
req
|
||||
fileStream
|
||||
.on('response', reporter.handleResponse)
|
||||
.on('data', reporter.handleData)
|
||||
.on('error', _.partial(reporter.handleError, 'ENOTFOUND'))
|
||||
|
@ -73,7 +75,12 @@ module.exports = function (settings, logger) {
|
|||
|
||||
function wrappedRequest(requestOptions) {
|
||||
return Promise.try(function () {
|
||||
return request.get(requestOptions);
|
||||
let urlInfo = url.parse(requestOptions.url);
|
||||
if (/^file/.test(urlInfo.protocol)) {
|
||||
return fs.createReadStream(urlInfo.path);
|
||||
} else {
|
||||
return request.get(requestOptions);
|
||||
}
|
||||
})
|
||||
.catch(function (err) {
|
||||
if (err.message.match(/invalid uri/i)) {
|
||||
|
|
|
@ -7,7 +7,7 @@ module.exports = {
|
|||
};
|
||||
|
||||
function install(settings, logger) {
|
||||
logger.log(`installing ${settings.package}`);
|
||||
logger.log(`Installing ${settings.package}`);
|
||||
|
||||
try {
|
||||
fs.statSync(settings.pluginPath);
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
var Promise = require('bluebird');
|
||||
|
||||
/*
|
||||
Responsible for reporting the progress of the file request stream
|
||||
Responsible for reporting the progress of the file stream
|
||||
*/
|
||||
module.exports = function (logger, request) {
|
||||
module.exports = function (logger, stream) {
|
||||
var oldDotCount = 0;
|
||||
var runningTotal = 0;
|
||||
var totalSize = 0;
|
||||
|
@ -22,7 +22,7 @@ module.exports = function (logger, request) {
|
|||
|
||||
if (err) logger.error(err);
|
||||
hasError = true;
|
||||
request.abort();
|
||||
if (stream.abort) stream.abort();
|
||||
_reject(new Error(errorMessage));
|
||||
}
|
||||
|
||||
|
@ -56,7 +56,7 @@ module.exports = function (logger, request) {
|
|||
function handleEnd() {
|
||||
if (hasError) return;
|
||||
|
||||
logger.log('Download Complete');
|
||||
logger.log('Extraction complete');
|
||||
_resolve();
|
||||
}
|
||||
|
||||
|
|
|
@ -86,7 +86,11 @@ module.exports = function (program) {
|
|||
let set = _.partial(_.set, settings);
|
||||
let get = _.partial(_.get, settings);
|
||||
|
||||
if (opts.dev) set('env', 'development');
|
||||
if (opts.dev) {
|
||||
set('env', 'development');
|
||||
set('optimize.lazy', true);
|
||||
}
|
||||
|
||||
if (opts.elasticsearch) set('elasticsearch.url', opts.elasticsearch);
|
||||
if (opts.port) set('server.port', opts.port);
|
||||
if (opts.host) set('server.host', opts.host);
|
||||
|
|
|
@ -1,20 +0,0 @@
|
|||
/**
|
||||
* Optimized application entry file
|
||||
*
|
||||
* This is programatically created and updated, do not modify
|
||||
*
|
||||
* built using: <%= optimizerTagline %>
|
||||
* includes code from:
|
||||
<%
|
||||
entry.deps.sort().forEach(function (plugin) {
|
||||
print(` * - ${plugin}\n`);
|
||||
})
|
||||
%> *
|
||||
*/
|
||||
|
||||
require('ui/testHarness');
|
||||
<%
|
||||
entry.modules.slice(0).reverse().forEach(function (id) {
|
||||
print(`require('${id.replace(/\\/g, '\\\\')}');\n`);
|
||||
});
|
||||
%>require('ui/testHarness').bootstrap();
|
|
@ -23,7 +23,8 @@ module.exports = function (kibana) {
|
|||
cert: Joi.string(),
|
||||
key: Joi.string()
|
||||
}).default(),
|
||||
minimumVerison: Joi.string().default('1.4.4')
|
||||
apiVersion: Joi.string().default('master'),
|
||||
minimumVerison: Joi.string().default('2.0.0')
|
||||
}).default();
|
||||
},
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@ describe('plugins/elasticsearch', function () {
|
|||
var get = sinon.stub().withArgs('elasticserach.minimumVerison').returns('1.4.3');
|
||||
var config = function () { return { get: get }; };
|
||||
server = {
|
||||
log: _.noop,
|
||||
config: config,
|
||||
plugins: {
|
||||
elasticsearch: {
|
||||
|
|
|
@ -4,6 +4,8 @@ var versionMath = require('./version_math');
|
|||
var SetupError = require('./setup_error');
|
||||
|
||||
module.exports = function (server) {
|
||||
server.log(['plugin', 'debug'], 'Checking Elasticsearch version');
|
||||
|
||||
var client = server.plugins.elasticsearch.client;
|
||||
var minimumElasticsearchVersion = server.config().get('elasticsearch.minimumVerison');
|
||||
|
||||
|
@ -31,7 +33,6 @@ module.exports = function (server) {
|
|||
`${minimumElasticsearchVersion} or higher on all nodes. I found ` +
|
||||
`the following incompatible nodes in your cluster: ${badNodeNames.join(',')}`;
|
||||
|
||||
server.plugins.elasticsearch.status.red(message);
|
||||
throw new SetupError(server, message);
|
||||
});
|
||||
};
|
||||
|
|
|
@ -13,6 +13,7 @@ module.exports = function (server) {
|
|||
var clientCrt = config.get('elasticsearch.ssl.cert');
|
||||
var clientKey = config.get('elasticsearch.ssl.key');
|
||||
var ca = config.get('elasticsearch.ssl.ca');
|
||||
var apiVersion = config.get('elasticsearch.apiVersion');
|
||||
|
||||
if (username && password) {
|
||||
uri.auth = util.format('%s:%s', username, password);
|
||||
|
@ -30,7 +31,7 @@ module.exports = function (server) {
|
|||
var client = new elasticsearch.Client({
|
||||
host: url.format(uri),
|
||||
ssl: ssl,
|
||||
apiVersion: '1.4',
|
||||
apiVersion: apiVersion,
|
||||
log: function () {
|
||||
this.error = function (err) {
|
||||
server.log(['error', 'elasticsearch'], err);
|
||||
|
|
|
@ -15,7 +15,6 @@ module.exports = function (plugin, server) {
|
|||
|
||||
plugin.status.yellow('Waiting for Elasticsearch');
|
||||
|
||||
|
||||
function waitForPong() {
|
||||
return client.ping({ requestTimeout: 1500 }).catch(function (err) {
|
||||
if (!(err instanceof NoConnections)) throw err;
|
||||
|
@ -54,13 +53,12 @@ module.exports = function (plugin, server) {
|
|||
|
||||
function check() {
|
||||
return waitForPong()
|
||||
.then(_.partial(checkEsVersion, server, plugin))
|
||||
.then(_.partial(checkEsVersion, server))
|
||||
.then(waitForShards)
|
||||
.then(_.partial(migrateConfig, server))
|
||||
.catch(_.bindKey(server, 'log', 'error'));
|
||||
.catch(err => plugin.status.red(err));
|
||||
}
|
||||
|
||||
|
||||
var timeoutId = null;
|
||||
|
||||
function scheduleCheck(ms) {
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
<i aria-hidden="true" class="fa fa-chain-broken"></i> Unlinked!
|
||||
</div>
|
||||
|
||||
<form ng-if="vis.type.requiresSearch && $state.linked" class="inline-form" name="queryInput">
|
||||
<form ng-if="vis.type.requiresSearch && $state.linked" class="inline-form fill" name="queryInput">
|
||||
<div class="typeahead">
|
||||
<div class="input-group">
|
||||
<input
|
||||
|
@ -39,7 +39,7 @@
|
|||
<form
|
||||
ng-if="vis.type.requiresSearch && !$state.linked"
|
||||
ng-submit="fetch()"
|
||||
class="inline-form"
|
||||
class="inline-form fill"
|
||||
name="queryInput">
|
||||
<div class="typeahead" kbn-typeahead="visualize">
|
||||
<div class="input-group"
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
module.exports = (kibana) => {
|
||||
if (!kibana.config.get('optimize.tests')) return;
|
||||
|
||||
let { union } = require('lodash');
|
||||
|
||||
let utils = require('requirefrom')('src/utils');
|
||||
|
|
|
@ -79,20 +79,12 @@ module.exports = Joi.object({
|
|||
|
||||
optimize: Joi.object({
|
||||
enabled: Joi.boolean().default(true),
|
||||
bundleFilter: Joi.string().when('tests', {
|
||||
is: true,
|
||||
then: Joi.default('tests'),
|
||||
otherwise: Joi.default('*')
|
||||
}),
|
||||
bundleFilter: Joi.string().default('!tests'),
|
||||
bundleDir: Joi.string().default(fromRoot('optimize/bundles')),
|
||||
viewCaching: Joi.boolean().default(Joi.ref('$prod')),
|
||||
lazy: Joi.boolean().when('$dev', {
|
||||
is: true,
|
||||
then: Joi.default(true),
|
||||
otherwise: Joi.default(false)
|
||||
}),
|
||||
lazy: Joi.boolean().default(false),
|
||||
lazyPort: Joi.number().default(5602),
|
||||
lazyHost: Joi.string().hostname().default('0.0.0.0'),
|
||||
lazyHost: Joi.string().hostname().default('localhost'),
|
||||
lazyPrebuild: Joi.boolean().default(false),
|
||||
lazyProxyTimeout: Joi.number().default(5 * 60000),
|
||||
unsafeCache: Joi
|
||||
|
@ -109,8 +101,7 @@ module.exports = Joi.object({
|
|||
Joi.boolean()
|
||||
)
|
||||
.default(Joi.ref('$dev')),
|
||||
profile: Joi.boolean().default(false),
|
||||
tests: Joi.boolean().default(false),
|
||||
profile: Joi.boolean().default(false)
|
||||
}).default()
|
||||
|
||||
}).default();
|
||||
|
|
|
@ -13,7 +13,10 @@ class Status extends EventEmitter {
|
|||
|
||||
this.on('change', function (previous, previousMsg) {
|
||||
this.since = new Date();
|
||||
server.log(['status', name, 'info'], {
|
||||
var tags = ['status', name];
|
||||
tags.push(this.state === 'red' ? 'error' : 'info');
|
||||
|
||||
server.log(tags, {
|
||||
tmpl: 'Status changed from <%= prevState %> to <%= state %><% message && print(` - ${message}`) %>',
|
||||
name: name,
|
||||
state: this.state,
|
||||
|
@ -42,8 +45,14 @@ states.all.forEach(function (state) {
|
|||
let previous = this.state;
|
||||
let previousMsg = this.message;
|
||||
|
||||
this.state = state.id;
|
||||
this.error = null;
|
||||
this.message = message || state.title;
|
||||
this.state = state.id;
|
||||
|
||||
if (message instanceof Error) {
|
||||
this.error = message;
|
||||
this.message = message.message;
|
||||
}
|
||||
|
||||
if (previous === this.state && previousMsg === this.message) {
|
||||
// noop
|
||||
|
|
25
src/ui/public/agg_types/buckets/RangeKey.js
Normal file
25
src/ui/public/agg_types/buckets/RangeKey.js
Normal file
|
@ -0,0 +1,25 @@
|
|||
module.exports = function () {
|
||||
|
||||
const id = Symbol('id');
|
||||
|
||||
class RangeKey {
|
||||
constructor(bucket) {
|
||||
this.gte = bucket.from == null ? -Infinity : bucket.from;
|
||||
this.lt = bucket.to == null ? +Infinity : bucket.to;
|
||||
|
||||
this[id] = RangeKey.idBucket(bucket);
|
||||
}
|
||||
|
||||
|
||||
static idBucket(bucket) {
|
||||
return `from:${bucket.from},to:${bucket.to}`;
|
||||
}
|
||||
|
||||
toString() {
|
||||
return this[id];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return RangeKey;
|
||||
};
|
|
@ -2,7 +2,12 @@ define(function (require) {
|
|||
var buildRangeFilter = require('ui/filter_manager/lib/range');
|
||||
return function createRangeFilterProvider(Private) {
|
||||
return function (aggConfig, key) {
|
||||
return buildRangeFilter(aggConfig.params.field, key, aggConfig.vis.indexPattern);
|
||||
return buildRangeFilter(
|
||||
aggConfig.params.field,
|
||||
key,
|
||||
aggConfig.vis.indexPattern,
|
||||
aggConfig.fieldFormatter()(key)
|
||||
);
|
||||
};
|
||||
};
|
||||
});
|
||||
|
|
|
@ -2,11 +2,12 @@ define(function (require) {
|
|||
return function DateHistogramAggType(timefilter, config, Private) {
|
||||
var _ = require('lodash');
|
||||
var moment = require('moment');
|
||||
var tzDetect = require('jstimezonedetect').jstz;
|
||||
var BucketAggType = Private(require('ui/agg_types/buckets/_bucket_agg_type'));
|
||||
var TimeBuckets = Private(require('ui/time_buckets'));
|
||||
var createFilter = Private(require('ui/agg_types/buckets/create_filter/date_histogram'));
|
||||
var intervalOptions = Private(require('ui/agg_types/buckets/_interval_options'));
|
||||
|
||||
var timeZone = tzDetect.determine().name();
|
||||
var tzOffset = moment().format('Z');
|
||||
|
||||
function getInterval(agg) {
|
||||
|
@ -93,7 +94,7 @@ define(function (require) {
|
|||
var interval = agg.buckets.getInterval();
|
||||
output.bucketInterval = interval;
|
||||
output.params.interval = interval.expression;
|
||||
output.params.time_zone = tzOffset;
|
||||
output.params.time_zone = timeZone || tzOffset;
|
||||
|
||||
var scaleMetrics = interval.scaled && interval.scale < 1;
|
||||
if (scaleMetrics) {
|
||||
|
|
|
@ -4,7 +4,10 @@ define(function (require) {
|
|||
var BucketAggType = Private(require('ui/agg_types/buckets/_bucket_agg_type'));
|
||||
var createFilter = Private(require('ui/agg_types/buckets/create_filter/range'));
|
||||
var FieldFormat = Private(require('ui/index_patterns/_field_format/FieldFormat'));
|
||||
var RangeKey = Private(require('./RangeKey'));
|
||||
|
||||
var keyCaches = new WeakMap();
|
||||
var formats = new WeakMap();
|
||||
|
||||
return new BucketAggType({
|
||||
name: 'range',
|
||||
|
@ -14,22 +17,36 @@ define(function (require) {
|
|||
return aggConfig.params.field.displayName + ' ranges';
|
||||
},
|
||||
getKey: function (bucket, key, agg) {
|
||||
let range = { gte: bucket.from, lt: bucket.to };
|
||||
var keys = keyCaches.get(agg);
|
||||
|
||||
if (range.gte == null) range.gte = -Infinity;
|
||||
if (range.lt == null) range.lt = +Infinity;
|
||||
if (!keys) {
|
||||
keys = new Map();
|
||||
keyCaches.set(agg, keys);
|
||||
}
|
||||
|
||||
return range;
|
||||
var id = RangeKey.idBucket(bucket);
|
||||
|
||||
var key = keys.get(id);
|
||||
if (!key) {
|
||||
key = new RangeKey(bucket);
|
||||
keys.set(id, key);
|
||||
}
|
||||
|
||||
return key;
|
||||
},
|
||||
getFormat: function (agg) {
|
||||
if (agg.$$rangeAggTypeFormat) return agg.$$rangeAggTypeFormat;
|
||||
let format = formats.get(agg);
|
||||
if (format) return format;
|
||||
|
||||
var RangeFormat = FieldFormat.from(function (range) {
|
||||
var format = agg.fieldOwnFormatter();
|
||||
let RangeFormat = FieldFormat.from(function (range) {
|
||||
let format = agg.fieldOwnFormatter();
|
||||
return `${format(range.gte)} to ${format(range.lt)}`;
|
||||
});
|
||||
|
||||
return (this.$$rangeAggTypeFormat = new RangeFormat());
|
||||
format = new RangeFormat();
|
||||
|
||||
formats.set(agg, format);
|
||||
return format;
|
||||
},
|
||||
params: [
|
||||
{
|
||||
|
|
4
src/ui/public/chrome/api/angular.js
vendored
4
src/ui/public/chrome/api/angular.js
vendored
|
@ -22,7 +22,7 @@ module.exports = function (chrome, internals) {
|
|||
}()))
|
||||
.directive('kbnChrome', function ($rootScope) {
|
||||
return {
|
||||
compile: function ($el) {
|
||||
template: function ($el) {
|
||||
var $content = $(require('ui/chrome/chrome.html'));
|
||||
var $app = $content.find('.application');
|
||||
|
||||
|
@ -35,7 +35,7 @@ module.exports = function (chrome, internals) {
|
|||
$app.html(internals.rootTemplate);
|
||||
}
|
||||
|
||||
$el.html($content);
|
||||
return $content;
|
||||
},
|
||||
controllerAs: 'chrome',
|
||||
controller: function ($scope, $rootScope, $location, $http) {
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
require('babel/polyfill');
|
||||
|
||||
var _ = require('lodash');
|
||||
var $ = require('jquery');
|
||||
var angular = require('angular');
|
||||
|
|
|
@ -1,14 +1,16 @@
|
|||
<th width="1%"></th>
|
||||
<th ng-if="indexPattern.timeFieldName">
|
||||
<span>Time <i ng-class="headerClass(indexPattern.timeFieldName)" ng-click="sort(indexPattern.timeFieldName)" tooltip="Sort by time"></i></span>
|
||||
</th>
|
||||
<th ng-repeat="name in columns">
|
||||
<span class="table-header-name">
|
||||
{{name | shortDots}} <i ng-class="headerClass(name)" ng-click="sort(name)" tooltip="{{tooltip(name)}}" tooltip-append-to-body="1"></i>
|
||||
</span>
|
||||
<span class="table-header-move">
|
||||
<i ng-click="toggleColumn(name)" ng-show="canRemove(name)" class="fa fa-remove" tooltip="Remove column" tooltip-append-to-body="1"></i>
|
||||
<i ng-click="moveLeft(name)" class="fa fa-angle-double-left" ng-show="!$first" tooltip="Move column to the left" tooltip-append-to-body="1"></i>
|
||||
<i ng-click="moveRight(name)" class="fa fa-angle-double-right" ng-show="!$last" tooltip="Move column to the right" tooltip-append-to-body="1"></i>
|
||||
</span>
|
||||
</th>
|
||||
<tr>
|
||||
<th width="1%"></th>
|
||||
<th ng-if="indexPattern.timeFieldName">
|
||||
<span>Time <i ng-class="headerClass(indexPattern.timeFieldName)" ng-click="sort(indexPattern.timeFieldName)" tooltip="Sort by time"></i></span>
|
||||
</th>
|
||||
<th ng-repeat="name in columns">
|
||||
<span class="table-header-name">
|
||||
{{name | shortDots}} <i ng-class="headerClass(name)" ng-click="sort(name)" tooltip="{{tooltip(name)}}" tooltip-append-to-body="1"></i>
|
||||
</span>
|
||||
<span class="table-header-move">
|
||||
<i ng-click="toggleColumn(name)" ng-show="canRemove(name)" class="fa fa-remove" tooltip="Remove column" tooltip-append-to-body="1"></i>
|
||||
<i ng-click="moveLeft(name)" class="fa fa-angle-double-left" ng-show="!$first" tooltip="Move column to the left" tooltip-append-to-body="1"></i>
|
||||
<i ng-click="moveRight(name)" class="fa fa-angle-double-right" ng-show="!$last" tooltip="Move column to the right" tooltip-append-to-body="1"></i>
|
||||
</span>
|
||||
</th>
|
||||
</tr>
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
doc-table {
|
||||
overflow: auto;
|
||||
margin: 5px;
|
||||
flex: 1 1 100%;
|
||||
|
||||
.discover-table-datafield {
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
define(function (require) {
|
||||
var _ = require('lodash');
|
||||
var Notifier = require('ui/notify/Notifier');
|
||||
|
||||
return function EventsProvider(Private, Promise, Notifier) {
|
||||
return function EventsProvider(Private, Promise) {
|
||||
var SimpleEmitter = require('ui/utils/SimpleEmitter');
|
||||
var notify = new Notifier({ location: 'EventEmitter' });
|
||||
|
||||
|
|
|
@ -10,8 +10,14 @@ define(function () {
|
|||
.get(filter.meta.index).then(function (indexPattern) {
|
||||
key = filter.meta.field;
|
||||
field = indexPattern.fields.byName[key];
|
||||
value = filter.script.params.value;
|
||||
value = field.format.convert(value);
|
||||
|
||||
if (filter.meta.formattedValue) {
|
||||
value = filter.meta.formattedValue;
|
||||
} else {
|
||||
value = filter.script.params.value;
|
||||
value = field.format.convert(value);
|
||||
}
|
||||
|
||||
return { key: key, value: value };
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
define(function (require) {
|
||||
var _ = require('lodash');
|
||||
return function buildRangeFilter(field, params, indexPattern) {
|
||||
var filter = { meta: { index: indexPattern.id} };
|
||||
return function buildRangeFilter(field, params, indexPattern, formattedValue) {
|
||||
var filter = { meta: { index: indexPattern.id } };
|
||||
if (formattedValue) filter.meta.formattedValue = formattedValue;
|
||||
|
||||
params = _.clone(params);
|
||||
|
||||
if (params.gte && params.gt) throw new Error('gte and gt are mutually exclusive');
|
||||
if (params.lte && params.lt) throw new Error('lte and lt are mutually exclusive');
|
||||
|
|
20
src/ui/public/stringify/__tests__/_date.js
Normal file
20
src/ui/public/stringify/__tests__/_date.js
Normal file
|
@ -0,0 +1,20 @@
|
|||
describe('Date Format', function () {
|
||||
var fieldFormats;
|
||||
var expect = require('expect.js');
|
||||
var ngMock = require('ngMock');
|
||||
|
||||
beforeEach(ngMock.module('kibana'));
|
||||
beforeEach(ngMock.inject(function (Private) {
|
||||
fieldFormats = Private(require('ui/registry/field_formats'));
|
||||
}));
|
||||
|
||||
it('decoding an undefined or null date should return an empty string', function () {
|
||||
var DateFormat = fieldFormats.getType('date');
|
||||
var date = new DateFormat({
|
||||
pattern: 'dd-MM-yyyy'
|
||||
});
|
||||
expect(date.convert(null)).to.be('');
|
||||
expect(date.convert(undefined)).to.be('');
|
||||
});
|
||||
|
||||
});
|
|
@ -4,4 +4,5 @@ describe('Stringify Component', function () {
|
|||
require('./_source');
|
||||
require('./_string');
|
||||
require('./_url');
|
||||
require('./_date');
|
||||
});
|
||||
|
|
|
@ -45,6 +45,9 @@ define(function (require) {
|
|||
if (this._memoizedPattern !== pattern) {
|
||||
this._memoizedPattern = pattern;
|
||||
this._memoizedConverter = _.memoize(function converter(val) {
|
||||
if (val === null || val === undefined) {
|
||||
return '';
|
||||
}
|
||||
return moment(val).format(pattern);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -23,11 +23,6 @@
|
|||
}
|
||||
}
|
||||
|
||||
// the element should take up an even share of available space
|
||||
> .fill {
|
||||
flex: 1 1 1%;
|
||||
}
|
||||
|
||||
button {
|
||||
padding: @padding-base-vertical @padding-base-horizontal;
|
||||
font-size: @font-size-base;
|
||||
|
@ -79,7 +74,7 @@
|
|||
}
|
||||
|
||||
.inline-form {
|
||||
.flex-parent();
|
||||
.flex-parent(0, 0, auto);
|
||||
display: flex;
|
||||
|
||||
> .typeahead {
|
||||
|
@ -102,6 +97,11 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// the element should take up an even share of available space
|
||||
> .fill {
|
||||
flex: 1 1 1%;
|
||||
}
|
||||
}
|
||||
|
||||
.nav-controls .column {
|
||||
|
|
|
@ -16,12 +16,13 @@ define(function (require) {
|
|||
throw new Error('OrderedXKeysUtilService expects an object');
|
||||
}
|
||||
|
||||
var objKeys = getUniqKeys(obj);
|
||||
var uniqKeys = getUniqKeys(obj);
|
||||
var uniqKeysPairs = [...uniqKeys.entries()];
|
||||
|
||||
var interval = _.get(obj, 'ordered.interval');
|
||||
var dateInterval = moment.isDuration(interval) ? interval : false;
|
||||
|
||||
return _(objKeys)
|
||||
.pairs()
|
||||
return _(uniqKeysPairs)
|
||||
.sortBy(function (d) {
|
||||
if (d[1].isDate || d[1].isOrdered) {
|
||||
return +d[0];
|
||||
|
|
|
@ -17,7 +17,7 @@ define(function (require) {
|
|||
}
|
||||
|
||||
var flattenedData = flattenDataArray(obj);
|
||||
var uniqueXValues = {};
|
||||
var uniqueXValues = new Map();
|
||||
|
||||
var charts;
|
||||
if (!obj.series) {
|
||||
|
@ -36,7 +36,7 @@ define(function (require) {
|
|||
|
||||
flattenedData.forEach(function (d, i) {
|
||||
var key = d.x;
|
||||
var prev = uniqueXValues[key];
|
||||
var prev = uniqueXValues.get(key);
|
||||
|
||||
if (d.xi != null) {
|
||||
i = d.xi;
|
||||
|
@ -46,12 +46,12 @@ define(function (require) {
|
|||
i = Math.min(i, prev.index);
|
||||
}
|
||||
|
||||
uniqueXValues[key] = {
|
||||
uniqueXValues.set(key, {
|
||||
index: i,
|
||||
isDate: isDate,
|
||||
isOrdered: isOrdered,
|
||||
isNumber: _.isNumber(key)
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
return uniqueXValues;
|
||||
|
|
|
@ -14,6 +14,7 @@ module.exports = function (grunt) {
|
|||
'_build:readme',
|
||||
'_build:installNpmDeps',
|
||||
'clean:testsFromModules',
|
||||
'clean:deepModuleBins',
|
||||
'clean:deepModules',
|
||||
'run:optimizeBuild',
|
||||
'stop:optimizeBuild',
|
||||
|
|
|
@ -4,6 +4,7 @@ module.exports = function (grunt) {
|
|||
build: 'build',
|
||||
target: 'target',
|
||||
testsFromModules: 'build/kibana/node_modules/**/*test*/**',
|
||||
deepModules: 'build/kibana/node_modules/*/node_modules/**/{' + modules.join(',') + '}/**'
|
||||
deepModuleBins: 'build/kibana/node_modules/*/node_modules/**/.bin/{' + modules.join(',') + '}',
|
||||
deepModules: 'build/kibana/node_modules/*/node_modules/**/{' + modules.join(',') + '}/',
|
||||
};
|
||||
};
|
||||
|
|
|
@ -1,12 +1,44 @@
|
|||
module.exports = function (grunt) {
|
||||
return {
|
||||
unit: {
|
||||
configFile: 'karma.conf.js',
|
||||
singleRun: true,
|
||||
reporters: 'dots',
|
||||
browsers: [
|
||||
'<%= karmaBrowser %>'
|
||||
]
|
||||
}
|
||||
options: {
|
||||
// base path that will be used to resolve all patterns (eg. files, exclude)
|
||||
basePath: '',
|
||||
|
||||
captureTimeout: 30000,
|
||||
browserNoActivityTimeout: 120000,
|
||||
frameworks: ['mocha'],
|
||||
port: 9876,
|
||||
colors: true,
|
||||
logLevel: grunt.option('debug') || grunt.option('verbose') ? 'DEBUG' : 'INFO',
|
||||
autoWatch: false,
|
||||
browsers: ['<%= karmaBrowser %>'],
|
||||
|
||||
// available reporters: https://npmjs.org/browse/keyword/karma-reporter
|
||||
reporters: ['progress', 'growl'],
|
||||
|
||||
// list of files / patterns to load in the browser
|
||||
files: [
|
||||
'http://localhost:5610/bundles/commons.bundle.js',
|
||||
'http://localhost:5610/bundles/tests.bundle.js',
|
||||
'http://localhost:5610/bundles/commons.style.css',
|
||||
'http://localhost:5610/bundles/tests.style.css'
|
||||
],
|
||||
|
||||
proxies: {
|
||||
'/tests/': 'http://localhost:5610/tests/',
|
||||
'/bundles/': 'http://localhost:5610/bundles/'
|
||||
},
|
||||
|
||||
client: {
|
||||
mocha: {
|
||||
reporter: 'html', // change Karma's debug.html to the mocha web reporter
|
||||
timeout: 10000,
|
||||
slow: 5000
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
dev: { singleRun: false },
|
||||
unit: { singleRun: true },
|
||||
};
|
||||
};
|
||||
|
|
|
@ -12,10 +12,31 @@ module.exports = function (grunt) {
|
|||
},
|
||||
cmd: './bin/kibana',
|
||||
args: [
|
||||
'--server.port=5610',
|
||||
'--env.name=development',
|
||||
'--logging.json=false',
|
||||
'--optimize.tests=true',
|
||||
'--optimize.lazy=false'
|
||||
'--optimize.bundleFilter=tests',
|
||||
'--plugins.initialize=false'
|
||||
]
|
||||
},
|
||||
|
||||
devTestServer: {
|
||||
options: {
|
||||
wait: false,
|
||||
ready: /Server running/,
|
||||
quiet: false,
|
||||
failOnError: false
|
||||
},
|
||||
cmd: './bin/kibana',
|
||||
args: [
|
||||
'--dev',
|
||||
'--no-watch',
|
||||
'--server.port=5610',
|
||||
'--optimize.lazyPort=5611',
|
||||
'--optimize.lazyPrebuild=true',
|
||||
'--logging.json=false',
|
||||
'--optimize.bundleFilter=tests',
|
||||
'--plugins.initialize=false'
|
||||
]
|
||||
},
|
||||
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
module.exports = function (grunt) {
|
||||
let { compact } = require('lodash');
|
||||
|
||||
grunt.registerTask('jenkins', 'Jenkins build script', [
|
||||
grunt.registerTask('jenkins', 'Jenkins build script', compact([
|
||||
'esvm:dev',
|
||||
'test'
|
||||
]);
|
||||
'test',
|
||||
process.env.JOB_NAME === 'kibana_core' ? 'build' : null
|
||||
]));
|
||||
|
||||
};
|
||||
|
|
|
@ -1,58 +0,0 @@
|
|||
module.exports = function (grunt) {
|
||||
var maybeStartServer = function (options) {
|
||||
return function () {
|
||||
var http = require('http');
|
||||
var opts = {
|
||||
method: 'HEAD',
|
||||
path: '/api/status',
|
||||
host: 'localhost',
|
||||
port: options.port
|
||||
};
|
||||
|
||||
grunt.log.debug('checking for server', JSON.stringify(opts));
|
||||
|
||||
var req = http.request(opts);
|
||||
|
||||
var done = (function (cb) {
|
||||
return function (res) {
|
||||
req.removeListener('error', onError);
|
||||
req.removeListener('response', onResponse);
|
||||
if (res) res.socket.destroy();
|
||||
cb();
|
||||
};
|
||||
}(this.async()));
|
||||
|
||||
function onResponse(res) {
|
||||
grunt.log.debug('Server responded with', res.statusCode);
|
||||
if (res.statusCode === 200 && res.headers['x-app-name'] === 'kibana') {
|
||||
grunt.log.ok('Kibana server already started on port', options.port);
|
||||
} else {
|
||||
grunt.log.error('Another server is already running on port', options.port);
|
||||
process.exit(1); // eslint-disable-line no-process-exit
|
||||
}
|
||||
|
||||
done(res);
|
||||
}
|
||||
|
||||
function onError(err) {
|
||||
if (err.code !== 'ECONNREFUSED') {
|
||||
grunt.log.error('Kibana server check failed', err);
|
||||
}
|
||||
|
||||
grunt.config.set(options.name, true);
|
||||
grunt.task.run(options.tasks);
|
||||
done();
|
||||
}
|
||||
|
||||
req.on('error', onError);
|
||||
req.on('response', onResponse);
|
||||
req.end();
|
||||
};
|
||||
};
|
||||
|
||||
grunt.registerTask('maybeStartTestServer', maybeStartServer({
|
||||
name: 'kibana-server',
|
||||
port: grunt.option('port') || 5601,
|
||||
tasks: ['run:testServer']
|
||||
}));
|
||||
};
|
|
@ -1,29 +1,26 @@
|
|||
var _ = require('lodash');
|
||||
module.exports = function (grunt) {
|
||||
grunt.registerTask('test', function () {
|
||||
if (grunt.option('quick')) {
|
||||
grunt.task.run('quick-test');
|
||||
return;
|
||||
}
|
||||
grunt.registerTask('test:server', [ 'simplemocha:all' ]);
|
||||
grunt.registerTask('test:browser', [ 'run:testServer', 'karma:unit' ]);
|
||||
|
||||
grunt.registerTask('test:quick', [
|
||||
'test:server',
|
||||
'test:browser'
|
||||
]);
|
||||
|
||||
grunt.registerTask('test:dev', [
|
||||
'run:devTestServer',
|
||||
'karma:dev'
|
||||
]);
|
||||
|
||||
grunt.registerTask('test', function (subTask) {
|
||||
if (subTask) grunt.fail.fatal(`invalid task "test:${subTask}"`);
|
||||
|
||||
grunt.task.run(_.compact([
|
||||
'eslint:source',
|
||||
'simplemocha:all',
|
||||
'maybeStartTestServer',
|
||||
'karma:unit'
|
||||
!grunt.option('quick') && 'eslint:source',
|
||||
'test:quick'
|
||||
]));
|
||||
});
|
||||
|
||||
grunt.registerTask('quick-test', function () {
|
||||
grunt.task.run([
|
||||
'simplemocha:all',
|
||||
'maybeStartTestServer',
|
||||
'karma:unit'
|
||||
]);
|
||||
});
|
||||
|
||||
grunt.registerTask('test:watch', [
|
||||
'maybeStartTestServer',
|
||||
'watch:test'
|
||||
]);
|
||||
grunt.registerTask('quick-test', ['test:quick']); // historical alias
|
||||
};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue