mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
Merge branch 'master' of github.com:elastic/kibana into fix/configFileOrder
This commit is contained in:
commit
1d576f4fd2
109 changed files with 6479 additions and 656 deletions
4
.gitignore
vendored
4
.gitignore
vendored
|
@ -10,8 +10,10 @@ target
|
|||
.idea
|
||||
*.iml
|
||||
*.log
|
||||
esvm
|
||||
/esvm
|
||||
.htpasswd
|
||||
installedPlugins
|
||||
disabledPlugins
|
||||
webpackstats.json
|
||||
config/kibana.dev.yml
|
||||
coverage
|
||||
|
|
|
@ -1 +1 @@
|
|||
iojs-v2.4
|
||||
iojs-v2.5
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
language: node_js
|
||||
node_js: 'iojs-v2.4'
|
||||
install: npm install
|
||||
node_js: 'iojs-v2.5'
|
||||
install:
|
||||
- npm install -g npm@3.2
|
||||
- npm install
|
||||
script: ./node_modules/.bin/grunt travis
|
||||
sudo: false
|
||||
cache:
|
||||
|
|
|
@ -23,16 +23,22 @@ Please make sure you have signed the [Contributor License Agreement](http://www.
|
|||
nvm install "$(cat .node-version)"
|
||||
```
|
||||
|
||||
- Install npm 3.2
|
||||
|
||||
```sh
|
||||
npm install -g npm@3.2
|
||||
```
|
||||
|
||||
- Install dependencies
|
||||
|
||||
```sh
|
||||
npm install
|
||||
```
|
||||
|
||||
- Start elasticsearch, you can use [esvm](https://github.com/simianhacker/esvm) to make that easier.
|
||||
- Start elasticsearch
|
||||
|
||||
```sh
|
||||
grunt esvm:dev:keepalive
|
||||
npm run elasticsearch
|
||||
```
|
||||
|
||||
- Start the development server.
|
||||
|
@ -59,15 +65,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
|
||||
|
||||
|
|
24
Gruntfile.js
24
Gruntfile.js
|
@ -1,4 +1,4 @@
|
|||
require('babel/register')(require('./src/optimize/babelOptions'));
|
||||
require('babel/register')(require('./src/optimize/babelOptions').node);
|
||||
|
||||
module.exports = function (grunt) {
|
||||
// set the config once before calling load-grunt-config
|
||||
|
@ -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';
|
||||
|
@ -41,23 +45,7 @@ module.exports = function (grunt) {
|
|||
'<%= root %>/tasks/**/*.js',
|
||||
'<%= src %>/**/*.js',
|
||||
'!<%= src %>/fixtures/**/*.js'
|
||||
],
|
||||
|
||||
deepModules: {
|
||||
'caniuse-db': '1.0.30000265',
|
||||
'chalk': '1.1.0',
|
||||
'glob': '4.5.3',
|
||||
'har-validator': '1.8.0',
|
||||
'json5': '0.4.0',
|
||||
'loader-utils': '0.2.11',
|
||||
'micromatch': '2.2.0',
|
||||
'postcss-normalize-url': '2.1.1',
|
||||
'postcss-reduce-idents': '1.0.2',
|
||||
'postcss-unique-selectors': '1.0.0',
|
||||
'postcss-minify-selectors': '1.4.6',
|
||||
'postcss-single-charset': '0.3.0',
|
||||
'regenerator': '0.8.36'
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
grunt.config.merge(config);
|
||||
|
|
|
@ -35,4 +35,11 @@ Visit [Elastic.co](http://www.elastic.co/guide/en/kibana/current/index.html) for
|
|||
|
||||
## Snapshot Builds
|
||||
|
||||
***Snapshots are currently disabled*** until [#4597](https://github.com/elastic/kibana/issues/4597) is complete, the snapshot builds can not be built. Master can be started for development or experimentation by running `./bin/kibana` from the root of the project.
|
||||
For the daring, snapshot builds are available. These builds are created after each commit to the master branch, and therefore are not something you should run in production.
|
||||
|
||||
| platform | | |
|
||||
| --- | --- | --- |
|
||||
| OSX | [tar](http://download.elastic.co/kibana/kibana/kibana-4.2.0-snapshot-darwin-x64.tar.gz) | [zip](http://download.elastic.co/kibana/kibana/kibana-4.2.0-snapshot-darwin-x64.zip) |
|
||||
| Linux x64 | [tar](http://download.elastic.co/kibana/kibana/kibana-4.2.0-snapshot-linux-x64.tar.gz) | [zip](http://download.elastic.co/kibana/kibana/kibana-4.2.0-snapshot-linux-x64.zip) |
|
||||
| Linux x86 | [tar](http://download.elastic.co/kibana/kibana/kibana-4.2.0-snapshot-linux-x86.tar.gz) | [zip](http://download.elastic.co/kibana/kibana/kibana-4.2.0-snapshot-linux-x86.zip) |
|
||||
| Windows | [tar](http://download.elastic.co/kibana/kibana/kibana-4.2.0-snapshot-windows.tar.gz) | [zip](http://download.elastic.co/kibana/kibana/kibana-4.2.0-snapshot-windows.zip) |
|
||||
|
|
|
@ -2,6 +2,7 @@ This is a collection of style guides for Kibana projects. The include guides for
|
|||
|
||||
- [JavaScript](#javascript-style-guide)
|
||||
- [Kibana Project](#kibana-style-guide)
|
||||
- [Html](#html-style-guide)
|
||||
|
||||
# JavaScript Style Guide
|
||||
|
||||
|
@ -855,6 +856,24 @@ require('ui/routes')
|
|||
});
|
||||
```
|
||||
|
||||
# Html Style Guide
|
||||
|
||||
### Multiple attribute values
|
||||
|
||||
When a node has multiple attributes that would cause it to exceed the line character limit, each attribute including the first should be on its own line with a single indent. Also, when a node that is styled in this way has child nodes, there should be a blank line between the openening parent tag and the first child tag.
|
||||
|
||||
```
|
||||
<ul
|
||||
attribute1="value1"
|
||||
attribute2="value2"
|
||||
attribute3="value3">
|
||||
|
||||
<li></li>
|
||||
<li></li>
|
||||
...
|
||||
</ul>
|
||||
```
|
||||
|
||||
# Attribution
|
||||
|
||||
This JavaScript guide forked from the [node style guide](https://github.com/felixge/node-style-guide) created by [Felix Geisendörfer](http://felixge.de/) and is
|
||||
|
|
|
@ -20,14 +20,14 @@
|
|||
|
||||
# If your Elasticsearch is protected with basic auth, this is the user credentials
|
||||
# used by the Kibana server to perform maintence on the kibana_index at statup. Your Kibana
|
||||
# users will still need to authenticate with Elasticsearch (which is proxied thorugh
|
||||
# users will still need to authenticate with Elasticsearch (which is proxied through
|
||||
# the Kibana server)
|
||||
# elasticsearch.username: user
|
||||
# elasticsearch.password: pass
|
||||
|
||||
# SSL for outgoing requests from the Kibana Server to the browser (PEM formatted)
|
||||
# server.ssl.cert: /path/to/your/server.key
|
||||
# server.ssl.key: /path/to/your/server.crt
|
||||
# server.ssl.cert: /path/to/your/server.crt
|
||||
# server.ssl.key: /path/to/your/server.key
|
||||
|
||||
# Optional setting to validate that your Elasticsearch backend uses the same key files (PEM formatted)
|
||||
# elasticsearch.ssl.cert: /path/to/your/client.crt
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
5547
npm-shrinkwrap.json
generated
Normal file
5547
npm-shrinkwrap.json
generated
Normal file
File diff suppressed because it is too large
Load diff
45
package.json
45
package.json
|
@ -13,8 +13,8 @@
|
|||
"private": false,
|
||||
"version": "4.2.0-snapshot",
|
||||
"build": {
|
||||
"number": 8173,
|
||||
"sha": "0102888deb393e4141369fbd1644a5d77f8732da"
|
||||
"number": 8467,
|
||||
"sha": "6cb7fec4e154faa0a4a3fee4b33dfef91b9870d9"
|
||||
},
|
||||
"main": "src/server/KbnServer.js",
|
||||
"homepage": "https://www.elastic.co/products/kibana",
|
||||
|
@ -34,9 +34,16 @@
|
|||
],
|
||||
"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",
|
||||
"test:coverage": "grunt test:coverage",
|
||||
"build": "grunt build",
|
||||
"start": "./bin/kibana --dev",
|
||||
"precommit": "grunt lintStagedFiles",
|
||||
"karma": "karma start"
|
||||
"karma": "karma start",
|
||||
"elasticsearch": "grunt esvm:dev:keepalive"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
@ -44,22 +51,21 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"@spalger/angular-bootstrap": "^0.10.0",
|
||||
"@spalger/angular-nvd3": "^1.0.0-beta",
|
||||
"@spalger/filesaver": "^1.1.2",
|
||||
"@spalger/leaflet-draw": "^0.2.3",
|
||||
"@spalger/leaflet-heat": "^0.1.3",
|
||||
"@spalger/nvd3": "^1.8.1",
|
||||
"@spalger/ui-ace": "^0.2.3",
|
||||
"Nonsense": "^0.1.2",
|
||||
"angular": "1.2.28",
|
||||
"angular-bindonce": "0.3.1",
|
||||
"angular-elastic": "2.5.0",
|
||||
"angular-mocks": "1.2.28",
|
||||
"angular-nvd3": "panda01/angular-nvd3#kibana",
|
||||
"angular-route": "1.2.28",
|
||||
"ansicolors": "^0.3.2",
|
||||
"autoprefixer": "^5.2.0",
|
||||
"autoprefixer-loader": "^2.0.0",
|
||||
"babel": "^5.8.21",
|
||||
"babel-core": "^5.8.21",
|
||||
"babel-core": "^5.8.22",
|
||||
"babel-loader": "^5.3.2",
|
||||
"babel-runtime": "^5.8.20",
|
||||
"bluebird": "^2.9.27",
|
||||
|
@ -67,7 +73,6 @@
|
|||
"bootstrap": "^3.3.5",
|
||||
"brace": "^0.5.1",
|
||||
"bunyan": "^1.2.3",
|
||||
"chokidar": "^1.0.4",
|
||||
"commander": "^2.8.1",
|
||||
"css-loader": "^0.15.1",
|
||||
"d3": "^3.5.6",
|
||||
|
@ -79,32 +84,28 @@
|
|||
"extract-text-webpack-plugin": "^0.8.2",
|
||||
"file-loader": "^0.8.4",
|
||||
"font-awesome": "^4.3.0",
|
||||
"glob": "^4.3.2",
|
||||
"good": "^6.2.0",
|
||||
"good-squeeze": "^2.1.0",
|
||||
"gridster": "^0.5.6",
|
||||
"hapi": "^8.6.1",
|
||||
"imports-loader": "^0.6.4",
|
||||
"is-array": "^1.0.1",
|
||||
"jade": "^1.7.2",
|
||||
"jade-loader": "^0.7.1",
|
||||
"joi": "^6.4.3",
|
||||
"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",
|
||||
"lodash": "^3.10.0",
|
||||
"marked": "0.3.3",
|
||||
"memory-fs": "^0.2.0",
|
||||
"minimatch": "^2.0.8",
|
||||
"mkdirp": "^0.5.1",
|
||||
"moment": "^2.10.3",
|
||||
"moment-timezone": "^0.4.0",
|
||||
"ng-clip": "^0.2.6",
|
||||
"numeral": "^1.5.3",
|
||||
"nvd3": "panda01/nvd3#kibana",
|
||||
"raw-loader": "^0.5.1",
|
||||
"request": "^2.60.0",
|
||||
"requirefrom": "^0.2.0",
|
||||
|
@ -121,37 +122,44 @@
|
|||
"zeroclipboard": "^2.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"Nonsense": "^0.1.2",
|
||||
"angular-mocks": "1.2.28",
|
||||
"auto-release-sinon": "^1.0.3",
|
||||
"babel-eslint": "^4.0.5",
|
||||
"chokidar": "^1.0.4",
|
||||
"eslint": "1.0.x",
|
||||
"expect.js": "^0.3.1",
|
||||
"faker": "^1.1.0",
|
||||
"glob": "^4.3.2",
|
||||
"grunt": "^0.4.5",
|
||||
"grunt-babel": "^5.0.1",
|
||||
"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-run": "^0.4.0",
|
||||
"grunt-s3": "^0.2.0-alpha.3",
|
||||
"grunt-simple-mocha": "^0.4.0",
|
||||
"gruntify-eslint": "^1.0.0",
|
||||
"html-entities": "^1.1.1",
|
||||
"husky": "^0.8.1",
|
||||
"istanbul-instrumenter-loader": "^0.1.3",
|
||||
"karma": "^0.13.3",
|
||||
"karma-chrome-launcher": "^0.2.0",
|
||||
"karma-coverage": "^0.5.0",
|
||||
"karma-firefox-launcher": "^0.1.6",
|
||||
"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",
|
||||
"marked-text-renderer": "^0.1.0",
|
||||
"mocha": "^2.2.5",
|
||||
"nock": "^2.9.0",
|
||||
"npm": "^2.11.0",
|
||||
"npm": "3.2",
|
||||
"portscanner": "^1.0.0",
|
||||
"simple-git": "^1.3.0",
|
||||
"sinon": "^1.15.4",
|
||||
|
@ -159,6 +167,7 @@
|
|||
"wreck": "^6.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=2"
|
||||
"node": "2.5",
|
||||
"npm": "3.2"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,33 @@ 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 = 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');
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -19,7 +19,9 @@ let dead = fork => {
|
|||
};
|
||||
|
||||
let kill = fork => {
|
||||
fork.kill('SIGINT'); // make it snappy
|
||||
// fork.kill() waits for process to disconnect, but causes occasional
|
||||
// "ipc disconnected" errors and is too slow for the proc's "exit" event
|
||||
fork.process.kill();
|
||||
fork.killed = true;
|
||||
};
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ var babelOpts = _.defaults({
|
|||
fromRoot('src'),
|
||||
/[\\\/](node_modules|bower_components)[\\\/]/
|
||||
]
|
||||
}, require('../optimize/babelOptions'));
|
||||
}, require('../optimize/babelOptions').node);
|
||||
|
||||
require('babel/register')(babelOpts);
|
||||
require('./cli');
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
require('babel/register')(require('../optimize/babelOptions'));
|
||||
require('babel/register')(require('../optimize/babelOptions').node);
|
||||
require('./cli');
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
var expect = require('expect.js');
|
||||
var sinon = require('sinon');
|
||||
var nock = require('nock');
|
||||
var glob = require('glob');
|
||||
var rimraf = require('rimraf');
|
||||
var fs = require('fs');
|
||||
var { join } = require('path');
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -11,6 +11,7 @@ var CommonsChunkPlugin = require('webpack/lib/optimize/CommonsChunkPlugin');
|
|||
let utils = require('requirefrom')('src/utils');
|
||||
let fromRoot = utils('fromRoot');
|
||||
let babelOptions = require('./babelOptions');
|
||||
let babelExclude = [/[\/\\](webpackShims|node_modules|bower_components)[\/\\]/];
|
||||
|
||||
class BaseOptimizer {
|
||||
constructor(opts) {
|
||||
|
@ -111,26 +112,27 @@ class BaseOptimizer {
|
|||
{ test: /[\/\\]src[\/\\](plugins|ui)[\/\\].+\.js$/, loader: `rjs-repack${mapQ}` },
|
||||
{
|
||||
test: /\.js$/,
|
||||
exclude: /[\/\\](node_modules|bower_components)[\/\\]/,
|
||||
exclude: babelExclude.concat(this.env.noParse),
|
||||
loader: 'babel',
|
||||
query: babelOptions
|
||||
query: babelOptions.webpack
|
||||
},
|
||||
{
|
||||
test: /\.jsx$/,
|
||||
exclude: /[\/\\](node_modules|bower_components)[\/\\]/,
|
||||
exclude: babelExclude.concat(this.env.noParse),
|
||||
loader: 'babel',
|
||||
query: defaults({
|
||||
nonStandard: true
|
||||
}, babelOptions)
|
||||
nonStandard: true,
|
||||
}, babelOptions.webpack)
|
||||
}
|
||||
].concat(this.env.loaders),
|
||||
postLoaders: this.env.postLoaders || [],
|
||||
noParse: this.env.noParse,
|
||||
},
|
||||
|
||||
resolve: {
|
||||
extensions: ['.babel.js', '.js', '.less', ''],
|
||||
extensions: ['.js', '.jsx', '.less', ''],
|
||||
postfixes: [''],
|
||||
modulesDirectories: ['node_modules'],
|
||||
modulesDirectories: ['webpackShims', 'node_modules'],
|
||||
loaderPostfixes: ['-loader', ''],
|
||||
root: fromRoot('.'),
|
||||
alias: this.env.aliases,
|
||||
|
|
|
@ -1,4 +1,10 @@
|
|||
module.exports = {
|
||||
exports.webpack = {
|
||||
stage: 1,
|
||||
nonStandard: false
|
||||
nonStandard: false,
|
||||
optional: ['runtime']
|
||||
};
|
||||
|
||||
exports.node = Object.assign({}, exports.webpack, {
|
||||
optional: ['runtime', 'asyncToGenerator'],
|
||||
blacklist: ['regenerator']
|
||||
});
|
||||
|
|
|
@ -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();
|
|
@ -1,28 +0,0 @@
|
|||
module.exports = function (kibana) {
|
||||
let _ = require('lodash');
|
||||
let fromRoot = require('../../utils/fromRoot');
|
||||
let { readdirSync } = require('fs');
|
||||
let { resolve, basename } = require('path');
|
||||
|
||||
let modules = {
|
||||
moment$: fromRoot('node_modules/moment/min/moment.min.js')
|
||||
};
|
||||
|
||||
let metaLibs = resolve(__dirname, 'metaLibs');
|
||||
readdirSync(metaLibs).forEach(function (file) {
|
||||
if (file[0] === '.') return;
|
||||
let name = basename(file, '.js') + '$';
|
||||
modules[name] = resolve(metaLibs, file);
|
||||
});
|
||||
|
||||
return new kibana.Plugin({
|
||||
init: false,
|
||||
uiExports: {
|
||||
modules: modules,
|
||||
noParse: [
|
||||
/node_modules[\/\\](angular|elasticsearch-browser)[\/\\]/,
|
||||
/node_modules[\/\\](angular-nvd3|mocha|moment)[\/\\]/
|
||||
]
|
||||
}
|
||||
});
|
||||
};
|
|
@ -1,5 +0,0 @@
|
|||
require('d3');
|
||||
require('nvd3/build/nv.d3.css');
|
||||
require('nvd3/build/nv.d3.js');
|
||||
require('angular-nvd3/dist/angular-nvd3.min.js');
|
||||
module.exports = window.nv;
|
|
@ -1,4 +0,0 @@
|
|||
{
|
||||
"name": "bundledLibs",
|
||||
"version": "1.0.0"
|
||||
}
|
|
@ -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();
|
||||
},
|
||||
|
||||
|
@ -34,6 +35,7 @@ module.exports = function (kibana) {
|
|||
exposeClient(server);
|
||||
createProxy(server, 'GET', '/{paths*}');
|
||||
createProxy(server, 'POST', '/_mget');
|
||||
createProxy(server, 'POST', '/{index}/_search');
|
||||
createProxy(server, 'POST', '/_msearch');
|
||||
|
||||
function noBulkCheck(request, reply) {
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
};
|
||||
|
|
|
@ -1,30 +1,32 @@
|
|||
var url = require('url');
|
||||
var fs = require('fs');
|
||||
var _ = require('lodash');
|
||||
var readFile = _.partialRight(require('fs').readFileSync, 'utf8');
|
||||
var http = require('http');
|
||||
var agentOptions;
|
||||
module.exports = function (server) {
|
||||
var https = require('https');
|
||||
|
||||
module.exports = _.memoize(function (server) {
|
||||
var config = server.config();
|
||||
var target = url.parse(config.get('elasticsearch.url'));
|
||||
|
||||
if (!agentOptions) {
|
||||
agentOptions = {
|
||||
rejectUnauthorized: config.get('elasticsearch.ssl.verify')
|
||||
};
|
||||
if (!/^https/.test(target.protocol)) return new http.Agent();
|
||||
|
||||
var customCA;
|
||||
if (/^https/.test(target.protocol) && config.get('elasticsearch.ssl.ca')) {
|
||||
customCA = fs.readFileSync(config.get('elasticsearch.ssl.ca'), 'utf8');
|
||||
agentOptions.ca = [customCA];
|
||||
}
|
||||
var agentOptions = {
|
||||
rejectUnauthorized: config.get('elasticsearch.ssl.verify')
|
||||
};
|
||||
|
||||
// Add client certificate and key if required by elasticsearch
|
||||
if (/^https/.test(target.protocol) &&
|
||||
config.get('elasticsearch.ssl.cert') &&
|
||||
config.get('elasticsearch.ssl.key')) {
|
||||
agentOptions.crt = fs.readFileSync(config.get('elasticsearch.ssl.cert'), 'utf8');
|
||||
agentOptions.key = fs.readFileSync(config.get('elasticsearch.ssl.key'), 'utf8');
|
||||
}
|
||||
if (config.get('elasticsearch.ssl.ca')) {
|
||||
agentOptions.ca = [readFile(config.get('elasticsearch.ssl.ca'))];
|
||||
}
|
||||
|
||||
return new http.Agent(agentOptions);
|
||||
};
|
||||
// Add client certificate and key if required by elasticsearch
|
||||
if (config.get('elasticsearch.ssl.cert') && config.get('elasticsearch.ssl.key')) {
|
||||
agentOptions.cert = readFile(config.get('elasticsearch.ssl.cert'));
|
||||
agentOptions.key = readFile(config.get('elasticsearch.ssl.key'));
|
||||
}
|
||||
|
||||
return new https.Agent(agentOptions);
|
||||
});
|
||||
|
||||
// See https://lodash.com/docs#memoize: We use a Map() instead of the default, because we want the keys in the cache
|
||||
// to be the server objects, and by default these would be coerced to strings as keys (which wouldn't be useful)
|
||||
module.exports.cache = new Map();
|
|
@ -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) {
|
||||
|
|
|
@ -1,6 +1,14 @@
|
|||
<div class="panel panel-default" ng-switch on="panel.type" ng-if="savedObj || error">
|
||||
<div class="panel-heading">
|
||||
<span class="panel-title">{{savedObj.title}}</span>
|
||||
<span class="panel-title">
|
||||
<i
|
||||
class="fa"
|
||||
ng-class="savedObj.vis.type.icon"
|
||||
aria-label="{{savedObj.vis.type.title}} Icon"
|
||||
title="{{savedObj.vis.type.title}}">
|
||||
</i>
|
||||
{{savedObj.title}}
|
||||
</span>
|
||||
<div class="btn-group">
|
||||
<a aria-label="Edit" ng-show="chrome.getVisible() && editUrl" ng-href="{{editUrl}}">
|
||||
<i aria-hidden="true" class="fa fa-pencil"></i>
|
||||
|
|
|
@ -76,6 +76,12 @@ dashboard-grid {
|
|||
|
||||
.ellipsis();
|
||||
flex: 1 1 auto;
|
||||
|
||||
i {
|
||||
opacity: 0.3;
|
||||
font-size: 1.2em;
|
||||
margin-right: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
a {
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
(Default: <i>{{conf.defVal == undefined ? 'null' : conf.defVal}}</i>)
|
||||
</span>
|
||||
<br>
|
||||
<span class="smaller">{{conf.description}}</span>
|
||||
<span class="smaller" ng-bind-html="conf.description | trustAsHtml"></span>
|
||||
</td>
|
||||
<td class="value">
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ define(function (require) {
|
|||
require('plugins/kibana/settings/sections/indices/index'),
|
||||
require('plugins/kibana/settings/sections/advanced/index'),
|
||||
require('plugins/kibana/settings/sections/objects/index'),
|
||||
require('plugins/kibana/settings/sections/status/index'),
|
||||
require('plugins/kibana/settings/sections/about/index')
|
||||
];
|
||||
});
|
||||
|
|
|
@ -129,6 +129,8 @@ define(function (require) {
|
|||
if (_.contains(loadedEditors, editor)) return;
|
||||
loadedEditors.push(editor);
|
||||
|
||||
editor.$blockScrolling = Infinity;
|
||||
|
||||
var session = editor.getSession();
|
||||
var fieldName = editor.container.id;
|
||||
|
||||
|
|
10
src/plugins/kibana/public/settings/sections/status/index.js
Normal file
10
src/plugins/kibana/public/settings/sections/status/index.js
Normal file
|
@ -0,0 +1,10 @@
|
|||
define(function (require) {
|
||||
var _ = require('lodash');
|
||||
|
||||
return {
|
||||
order: 3,
|
||||
name: 'status',
|
||||
display: 'Status',
|
||||
url: '/status'
|
||||
};
|
||||
});
|
|
@ -130,7 +130,8 @@
|
|||
|
||||
<div class="vis-editor-canvas" ng-class="{ embedded: !chrome.getVisible() }">
|
||||
<div class="visualize-info" ng-if="savedVis.id">
|
||||
<div class="visualize-info-tab">
|
||||
<div class="visualize-info-tab" title="{{savedVis.vis.type.title}}">
|
||||
<i class="fa" aria-label="{{savedVis.vis.type.title}} Icon" ng-class="savedVis.vis.type.icon"></i>
|
||||
<span bindonce bo-bind="savedVis.title"></span>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -9,10 +9,10 @@ module.exports = function formatNumber(num, which) {
|
|||
case 'time':
|
||||
return moment(num).format('HH:mm:ss');
|
||||
case 'byte':
|
||||
format += 'b';
|
||||
format += ' b';
|
||||
break;
|
||||
case 'ms':
|
||||
postfix = 'ms';
|
||||
postfix = ' ms';
|
||||
break;
|
||||
}
|
||||
return numeral(num).format(format) + postfix;
|
||||
|
|
|
@ -1,48 +1,39 @@
|
|||
<div class="container">
|
||||
<div class="container state_default state_{{ui.serverState}}">
|
||||
<header>
|
||||
<h1>
|
||||
<strong>Kibana</strong> Status Page
|
||||
Status: <span class="state_color">{{ ui.serverStateMessage }}</span>
|
||||
<i class="fa state_color state_icon" />
|
||||
</h1>
|
||||
</header>
|
||||
|
||||
<section class="section">
|
||||
<h4>What is this page?</h4>
|
||||
<p>This page is your sanity check, and your savior. You can check for potential problems</p>
|
||||
<p>Here is the status of your kibana instance and the plugins you have installed along with some, statistics to asses potential problems.</p>
|
||||
</section>
|
||||
|
||||
<div class="system_status_wrapper state_default state_{{ui.serverState}}">
|
||||
|
||||
<h3 class="title">
|
||||
<b>System Status</b> {{ ui.serverStateMessage }}
|
||||
</h3>
|
||||
<div class="row metrics_wrapper">
|
||||
<div ng-repeat="(name, data) in ui.metrics">
|
||||
<status-page-metric name="{{name}}" data="data"></status-page-metric>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row plugin_status_wrapper">
|
||||
<h3>Installed Plugins</h3>
|
||||
<div ng-if="!ui.statuses && ui.loading" class="loading_statuses">
|
||||
<span class="spinner"></span>
|
||||
</div>
|
||||
|
||||
<h4 ng-if="!ui.statuses && !ui.loading" class="missing_statuses">
|
||||
No status information available
|
||||
No plugin status information available
|
||||
</h4>
|
||||
|
||||
<table class="status_breakdown" ng-if="ui.statuses">
|
||||
<table class="plugin_status_breakdown row" ng-if="ui.statuses">
|
||||
<tr>
|
||||
<th class="col-xs-1">Name</th>
|
||||
<th class="col-xs-11">Description</th>
|
||||
<th class="col-xs-11">Status</th>
|
||||
</tr>
|
||||
<tr ng-repeat="status in ui.statuses" class="status_row state_default state_{{status.state}}">
|
||||
<tr ng-repeat="status in ui.statuses" class="status_row plugin_state_default plugin_state_{{status.state}}">
|
||||
<td class="col-xs-1 status_name">{{status.name}}</td>
|
||||
<td class="col-xs-11 status_message">{{status.message}}</td>
|
||||
<td class="col-xs-11 status_message">
|
||||
<i class="fa plugin_state_color plugin_state_icon" />
|
||||
{{status.message}}
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
|
||||
<h2>Server Metrics</h2>
|
||||
<p>Interval of 5 seconds, with a max history of 5 minutes.</p>
|
||||
<div id="chart_cont" class="row">
|
||||
<div ng-repeat="(name, data) in ui.metrics">
|
||||
<status-page-metric name="{{name}}" data="data"></status-page-metric>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -9,7 +9,8 @@ require('ui/chrome')
|
|||
.setTabs([
|
||||
{
|
||||
id: '',
|
||||
title: 'Server Status'
|
||||
title: 'Server Status',
|
||||
activeIndicatorColor: '#EFF0F2'
|
||||
}
|
||||
])
|
||||
.setRootTemplate(require('plugins/statusPage/statusPage.html'))
|
||||
|
@ -24,6 +25,7 @@ require('ui/chrome')
|
|||
return $http
|
||||
.get('/api/status')
|
||||
.then(function (resp) {
|
||||
|
||||
if (ui.fetchError) {
|
||||
ui.fetchError.clear();
|
||||
ui.fetchError = null;
|
||||
|
@ -36,7 +38,7 @@ require('ui/chrome')
|
|||
var overall = data.status.overall;
|
||||
if (!ui.serverState || (ui.serverState !== overall.state)) {
|
||||
ui.serverState = overall.state;
|
||||
ui.serverStateMessage = overall.nickname || overall.title;
|
||||
ui.serverStateMessage = overall.title;
|
||||
}
|
||||
})
|
||||
.catch(function () {
|
||||
|
@ -50,9 +52,4 @@ require('ui/chrome')
|
|||
};
|
||||
|
||||
ui.refresh();
|
||||
|
||||
// let the browser decide when to slow down requests
|
||||
setInterval(function () {
|
||||
$scope.$eval(ui.refresh);
|
||||
}, 5000);
|
||||
});
|
||||
|
|
|
@ -1,126 +1,178 @@
|
|||
@import "~font-awesome/less/font-awesome";
|
||||
|
||||
@status-bg: #eff0f2;
|
||||
@status-metric-bg: #fff;
|
||||
@status-metric-border: #aaa;
|
||||
@status-metric-title-color: #666;
|
||||
|
||||
@status-plugins-bg: #fff;
|
||||
@status-plugins-border: #bbb;
|
||||
@status-plugins-headings-color: #666;
|
||||
|
||||
@status-default: #7c7c7c;
|
||||
@status-green: #94c63d;
|
||||
@status-yellow: #edb800;
|
||||
@status-red: #da1e04;
|
||||
|
||||
@icon-default: @fa-var-clock-o;
|
||||
@icon-green: @fa-var-check;
|
||||
@icon-yellow: @fa-var-exclamation-circle;
|
||||
@icon-red: @fa-var-exclamation-triangle;
|
||||
|
||||
// background of main page
|
||||
.content {
|
||||
background-color: @status-bg;
|
||||
}
|
||||
|
||||
.section {
|
||||
margin-bottom:15px;
|
||||
}
|
||||
|
||||
.status_breakdown {
|
||||
margin:0 15px 15px 15px;
|
||||
// metrics section
|
||||
.metrics_wrapper {
|
||||
margin-top: 25px;
|
||||
.status_metric_wrapper {
|
||||
padding: 10px;
|
||||
border: 0;
|
||||
|
||||
.status_row {
|
||||
height:30px;
|
||||
line-height:30px;
|
||||
+ .status_row {
|
||||
border-top:1px solid #ebebeb;
|
||||
.content {
|
||||
text-align: right;
|
||||
padding: 15px;
|
||||
padding-right: 20px;
|
||||
background-color: @status-metric-bg;
|
||||
border-top: 2px solid;
|
||||
border-top-color: @status-metric-border;
|
||||
|
||||
.title {
|
||||
color: @status-metric-title-color;
|
||||
margin: 0 0 5px 0;
|
||||
}
|
||||
|
||||
.average {
|
||||
font-size: 42px;
|
||||
line-height:45px;
|
||||
font-weight: normal;
|
||||
margin:0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
th {
|
||||
font-size:10px;
|
||||
color:#a9a9a9;
|
||||
height:25px;
|
||||
line-height:25px;
|
||||
}
|
||||
|
||||
.status_name {
|
||||
font-weight:bold;
|
||||
padding:0px 5px;
|
||||
}
|
||||
|
||||
.status_message {
|
||||
border-left:1px solid #ebebeb;
|
||||
padding:0;
|
||||
padding-left:15px;
|
||||
}
|
||||
}
|
||||
|
||||
.system_status_wrapper {
|
||||
// plugin status table section
|
||||
.plugin_status_wrapper {
|
||||
margin-top: 25px;
|
||||
margin-left: -5px;
|
||||
margin-right: -5px;
|
||||
border-top:2px solid;
|
||||
background-color: @status-plugins-bg;
|
||||
padding: 10px;
|
||||
|
||||
h3 {
|
||||
margin-top: 3px;
|
||||
margin-bottom: 3px;
|
||||
}
|
||||
|
||||
.missing_statuses,
|
||||
.loading_statuses {
|
||||
padding: 20px;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
.status_chart_wrapper {
|
||||
border-top:1px solid #ebebeb;
|
||||
border-left:1px solid #ebebeb;
|
||||
.average {
|
||||
font-size: 42px;
|
||||
line-height:45px;
|
||||
margin-top:0;
|
||||
font-weight:bold;
|
||||
}
|
||||
.title {
|
||||
margin:0 0 5px 0;
|
||||
text-transform:capitalize;
|
||||
}
|
||||
}
|
||||
.plugin_status_breakdown {
|
||||
margin-left: 0;
|
||||
margin-right: 0;
|
||||
|
||||
#chart_cont {
|
||||
margin-top:35px;
|
||||
}
|
||||
.status_row {
|
||||
height:30px;
|
||||
line-height:30px;
|
||||
border-bottom:1px solid;
|
||||
border-bottom-color: @status-plugins-border;
|
||||
}
|
||||
|
||||
.status_chart_wrapper:nth-child(2), .status_chart_wrapper:nth-child(3) {
|
||||
border-top:0 none transparent;
|
||||
}
|
||||
th {
|
||||
color:@status-plugins-headings-color;
|
||||
font-weight: normal;
|
||||
height:25px;
|
||||
line-height:25px;
|
||||
border-bottom:1px solid;
|
||||
border-bottom-color: @status-plugins-border;
|
||||
}
|
||||
|
||||
.status_chart_wrapper:first-child {
|
||||
border-top:0 none transparent;
|
||||
border-left:0 none transparent;
|
||||
}
|
||||
.status_name {
|
||||
padding:0px 5px;
|
||||
border-left: 2px solid;
|
||||
}
|
||||
|
||||
.status_chart_wrapper:nth-child(3n + 1) {
|
||||
border-left:0 none transparent;
|
||||
}
|
||||
|
||||
.status_chart_wrapper:nth-child(n + 4) {
|
||||
padding-top:20px;
|
||||
}
|
||||
|
||||
.nv-axis.nv-x .tick line {
|
||||
display:none;
|
||||
}
|
||||
|
||||
.state(@primary, @secondary) {
|
||||
&.system_status_wrapper {
|
||||
border:1px solid @primary;
|
||||
border-radius:5px;
|
||||
overflow: hidden;
|
||||
|
||||
.title {
|
||||
color:#ffffff;
|
||||
height:50px;
|
||||
line-height:50px;
|
||||
margin:0 0 10px 0;
|
||||
padding:0 15px;
|
||||
border-color:@primary;
|
||||
background:@primary;
|
||||
background:-moz-linear-gradient(left,@primary 0%,@secondary 100%);
|
||||
background:-webkit-gradient(linear,left top,right top,color-stop(0%,@primary),color-stop(100%,@secondary));
|
||||
background:-webkit-linear-gradient(left,@primary 0%,@secondary 100%);
|
||||
background:-o-linear-gradient(left,@primary 0%,@secondary 100%);
|
||||
background:-ms-linear-gradient(left,@primary 0%,@secondary 100%);
|
||||
background:linear-gradient(to right,@primary 0%,@secondary 100%);
|
||||
filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=@primary,endColorstr=@secondary,GradientType=1);
|
||||
.status_message {
|
||||
padding:0;
|
||||
padding-left:15px;
|
||||
border-right: 2px solid;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.status_row {
|
||||
color: @primary;
|
||||
//plugin state
|
||||
.plugin_state(@color, @icon) {
|
||||
.plugin_state_color {
|
||||
color: @color;
|
||||
}
|
||||
|
||||
.plugin_state_icon:before {
|
||||
content: @icon;
|
||||
}
|
||||
|
||||
.status_name {
|
||||
border-left-color: @color !important;
|
||||
}
|
||||
|
||||
.status_message {
|
||||
border-right-color: @color !important;
|
||||
}
|
||||
}
|
||||
|
||||
.plugin_state_default {
|
||||
.plugin_state(@status-default, @icon-default);
|
||||
}
|
||||
|
||||
.plugin_state_green {
|
||||
.plugin_state(@status-green, @icon-green);
|
||||
}
|
||||
|
||||
.plugin_state_yellow {
|
||||
.plugin_state(@status-yellow, @icon-yellow);
|
||||
}
|
||||
|
||||
.plugin_state_red {
|
||||
.plugin_state(@status-red, @icon-red);
|
||||
}
|
||||
|
||||
//server state
|
||||
.state(@color, @icon) {
|
||||
.state_color {
|
||||
color: @color;
|
||||
}
|
||||
|
||||
.state_icon:before {
|
||||
content: @icon;
|
||||
}
|
||||
|
||||
.plugin_status_wrapper {
|
||||
border-top-color: @color;
|
||||
}
|
||||
}
|
||||
|
||||
.state_default {
|
||||
.state(#7C7C7C, #CFCFCF);
|
||||
.state(@status-default, @icon-default);
|
||||
}
|
||||
|
||||
.state_green {
|
||||
.state(#0a8e03, #96f501);
|
||||
.state(@status-green, @icon-green);
|
||||
}
|
||||
|
||||
.state_yellow {
|
||||
.state(#fdee00, #c16f00);
|
||||
.state(@status-yellow, @icon-yellow);
|
||||
}
|
||||
|
||||
.state_red {
|
||||
.state(#da1e04, #ff730f);
|
||||
.state(@status-red, @icon-red);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
<div class="status_chart_wrapper col-md-4">
|
||||
<h3 class="title">{{metric.title}}</h3>
|
||||
<h4 class="average">{{ metric.averages.join(', ') }}</h4>
|
||||
<nvd3 options="metric.chartOptions" data="metric.chartData"></nvd3>
|
||||
<div class="status_metric_wrapper col-md-4">
|
||||
<div class="content">
|
||||
<h3 class="title">{{metric.extendedTitle}}</h3>
|
||||
<h4 class="average">{{ metric.averages.join(', ') }}</h4>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -5,7 +5,6 @@ require('angular-nvd3');
|
|||
|
||||
var toTitleCase = require('./lib/toTitleCase');
|
||||
var formatNumber = require('./lib/formatNumber');
|
||||
var getChartOptions = _.memoize(require('./lib/makeChartOptions'));
|
||||
var readStatData = require('./lib/readStatData');
|
||||
|
||||
function calcAvg(metricList, metricNumberType) {
|
||||
|
@ -33,17 +32,16 @@ require('ui/modules')
|
|||
|
||||
self.name = $scope.name;
|
||||
self.title = toTitleCase(self.name);
|
||||
self.extendedTitle = self.title;
|
||||
self.numberType = 'precise';
|
||||
self.seriesNames = [];
|
||||
|
||||
switch (self.name) {
|
||||
case 'heapTotal':
|
||||
case 'heapUsed':
|
||||
case 'rss':
|
||||
self.numberType = 'byte';
|
||||
break;
|
||||
|
||||
case 'delay':
|
||||
case 'responseTimeAvg':
|
||||
case 'responseTimeMax':
|
||||
self.numberType = 'ms';
|
||||
|
@ -54,12 +52,22 @@ require('ui/modules')
|
|||
break;
|
||||
}
|
||||
|
||||
self.chartOptions = getChartOptions(self.numberType);
|
||||
|
||||
$scope.$watch('data', function (data) {
|
||||
self.rawData = data;
|
||||
self.chartData = readStatData(self.rawData, self.seriesNames);
|
||||
self.averages = calcAvg(self.chartData, self.numberType);
|
||||
|
||||
var unit = '';
|
||||
self.averages = self.averages.map(function (average) {
|
||||
var parts = average.split(' ');
|
||||
var value = parts.shift();
|
||||
unit = parts.join(' ');
|
||||
return value;
|
||||
});
|
||||
self.extendedTitle = self.title;
|
||||
if (unit) {
|
||||
self.extendedTitle = `${self.extendedTitle} (${unit})`;
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
let { chain, memoize } = require('lodash');
|
||||
let { resolve } = require('path');
|
||||
let { map, fromNode } = require('bluebird');
|
||||
|
||||
let fromRoot = require('./fromRoot');
|
||||
let { Glob } = require('glob');
|
||||
|
||||
let fromRoot = require('../../utils/fromRoot');
|
||||
|
||||
let findSourceFiles = async (patterns, cwd = fromRoot('.')) => {
|
||||
patterns = [].concat(patterns || []);
|
|
@ -1,17 +1,22 @@
|
|||
module.exports = (kibana) => {
|
||||
if (!kibana.config.get('optimize.tests')) return;
|
||||
|
||||
let { union } = require('lodash');
|
||||
|
||||
let utils = require('requirefrom')('src/utils');
|
||||
let fromRoot = utils('fromRoot');
|
||||
let findSourceFiles = utils('findSourceFiles');
|
||||
let findSourceFiles = require('./findSourceFiles');
|
||||
|
||||
return new kibana.Plugin({
|
||||
config: (Joi) => {
|
||||
return Joi.object({
|
||||
enabled: Joi.boolean().default(true),
|
||||
instrument: Joi.boolean().default(false)
|
||||
}).default();
|
||||
},
|
||||
|
||||
uiExports: {
|
||||
bundle: async (UiBundle, env, apps) => {
|
||||
|
||||
let modules = [];
|
||||
let config = kibana.config;
|
||||
|
||||
// add the modules from all of the apps
|
||||
for (let app of apps) {
|
||||
|
@ -25,6 +30,14 @@ module.exports = (kibana) => {
|
|||
|
||||
for (let f of testFiles) modules.push(f);
|
||||
|
||||
if (config.get('testsBundle.instrument')) {
|
||||
env.addPostLoader({
|
||||
test: /\.jsx?$/,
|
||||
exclude: /[\/\\](__tests__|node_modules|bower_components|webpackShims)[\/\\]/,
|
||||
loader: 'istanbul-instrumenter'
|
||||
});
|
||||
}
|
||||
|
||||
return new UiBundle({
|
||||
id: 'tests',
|
||||
modules: modules,
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
{
|
||||
"name": "tests_bundle",
|
||||
"name": "testsBundle",
|
||||
"version": "0.0.0"
|
||||
}
|
||||
|
|
|
@ -1,37 +1,61 @@
|
|||
let Promise = require('bluebird');
|
||||
let Joi = require('joi');
|
||||
let _ = require('lodash');
|
||||
let { zipObject } = require('lodash');
|
||||
let override = require('./override');
|
||||
let pkg = require('requirefrom')('src/utils')('packageJson');
|
||||
|
||||
const schema = Symbol('Joi Schema');
|
||||
const schemaKeys = Symbol('Schema Extensions');
|
||||
const vals = Symbol('config values');
|
||||
const pendingSets = Symbol('Pending Settings');
|
||||
|
||||
module.exports = class Config {
|
||||
constructor(schema, defaults) {
|
||||
this.schema = Joi.object({}).default();
|
||||
this.config = {};
|
||||
this.unappliedDefaults = _.cloneDeep(defaults || {});
|
||||
if (schema) this.extendSchema(schema);
|
||||
constructor(initialSchema, initialSettings) {
|
||||
this[schemaKeys] = new Map();
|
||||
|
||||
this[vals] = Object.create(null);
|
||||
this[pendingSets] = new Map(_.pairs(_.cloneDeep(initialSettings || {})));
|
||||
|
||||
if (initialSchema) this.extendSchema(initialSchema);
|
||||
}
|
||||
|
||||
extendSchema(key, schema) {
|
||||
getPendingSets() {
|
||||
return this[pendingSets];
|
||||
}
|
||||
|
||||
extendSchema(key, extension) {
|
||||
if (key && key.isJoi) {
|
||||
return _.each(key._inner.children, function (child) {
|
||||
return _.each(key._inner.children, (child) => {
|
||||
this.extendSchema(child.key, child.schema);
|
||||
}, this);
|
||||
});
|
||||
}
|
||||
|
||||
if (this.has(key)) {
|
||||
throw new Error(`Config schema already has key ${key}`);
|
||||
throw new Error(`Config schema already has key: ${key}`);
|
||||
}
|
||||
|
||||
this.schema = this.schema.keys(_.set({}, key, schema));
|
||||
this[schemaKeys].set(key, extension);
|
||||
this[schema] = null;
|
||||
|
||||
if (this.unappliedDefaults[key]) {
|
||||
this.set(key, this.unappliedDefaults[key]);
|
||||
this.unappliedDefaults[key] = null;
|
||||
let initialVals = this[pendingSets].get(key);
|
||||
if (initialVals) {
|
||||
this.set(key, initialVals);
|
||||
this[pendingSets].delete(key);
|
||||
} else {
|
||||
this._commit(this.config);
|
||||
this._commit(this[vals]);
|
||||
}
|
||||
}
|
||||
|
||||
removeSchema(key) {
|
||||
if (!this[schemaKeys].has(key)) {
|
||||
throw new TypeError(`Unknown schema key: ${key}`);
|
||||
}
|
||||
|
||||
this[schema] = null;
|
||||
this[schemaKeys].delete(key);
|
||||
this[pendingSets].delete(key);
|
||||
delete this[vals][key];
|
||||
}
|
||||
|
||||
resetTo(obj) {
|
||||
|
@ -40,7 +64,7 @@ module.exports = class Config {
|
|||
|
||||
set(key, value) {
|
||||
// clone and modify the config
|
||||
let config = _.cloneDeep(this.config);
|
||||
let config = _.cloneDeep(this[vals]);
|
||||
if (_.isPlainObject(key)) {
|
||||
config = override(config, key);
|
||||
} else {
|
||||
|
@ -51,10 +75,10 @@ module.exports = class Config {
|
|||
this._commit(config);
|
||||
}
|
||||
|
||||
_commit(newConfig) {
|
||||
_commit(newVals) {
|
||||
// resolve the current environment
|
||||
let env = newConfig.env;
|
||||
delete newConfig.env;
|
||||
let env = newVals.env;
|
||||
delete newVals.env;
|
||||
if (_.isObject(env)) env = env.name;
|
||||
if (!env) env = process.env.NODE_ENV || 'production';
|
||||
|
||||
|
@ -79,23 +103,21 @@ module.exports = class Config {
|
|||
);
|
||||
}
|
||||
|
||||
let results = Joi.validate(newConfig, this.schema, {
|
||||
context: context
|
||||
});
|
||||
let results = Joi.validate(newVals, this.getSchema(), { context });
|
||||
|
||||
if (results.error) {
|
||||
throw results.error;
|
||||
}
|
||||
|
||||
this.config = results.value;
|
||||
this[vals] = results.value;
|
||||
}
|
||||
|
||||
get(key) {
|
||||
if (!key) {
|
||||
return _.cloneDeep(this.config);
|
||||
return _.cloneDeep(this[vals]);
|
||||
}
|
||||
|
||||
let value = _.get(this.config, key);
|
||||
let value = _.get(this[vals], key);
|
||||
if (value === undefined) {
|
||||
if (!this.has(key)) {
|
||||
throw new Error('Unknown config key: ' + key);
|
||||
|
@ -130,6 +152,15 @@ module.exports = class Config {
|
|||
key = key.join('.');
|
||||
}
|
||||
|
||||
return !!has(key, this.schema);
|
||||
return !!has(key, this.getSchema());
|
||||
}
|
||||
|
||||
getSchema() {
|
||||
if (!this[schema]) {
|
||||
let objKeys = zipObject([...this[schemaKeys]]);
|
||||
this[schema] = Joi.object().keys(objKeys).default();
|
||||
}
|
||||
|
||||
return this[schema];
|
||||
}
|
||||
};
|
||||
|
|
|
@ -208,6 +208,24 @@ describe('lib/config/config', function () {
|
|||
|
||||
});
|
||||
|
||||
describe('#removeSchema(key)', function () {
|
||||
it('should completely remove the key', function () {
|
||||
var config = new Config(Joi.object().keys({
|
||||
a: Joi.number().default(1)
|
||||
}));
|
||||
|
||||
expect(config.get('a')).to.be(1);
|
||||
config.removeSchema('a');
|
||||
expect(() => config.get('a')).to.throwException('Unknown config key');
|
||||
});
|
||||
|
||||
it('only removes existing keys', function () {
|
||||
var config = new Config(Joi.object());
|
||||
|
||||
expect(() => config.removeSchema('b')).to.throwException('Unknown schema');
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -1,16 +1,11 @@
|
|||
module.exports = function (kbnServer, server, config) {
|
||||
let _ = require('lodash');
|
||||
|
||||
server.decorate('server', 'config', function () {
|
||||
return kbnServer.config;
|
||||
});
|
||||
|
||||
_.forOwn(config.unappliedDefaults, function (val, key) {
|
||||
if (val === null) return;
|
||||
server.log(['warning', 'config'], {
|
||||
tmpl: 'Settings for "<%= key %>" were not applied, check for spelling errors and ensure the plugin is loaded.',
|
||||
key: key,
|
||||
val: val
|
||||
});
|
||||
});
|
||||
let tmpl = 'Settings for "<%= key %>" were not applied, check for spelling errors and ensure the plugin is loaded.';
|
||||
for (let [key, val] of config.getPendingSets()) {
|
||||
server.log(['warning', 'config'], { key, val, tmpl });
|
||||
}
|
||||
};
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
module.exports = function (kbnServer, server, config) {
|
||||
let _ = require('lodash');
|
||||
let fs = require('fs');
|
||||
let Boom = require('boom');
|
||||
let Hapi = require('hapi');
|
||||
let parse = require('url').parse;
|
||||
|
@ -10,13 +11,23 @@ module.exports = function (kbnServer, server, config) {
|
|||
server = kbnServer.server = new Hapi.Server();
|
||||
|
||||
// Create a new connection
|
||||
server.connection({
|
||||
var connectionOptions = {
|
||||
host: config.get('server.host'),
|
||||
port: config.get('server.port'),
|
||||
routes: {
|
||||
cors: config.get('server.cors')
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// enable tls if ssl key and cert are defined
|
||||
if (config.get('server.ssl.key') && config.get('server.ssl.cert')) {
|
||||
connectionOptions.tls = {
|
||||
key: fs.readFileSync(config.get('server.ssl.key')),
|
||||
cert: fs.readFileSync(config.get('server.ssl.cert'))
|
||||
};
|
||||
}
|
||||
|
||||
server.connection(connectionOptions);
|
||||
|
||||
// provide a simple way to expose static directories
|
||||
server.decorate('server', 'exposeStaticDir', function (routePath, dirPath) {
|
||||
|
|
|
@ -14,7 +14,7 @@ module.exports = class KbnLogger {
|
|||
this.dest = process.stdout;
|
||||
} else {
|
||||
this.dest = writeStr(config.dest, {
|
||||
mode: 'a',
|
||||
flags: 'a',
|
||||
encoding: 'utf8'
|
||||
});
|
||||
}
|
||||
|
|
|
@ -33,10 +33,17 @@ module.exports = class Plugin {
|
|||
};
|
||||
}
|
||||
|
||||
async setupConfig() {
|
||||
let { config } = this.kbnServer;
|
||||
async readConfig() {
|
||||
let schema = await this.getConfigSchema(Joi);
|
||||
this.kbnServer.config.extendSchema(this.id, schema || defaultConfigSchema);
|
||||
let { config } = this.kbnServer;
|
||||
config.extendSchema(this.id, schema || defaultConfigSchema);
|
||||
|
||||
if (config.get([this.id, 'enabled'])) {
|
||||
return true;
|
||||
} else {
|
||||
config.removeSchema(this.id);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async init() {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
let _ = require('lodash');
|
||||
let { get, indexBy } = require('lodash');
|
||||
let inspect = require('util').inspect;
|
||||
|
||||
let PluginApi = require('./PluginApi');
|
||||
|
@ -14,22 +14,32 @@ module.exports = class Plugins extends Collection {
|
|||
}
|
||||
|
||||
async new(path) {
|
||||
var api = new PluginApi(this.kbnServer, path);
|
||||
let api = new PluginApi(this.kbnServer, path);
|
||||
let output = [].concat(require(path)(api) || []);
|
||||
let config = this.kbnServer.config;
|
||||
|
||||
if (!output.length) return;
|
||||
|
||||
// clear the byIdCache
|
||||
this[byIdCache] = null;
|
||||
|
||||
for (let product of output) {
|
||||
|
||||
if (product instanceof api.Plugin) {
|
||||
this[byIdCache] = null;
|
||||
this.add(product);
|
||||
await product.setupConfig();
|
||||
} else {
|
||||
throw new TypeError('unexpected plugin export ' + inspect(product));
|
||||
let plugin = product;
|
||||
this.add(plugin);
|
||||
|
||||
let enabled = await plugin.readConfig();
|
||||
if (!enabled) this.delete(plugin);
|
||||
continue;
|
||||
}
|
||||
|
||||
throw new TypeError('unexpected plugin export ' + inspect(product));
|
||||
}
|
||||
}
|
||||
|
||||
get byId() {
|
||||
return this[byIdCache] || (this[byIdCache] = _.indexBy([...this], 'id'));
|
||||
return this[byIdCache] || (this[byIdCache] = indexBy([...this], 'id'));
|
||||
}
|
||||
|
||||
};
|
||||
|
|
|
@ -7,18 +7,10 @@ module.exports = async function (kbnServer, server, config) {
|
|||
}
|
||||
|
||||
let { plugins } = kbnServer;
|
||||
let enabledPlugins = {};
|
||||
|
||||
// setup config and filter out disabled plugins
|
||||
for (let plugin of plugins) {
|
||||
if (config.get([plugin.id, 'enabled'])) {
|
||||
enabledPlugins[plugin.id] = plugin;
|
||||
}
|
||||
}
|
||||
|
||||
let path = [];
|
||||
let initialize = async id => {
|
||||
let plugin = enabledPlugins[id];
|
||||
|
||||
async function initialize(id) {
|
||||
let plugin = plugins.byId[id];
|
||||
|
||||
if (includes(path, id)) {
|
||||
throw new Error(`circular dependencies found: "${path.concat(id).join(' -> ')}"`);
|
||||
|
@ -27,13 +19,10 @@ module.exports = async function (kbnServer, server, config) {
|
|||
path.push(id);
|
||||
|
||||
for (let reqId of plugin.requiredIds) {
|
||||
if (!enabledPlugins[reqId]) {
|
||||
if (plugins.byId[reqId]) {
|
||||
throw new Error(`Requirement "${reqId}" for plugin "${plugin.id}" is disabled.`);
|
||||
} else {
|
||||
throw new Error(`Unmet requirement "${reqId}" for plugin "${plugin.id}"`);
|
||||
}
|
||||
if (!plugins.byId[reqId]) {
|
||||
throw new Error(`Unmet requirement "${reqId}" for plugin "${id}"`);
|
||||
}
|
||||
|
||||
await initialize(reqId);
|
||||
}
|
||||
|
||||
|
@ -42,5 +31,7 @@ module.exports = async function (kbnServer, server, config) {
|
|||
path.pop();
|
||||
};
|
||||
|
||||
for (let id of keys(enabledPlugins)) await initialize(id);
|
||||
for (let {id} of plugins) {
|
||||
await initialize(id);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -53,7 +53,6 @@ module.exports = async (kbnServer, server, config) => {
|
|||
continue;
|
||||
}
|
||||
|
||||
require(modulePath);
|
||||
await plugins.new(path);
|
||||
debug({ tmpl: 'Found plugin at <%= path %>', path: modulePath });
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,27 +1,12 @@
|
|||
module.exports = function (kbnServer, server, config) {
|
||||
var _ = require('lodash');
|
||||
var Samples = require('./Samples');
|
||||
var ServerStatus = require('./ServerStatus');
|
||||
var { join } = require('path');
|
||||
|
||||
kbnServer.status = new ServerStatus(kbnServer.server);
|
||||
kbnServer.metrics = new Samples(60);
|
||||
|
||||
if (server.plugins.good) {
|
||||
server.plugins.good.monitor.on('ops', function (event) {
|
||||
var port = config.get('server.port');
|
||||
kbnServer.metrics.add({
|
||||
rss: event.psmem.rss,
|
||||
heapTotal: event.psmem.heapTotal,
|
||||
heapUsed: event.psmem.heapUsed,
|
||||
load: event.osload,
|
||||
delay: event.psdelay,
|
||||
concurrency: _.get(event, ['concurrents', port]),
|
||||
responseTimeAvg: _.get(event, ['responseTimes', port, 'avg']),
|
||||
responseTimeMax: _.get(event, ['responseTimes', port, 'max']),
|
||||
requests: _.get(event, ['requests', port, 'total'], 0)
|
||||
});
|
||||
});
|
||||
kbnServer.mixin(require('./metrics'));
|
||||
}
|
||||
|
||||
server.route({
|
||||
|
|
27
src/server/status/metrics.js
Normal file
27
src/server/status/metrics.js
Normal file
|
@ -0,0 +1,27 @@
|
|||
module.exports = function (kbnServer, server, config) {
|
||||
var _ = require('lodash');
|
||||
var Samples = require('./Samples');
|
||||
let lastReport = Date.now();
|
||||
|
||||
kbnServer.metrics = new Samples(12);
|
||||
|
||||
server.plugins.good.monitor.on('ops', function (event) {
|
||||
let now = Date.now();
|
||||
let secSinceLast = (now - lastReport) / 1000;
|
||||
lastReport = now;
|
||||
|
||||
var port = config.get('server.port');
|
||||
let requests = _.get(event, ['requests', port, 'total'], 0);
|
||||
let requestsPerSecond = requests / secSinceLast;
|
||||
|
||||
kbnServer.metrics.add({
|
||||
heapTotal: _.get(event, 'psmem.heapTotal'),
|
||||
heapUsed: _.get(event, 'psmem.heapUsed'),
|
||||
load: event.osload,
|
||||
responseTimeAvg: _.get(event, ['responseTimes', port, 'avg']),
|
||||
responseTimeMax: _.get(event, ['responseTimes', port, 'max']),
|
||||
requestsPerSecond: requestsPerSecond
|
||||
});
|
||||
|
||||
});
|
||||
};
|
|
@ -28,13 +28,13 @@ class UiApp {
|
|||
}
|
||||
|
||||
getModules() {
|
||||
return _([
|
||||
return _.chain([
|
||||
this.autoloadOverrides || autoload.require,
|
||||
this.uiExports.find(_.get(this, 'spec.uses', [])),
|
||||
])
|
||||
.flatten()
|
||||
.uniq()
|
||||
.push(this.main)
|
||||
.unshift(this.main)
|
||||
.value();
|
||||
}
|
||||
|
||||
|
|
|
@ -6,7 +6,14 @@ let fromRoot = require('../utils/fromRoot');
|
|||
let asRegExp = flow(
|
||||
escapeRegExp,
|
||||
function (path) {
|
||||
return path + '(?:\\.js)?$';
|
||||
let last = path.slice(-1);
|
||||
if (last === '/' || last === '\\') {
|
||||
// match a directory explicitly
|
||||
return path + '.*';
|
||||
} else {
|
||||
// match a directory or files or just the absolute path
|
||||
return path + '(?:\\.js$|$|\\\\|\\/)?';
|
||||
}
|
||||
},
|
||||
RegExp
|
||||
);
|
||||
|
@ -31,7 +38,10 @@ module.exports = class UiBundlerEnv {
|
|||
this.pluginInfo = [];
|
||||
|
||||
// regular expressions which will prevent webpack from parsing the file
|
||||
this.noParse = [];
|
||||
this.noParse = [
|
||||
/node_modules[\/\\](angular|elasticsearch-browser)[\/\\]/,
|
||||
/node_modules[\/\\](angular-nvd3|mocha|moment)[\/\\]/
|
||||
];
|
||||
|
||||
// webpack aliases, like require paths, mapping a prefix to a directory
|
||||
this.aliases = {
|
||||
|
@ -44,6 +54,7 @@ module.exports = class UiBundlerEnv {
|
|||
|
||||
// webpack loaders map loader configuration to regexps
|
||||
this.loaders = [];
|
||||
this.postLoaders = [];
|
||||
}
|
||||
|
||||
consumePlugin(plugin) {
|
||||
|
@ -64,6 +75,11 @@ module.exports = class UiBundlerEnv {
|
|||
for (let loader of arr(spec)) this.addLoader(loader);
|
||||
};
|
||||
|
||||
case 'postLoaders':
|
||||
return (plugin, spec) => {
|
||||
for (let loader of arr(spec)) this.addPostLoader(loader);
|
||||
};
|
||||
|
||||
case 'noParse':
|
||||
return (plugin, spec) => {
|
||||
for (let re of arr(spec)) this.addNoParse(re);
|
||||
|
@ -84,6 +100,10 @@ module.exports = class UiBundlerEnv {
|
|||
this.loaders.push(loader);
|
||||
}
|
||||
|
||||
addPostLoader(loader) {
|
||||
this.postLoaders.push(loader);
|
||||
}
|
||||
|
||||
addNoParse(regExp) {
|
||||
this.noParse.push(regExp);
|
||||
}
|
||||
|
@ -129,7 +149,7 @@ module.exports = class UiBundlerEnv {
|
|||
if (exports) loader.push(`exports?${exports}`);
|
||||
if (expose) loader.push(`expose?${expose}`);
|
||||
if (loader.length) this.loaders.push({ test: asRegExp(path), loader: loader.join('!') });
|
||||
if (!parse) this.noParse.push(asRegExp(path));
|
||||
if (!parse) this.addNoParse(path);
|
||||
}
|
||||
|
||||
claim(id, pluginId) {
|
||||
|
|
|
@ -260,7 +260,8 @@ define(function (require) {
|
|||
|
||||
AggConfig.prototype.makeLabel = function () {
|
||||
if (!this.type) return '';
|
||||
return this.type.makeLabel(this);
|
||||
var pre = (_.get(this.vis, 'params.mode') === 'percentage') ? 'Percentage of ' : '';
|
||||
return pre += this.type.makeLabel(this);
|
||||
};
|
||||
|
||||
AggConfig.prototype.field = function () {
|
||||
|
|
|
@ -223,7 +223,10 @@ describe('buildHierarchicalData', function () {
|
|||
type: 'pie',
|
||||
aggs: [
|
||||
{ type: 'count', schema: 'metric' },
|
||||
{ type: 'filters', schema: 'segment', params: {
|
||||
{
|
||||
type: 'filters',
|
||||
schema: 'segment',
|
||||
params: {
|
||||
filters: [
|
||||
{ input: { query: { query_string: { query: '_type:apache' } } } },
|
||||
{ input: { query: { query_string: { query: '_type:nginx' } } } }
|
||||
|
@ -256,7 +259,10 @@ describe('buildHierarchicalData', function () {
|
|||
type: 'pie',
|
||||
aggs: [
|
||||
{ type: 'count', schema: 'metric' },
|
||||
{ type: 'filters', schema: 'split', params: {
|
||||
{
|
||||
type: 'filters',
|
||||
schema: 'split',
|
||||
params: {
|
||||
filters: [
|
||||
{ input: { query: { query_string: { query: '_type:apache' } } } },
|
||||
{ input: { query: { query_string: { query: '_type:nginx' } } } }
|
||||
|
|
|
@ -38,8 +38,7 @@ describe('AggConfig Filters', function () {
|
|||
expect(filter.range).to.have.property('bytes');
|
||||
expect(filter.range.bytes).to.have.property('gte', 2048);
|
||||
expect(filter.range.bytes).to.have.property('lt', 3072);
|
||||
|
||||
expect(filter.meta).to.have.property('formattedValue', '2,048');
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
|
|
@ -41,7 +41,7 @@ describe('AggConfig Filters', function () {
|
|||
expect(filter.range).to.have.property('bytes');
|
||||
expect(filter.range.bytes).to.have.property('gte', 1024.0);
|
||||
expect(filter.range.bytes).to.have.property('lt', 2048.0);
|
||||
expect(filter.meta).to.have.property('formattedValue', '1,024 to 2,048');
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
|
|
@ -5,10 +5,12 @@ define(function (require) {
|
|||
return function (aggConfig, key) {
|
||||
var value = parseInt(key, 10);
|
||||
|
||||
return buildRangeFilter(aggConfig.params.field, {
|
||||
gte: value,
|
||||
lt: value + aggConfig.params.interval
|
||||
}, aggConfig.vis.indexPattern);
|
||||
return buildRangeFilter(
|
||||
aggConfig.params.field,
|
||||
{gte: value, lt: value + aggConfig.params.interval},
|
||||
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) {
|
||||
|
|
|
@ -12,7 +12,7 @@ var parse = _.wrap(require('url').parse, function (parse, path) {
|
|||
|
||||
function TabCollection() {
|
||||
|
||||
var tabs = null;
|
||||
var tabs = [];
|
||||
var specs = null;
|
||||
var defaults = null;
|
||||
var activeTab = null;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<kbn-notifications list="notifList"></kbn-notifications>
|
||||
<div class="content" style="display: none;" chrome-context >
|
||||
<div class="content" chrome-context >
|
||||
<nav
|
||||
ng-style="{ background: chrome.getNavBackground() }"
|
||||
ng-class="{ show: chrome.getVisible() }"
|
||||
|
|
|
@ -42,7 +42,6 @@ require('./api/theme')(chrome, internals);
|
|||
chrome.bootstrap = function () {
|
||||
chrome.setupAngular();
|
||||
angular.bootstrap(document, ['kibana']);
|
||||
$(document.body).children(':not(style-compile)').show();
|
||||
};
|
||||
|
||||
module.exports = chrome;
|
||||
|
|
|
@ -31,8 +31,9 @@ define(function () {
|
|||
']',
|
||||
description: 'Values that define the format used in situations where timebased' +
|
||||
' data is rendered in order, and formatted timestamps should adapt to the' +
|
||||
' interval between measurements. Keys are ISO 8601 intervals:' +
|
||||
' http://en.wikipedia.org/wiki/ISO_8601#Time_intervals'
|
||||
' interval between measurements. Keys are' +
|
||||
' <a href="http://en.wikipedia.org/wiki/ISO_8601#Time_intervals" target="_blank">' +
|
||||
'ISO8601 intervals.</a>'
|
||||
},
|
||||
'defaultIndex': {
|
||||
value: null,
|
||||
|
@ -71,8 +72,10 @@ define(function () {
|
|||
'visualization:tileMap:maxPrecision': {
|
||||
value: 7,
|
||||
description: 'The maximum geoHash precision displayed on tile maps: 7 is high, 10 is very high, ' +
|
||||
'12 is the max. Explanation of cell dimensions: http://www.elastic.co/guide/en/elasticsearch/reference/current/' +
|
||||
'search-aggregations-bucket-geohashgrid-aggregation.html#_cell_dimensions_at_the_equator',
|
||||
'12 is the max. ' +
|
||||
'<a href="http://www.elastic.co/guide/en/elasticsearch/reference/current/' +
|
||||
'search-aggregations-bucket-geohashgrid-aggregation.html#_cell_dimensions_at_the_equator" target="_blank">' +
|
||||
'Explanation of cell dimensions.</a>',
|
||||
},
|
||||
'csv:separator': {
|
||||
value: ',',
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -62,6 +62,7 @@
|
|||
readonly
|
||||
ui-ace="{
|
||||
useWrapMode: true,
|
||||
onLoad: aceLoaded,
|
||||
advanced: {
|
||||
highlightActiveLine: false
|
||||
},
|
||||
|
|
|
@ -17,24 +17,31 @@ define(function (require) {
|
|||
filter: '=?',
|
||||
columns: '=?'
|
||||
},
|
||||
link: function ($scope, $el, attr) {
|
||||
// If a field isn't in the mapping, use this
|
||||
$scope.mode = 'table';
|
||||
$scope.mapping = $scope.indexPattern.fields.byName;
|
||||
$scope.flattened = $scope.indexPattern.flattenHit($scope.hit);
|
||||
$scope.hitJson = angular.toJson($scope.hit, true);
|
||||
$scope.formatted = $scope.indexPattern.formatHit($scope.hit);
|
||||
$scope.fields = _.keys($scope.flattened).sort();
|
||||
link: {
|
||||
pre($scope) {
|
||||
$scope.aceLoaded = (editor) => {
|
||||
editor.$blockScrolling = Infinity;
|
||||
};
|
||||
},
|
||||
|
||||
$scope.toggleColumn = function (fieldName) {
|
||||
_.toggleInOut($scope.columns, fieldName);
|
||||
};
|
||||
post($scope, $el, attr) {
|
||||
// If a field isn't in the mapping, use this
|
||||
$scope.mode = 'table';
|
||||
$scope.mapping = $scope.indexPattern.fields.byName;
|
||||
$scope.flattened = $scope.indexPattern.flattenHit($scope.hit);
|
||||
$scope.hitJson = angular.toJson($scope.hit, true);
|
||||
$scope.formatted = $scope.indexPattern.formatHit($scope.hit);
|
||||
$scope.fields = _.keys($scope.flattened).sort();
|
||||
|
||||
$scope.showArrayInObjectsWarning = function (row, field) {
|
||||
var value = $scope.flattened[field];
|
||||
return _.isArray(value) && typeof value[0] === 'object';
|
||||
};
|
||||
$scope.toggleColumn = function (fieldName) {
|
||||
_.toggleInOut($scope.columns, fieldName);
|
||||
};
|
||||
|
||||
$scope.showArrayInObjectsWarning = function (row, field) {
|
||||
var value = $scope.flattened[field];
|
||||
return _.isArray(value) && typeof value[0] === 'object';
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
|
|
|
@ -42,5 +42,26 @@ describe('Filter Bar Directive', function () {
|
|||
$rootScope.$apply();
|
||||
});
|
||||
|
||||
it('should return a value for a range/histogram filter from a scripted field', (done) => {
|
||||
let filter = {
|
||||
meta: {
|
||||
index: 'logstash-*',
|
||||
formattedValue: '1,000.00 to 2,000.00',
|
||||
field: 'script number'
|
||||
},
|
||||
script: {
|
||||
params: {
|
||||
gte: 1000,
|
||||
lt: 2000,
|
||||
value: '>=1,000.00 <2,000.00'
|
||||
}
|
||||
}
|
||||
};
|
||||
mapScript(filter).then((result) => {
|
||||
expect(result).to.have.property('value', filter.meta.formattedValue);
|
||||
done();
|
||||
});
|
||||
$rootScope.$apply();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
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);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -70,11 +70,11 @@ module.exports = function (grunt) {
|
|||
grunt.log.ok(`downloading ${platform.name} - ${mb} mb`);
|
||||
};
|
||||
|
||||
grunt.registerTask('_build:downloadNodes:start', function () {
|
||||
grunt.registerTask('_build:downloadNodeBuilds:start', function () {
|
||||
map(platforms, start).nodeify(this.async());
|
||||
});
|
||||
|
||||
grunt.registerTask('_build:downloadNodes:finish', function () {
|
||||
grunt.registerTask('_build:downloadNodeBuilds:finish', function () {
|
||||
map(activeDownloads, async (platform) => {
|
||||
await platform.downloadPromise;
|
||||
grunt.log.ok(`${platform.name} download complete`);
|
|
@ -2,22 +2,24 @@ module.exports = function (grunt) {
|
|||
let { flatten } = require('lodash');
|
||||
|
||||
grunt.registerTask('build', flatten([
|
||||
'_build:shrinkwrap:ensureExists:true',
|
||||
'_build:getProps',
|
||||
'clean:build',
|
||||
'clean:target',
|
||||
'_build:downloadNodes:start',
|
||||
'_build:downloadNodeBuilds:start',
|
||||
'copy:devSource',
|
||||
'babel:build',
|
||||
'_build:cliIndex',
|
||||
'_build:installedPlugins',
|
||||
'_build:packageJson',
|
||||
'_build:readme',
|
||||
'_build:shrinkwrap:copyToBuild',
|
||||
'_build:shrinkwrap:cleanup',
|
||||
'_build:installNpmDeps',
|
||||
'clean:testsFromModules',
|
||||
'clean:deepModules',
|
||||
'run:optimizeBuild',
|
||||
'stop:optimizeBuild',
|
||||
'_build:downloadNodes:finish',
|
||||
'_build:downloadNodeBuilds:finish',
|
||||
'_build:versionedLinks',
|
||||
'_build:archives',
|
||||
!grunt.option('os-packages') ? [] : [
|
||||
|
|
|
@ -2,7 +2,6 @@ module.exports = function (grunt) {
|
|||
let { defaults } = require('lodash');
|
||||
|
||||
let pkg = grunt.config.get('pkg');
|
||||
let deepModules = grunt.config.get('deepModules');
|
||||
|
||||
grunt.registerTask('_build:packageJson', function () {
|
||||
|
||||
|
@ -18,7 +17,7 @@ module.exports = function (grunt) {
|
|||
sha: grunt.config.get('buildSha')
|
||||
},
|
||||
repository: pkg.repository,
|
||||
dependencies: defaults({}, pkg.dependencies, deepModules)
|
||||
dependencies: pkg.dependencies
|
||||
}, null, ' ')
|
||||
);
|
||||
});
|
||||
|
|
41
tasks/build/shrinkwrap.js
Normal file
41
tasks/build/shrinkwrap.js
Normal file
|
@ -0,0 +1,41 @@
|
|||
module.exports = function (grunt) {
|
||||
let { config } = grunt;
|
||||
let { statSync } = require('fs');
|
||||
let { join } = require('path');
|
||||
let exec = (...args) => require('../utils/exec')(...args, { cwd: config.get('root') });
|
||||
let newFiles = [];
|
||||
let shrinkwrapFile = join(config.get('root'), 'npm-shrinkwrap.json');
|
||||
|
||||
grunt.registerTask('_build:shrinkwrap:ensureExists', function (createIfMissing) {
|
||||
try {
|
||||
statSync(shrinkwrapFile);
|
||||
} catch (e) {
|
||||
if (e.code !== 'ENOENT') throw e;
|
||||
|
||||
if (createIfMissing) {
|
||||
exec('npm', ['shrinkwrap', '--dev', '--logLevel', 'error']);
|
||||
newFiles.push(shrinkwrapFile);
|
||||
}
|
||||
else grunt.fail.warn('Releases require an npm-shrinkwrap.json file to exist');
|
||||
}
|
||||
});
|
||||
|
||||
grunt.registerTask('_build:shrinkwrap:copyToBuild', function () {
|
||||
// this.requires(['_build:shrinkwrap:ensureExists', 'copy:devSource']);
|
||||
|
||||
// backup shrinkwrap and copy to build
|
||||
exec('cp', ['npm-shrinkwrap.json', 'npm-shrinkwrap.dev']);
|
||||
exec('cp', ['npm-shrinkwrap.json', join(config.get('root'), 'build', 'kibana', 'npm-shrinkwrap.build.json')]);
|
||||
|
||||
// create shrinkwrap without dev dependencies and copy to build
|
||||
exec('npm', ['shrinkwrap', '--logLevel', 'error']);
|
||||
exec('cp', ['npm-shrinkwrap.json', join(config.get('root'), 'build', 'kibana', 'npm-shrinkwrap.json')]);
|
||||
|
||||
// restore the dev shrinkwrap
|
||||
exec('mv', ['npm-shrinkwrap.dev', 'npm-shrinkwrap.json']);
|
||||
});
|
||||
|
||||
grunt.registerTask('_build:shrinkwrap:cleanup', function () {
|
||||
if (newFiles.length) exec('rm', newFiles.splice(0));
|
||||
});
|
||||
};
|
|
@ -3,9 +3,7 @@ let babelOptions = require('requirefrom')('src')('optimize/babelOptions');
|
|||
|
||||
module.exports = {
|
||||
build: {
|
||||
options: defaults({
|
||||
optional: ['runtime']
|
||||
}, babelOptions),
|
||||
options: babelOptions.node,
|
||||
src: [
|
||||
'build/kibana/**/*.js',
|
||||
'!**/public/**',
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
module.exports = function (grunt) {
|
||||
let modules = Object.keys(grunt.config.get('deepModules'));
|
||||
return {
|
||||
build: 'build',
|
||||
target: 'target',
|
||||
testsFromModules: 'build/kibana/node_modules/**/*test*/**',
|
||||
deepModules: 'build/kibana/node_modules/*/node_modules/**/{' + modules.join(',') + '}/**'
|
||||
testsFromModules: 'build/kibana/node_modules/**/*test*/**'
|
||||
};
|
||||
};
|
||||
|
|
|
@ -5,6 +5,7 @@ module.exports = function (grunt) {
|
|||
src: [
|
||||
'src/**',
|
||||
'bin/**',
|
||||
'webpackShims/**',
|
||||
'config/kibana.yml',
|
||||
'!src/**/__tests__/**',
|
||||
'!src/testUtils/**',
|
||||
|
|
|
@ -1,12 +1,54 @@
|
|||
module.exports = function (grunt) {
|
||||
return {
|
||||
unit: {
|
||||
configFile: 'karma.conf.js',
|
||||
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 },
|
||||
coverage: {
|
||||
singleRun: true,
|
||||
reporters: 'dots',
|
||||
browsers: [
|
||||
'<%= karmaBrowser %>'
|
||||
]
|
||||
reporters: ['coverage'],
|
||||
coverageReporter: {
|
||||
reporters: [
|
||||
{ type: 'html', dir: 'coverage' },
|
||||
{ type: 'text-summary' },
|
||||
]
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
|
|
@ -45,7 +45,6 @@ module.exports = function (grunt) {
|
|||
'inherits@1.0.0': ['ISC'],
|
||||
'jsonpointer@1.1.0': ['MIT'],
|
||||
'leaflet@0.7.2': ['BSD-2-Clause'],
|
||||
'moment-timezone@0.0.6': ['MIT'],
|
||||
'Nonsense@0.1.2': ['Public-Domain'],
|
||||
'pkginfo@0.2.3': ['MIT'],
|
||||
'uglify-js@2.2.5': ['BSD'],
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
module.exports = function (grunt) {
|
||||
let platform = require('os').platform();
|
||||
let {resolve} = require('path');
|
||||
let root = p => resolve(__dirname, '../../', p);
|
||||
|
||||
|
@ -10,12 +11,51 @@ module.exports = function (grunt) {
|
|||
quiet: false,
|
||||
failOnError: false
|
||||
},
|
||||
cmd: './bin/kibana',
|
||||
cmd: /^win/.test(platform) ? '.\\bin\\kibana.bat' : './bin/kibana',
|
||||
args: [
|
||||
'--server.port=5610',
|
||||
'--env.name=development',
|
||||
'--logging.json=false',
|
||||
'--optimize.tests=true',
|
||||
'--optimize.lazy=false'
|
||||
'--optimize.bundleFilter=tests',
|
||||
'--plugins.initialize=false'
|
||||
]
|
||||
},
|
||||
|
||||
testCoverageServer: {
|
||||
options: {
|
||||
wait: false,
|
||||
ready: /Server running/,
|
||||
quiet: false,
|
||||
failOnError: false
|
||||
},
|
||||
cmd: /^win/.test(platform) ? '.\\bin\\kibana.bat' : './bin/kibana',
|
||||
args: [
|
||||
'--server.port=5610',
|
||||
'--env.name=development',
|
||||
'--logging.json=false',
|
||||
'--optimize.bundleFilter=tests',
|
||||
'--plugins.initialize=false',
|
||||
'--testsBundle.instrument=true'
|
||||
]
|
||||
},
|
||||
|
||||
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,9 +1,9 @@
|
|||
module.exports = function (grunt) {
|
||||
|
||||
var readline = require('readline');
|
||||
|
||||
// build, then zip and upload to s3
|
||||
grunt.registerTask('release', [
|
||||
'_build:shrinkwrap:ensureExists',
|
||||
'_release:confirmUpload',
|
||||
'_release:loadS3Config',
|
||||
'build',
|
||||
|
|
|
@ -1,29 +1,27 @@
|
|||
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:coverage', [ 'run:testCoverageServer', 'karma:coverage' ]);
|
||||
|
||||
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
|
||||
};
|
||||
|
|
5
webpackShims/angular-nvd3.js
vendored
Normal file
5
webpackShims/angular-nvd3.js
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
require('d3');
|
||||
require('@spalger/nvd3/build/nv.d3.css');
|
||||
require('@spalger/nvd3/build/nv.d3.js');
|
||||
require('@spalger/angular-nvd3/dist/angular-nvd3.min.js');
|
||||
module.exports = window.nv;
|
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