diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 19dffe7114a1..b1123f51b10c 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -55,7 +55,7 @@ Please make sure you have signed the [Contributor License Agreement](http://www.
npm run elasticsearch
```
-- Start the development server.
+- Start the development server. _On Windows, you'll need you use Git Bash, Cygwin, or a similar shell that exposes the `sh` command._
```sh
npm start
@@ -146,7 +146,8 @@ Run the tests for just your particular plugin. Assuming you plugin lives outside
#### Running browser automation tests:
-*The Selenium server that is started currently only runs the tests in Firefox*
+*The Selenium server that is started currently only runs the tests in a recent version of Firefox.*
+*You can use the `PATH` environment variable to specify which version of Firefox to use.*
The following will start Kibana, Elasticsearch and Selenium for you. To run the functional UI tests use the following commands
@@ -177,7 +178,7 @@ npm run test:ui:runner
- These tests have been developed and tested with Chrome and Firefox browser. In theory, they should work on all browsers (that's the benefit of Intern using Leadfoot).
- These tests should also work with an external testing service like https://saucelabs.com/ or https://www.browserstack.com/ but that has not been tested.
- https://theintern.github.io/
-- https://theintern.github.io/leadfoot/Element.html
+- https://theintern.github.io/leadfoot/module-leadfoot_Element.html
#### Building OS packages
diff --git a/package.json b/package.json
index 4fcc9db19f0b..bca8b93a9fbe 100644
--- a/package.json
+++ b/package.json
@@ -49,7 +49,7 @@
"test:coverage": "grunt test:coverage",
"build": "grunt build",
"build:ospackages": "grunt build --os-packages",
- "start": "./bin/kibana --dev",
+ "start": "sh ./bin/kibana --dev",
"precommit": "grunt precommit",
"karma": "karma start",
"elasticsearch": "grunt esvm:dev:keepalive",
@@ -180,6 +180,7 @@
"makelogs": "3.0.0-beta3",
"marked-text-renderer": "0.1.0",
"mocha": "2.3.0",
+ "ncp": "2.0.0",
"nock": "2.10.0",
"npm": "2.11.0",
"portscanner": "1.0.0",
diff --git a/src/cli/serve/read_yaml_config.js b/src/cli/serve/read_yaml_config.js
index 8ef3acff942f..eda24281d245 100644
--- a/src/cli/serve/read_yaml_config.js
+++ b/src/cli/serve/read_yaml_config.js
@@ -48,7 +48,14 @@ module.exports = function (path) {
_.forOwn(val, function (subVal, subKey) {
apply(config, subVal, key + '.' + subKey);
});
- } else {
+ }
+ else if (_.isArray(val)) {
+ config[key] = [];
+ val.forEach((subVal, i) => {
+ apply(config, subVal, key + '.' + i);
+ });
+ }
+ else {
_.set(config, key, val);
}
}
diff --git a/src/plugins/kibana/server/lib/__tests__/create_mappings_from_pattern_fields.js b/src/plugins/kibana/server/lib/__tests__/create_mappings_from_pattern_fields.js
index cf4563458ece..7444d3838463 100644
--- a/src/plugins/kibana/server/lib/__tests__/create_mappings_from_pattern_fields.js
+++ b/src/plugins/kibana/server/lib/__tests__/create_mappings_from_pattern_fields.js
@@ -39,21 +39,21 @@ describe('createMappingsFromPatternFields', function () {
let mappings = createMappingsFromPatternFields(testFields);
_.forEach(mappings, function (mapping) {
- if (mapping.type !== 'string') {
+ if (mapping.type !== 'text') {
expect(_.isEqual(mapping, {
type: mapping.type,
- index: 'not_analyzed',
+ index: true,
doc_values: true
})).to.be.ok();
}
});
});
- it('should give strings a multi-field mapping', function () {
+ it('should give strings a multi-field mapping with a "text" base type', function () {
let mappings = createMappingsFromPatternFields(testFields);
_.forEach(mappings, function (mapping) {
- if (mapping.type === 'string') {
+ if (mapping.type === 'text') {
expect(mapping).to.have.property('fields');
}
});
@@ -68,7 +68,7 @@ describe('createMappingsFromPatternFields', function () {
expect(mappings.geo.properties).to.have.property('coordinates');
expect(_.isEqual(mappings.geo.properties.coordinates, {
type: 'geo_point',
- index: 'not_analyzed',
+ index: true,
doc_values: true
})).to.be.ok();
});
diff --git a/src/plugins/kibana/server/lib/create_mappings_from_pattern_fields.js b/src/plugins/kibana/server/lib/create_mappings_from_pattern_fields.js
index d05e65099161..b9ee189e35c4 100644
--- a/src/plugins/kibana/server/lib/create_mappings_from_pattern_fields.js
+++ b/src/plugins/kibana/server/lib/create_mappings_from_pattern_fields.js
@@ -13,10 +13,9 @@ module.exports = function createMappingsFromPatternFields(fields) {
if (field.type === 'string') {
mapping = {
- type: 'string',
- index: 'analyzed',
+ type: 'text',
fields: {
- raw: {type: 'string', index: 'not_analyzed', doc_values: true, ignore_above: 256}
+ raw: {type: 'keyword', ignore_above: 256}
}
};
}
@@ -24,7 +23,7 @@ module.exports = function createMappingsFromPatternFields(fields) {
const fieldType = field.type === 'number' ? 'double' : field.type;
mapping = {
type: fieldType,
- index: 'not_analyzed',
+ index: true,
doc_values: true
};
}
diff --git a/src/plugins/kibana/server/routes/api/ingest/register_post.js b/src/plugins/kibana/server/routes/api/ingest/register_post.js
index b20594f1ccce..f1bd1ab09c7d 100644
--- a/src/plugins/kibana/server/routes/api/ingest/register_post.js
+++ b/src/plugins/kibana/server/routes/api/ingest/register_post.js
@@ -101,10 +101,9 @@ module.exports = function registerPost(server) {
match: '*',
match_mapping_type: 'string',
mapping: {
- type: 'string',
- index: 'analyzed',
+ type: 'text',
fields: {
- raw: {type: 'string', index: 'not_analyzed', doc_values: true, ignore_above: 256}
+ raw: {type: 'keyword', ignore_above: 256}
}
}
}
diff --git a/src/server/status/__tests__/status.js b/src/server/status/__tests__/status.js
index ebac541ac96e..bb550820a0ad 100644
--- a/src/server/status/__tests__/status.js
+++ b/src/server/status/__tests__/status.js
@@ -4,7 +4,6 @@ import Status from '../status';
import ServerStatus from '../server_status';
describe('Status class', function () {
-
var server;
var serverStatus;
@@ -59,6 +58,34 @@ describe('Status class', function () {
expect(json.message).to.eql('Ready');
});
+ it('should call on handler if status is already matched', function (done) {
+ var status = serverStatus.create('test');
+ var msg = 'Test Ready';
+ status.green(msg);
+
+ status.on('green', function (prev, prevMsg) {
+ expect(arguments.length).to.equal(2);
+ expect(prev).to.be('green');
+ expect(prevMsg).to.be(msg);
+ expect(status.message).to.equal(msg);
+ done();
+ });
+ });
+
+ it('should call once handler if status is already matched', function (done) {
+ var status = serverStatus.create('test');
+ var msg = 'Test Ready';
+ status.green(msg);
+
+ status.once('green', function (prev, prevMsg) {
+ expect(arguments.length).to.equal(2);
+ expect(prev).to.be('green');
+ expect(prevMsg).to.be(msg);
+ expect(status.message).to.equal(msg);
+ done();
+ });
+ });
+
function testState(color) {
it(`should change the state to ${color} when #${color}() is called`, function () {
var status = serverStatus.create('test');
diff --git a/src/server/status/status.js b/src/server/status/status.js
index cc7f0162aa9d..929118d08512 100644
--- a/src/server/status/status.js
+++ b/src/server/status/status.js
@@ -36,6 +36,22 @@ class Status extends EventEmitter {
since: this.since
};
}
+
+ on(eventName, handler) {
+ super.on(eventName, handler);
+
+ if (eventName === this.state) {
+ setImmediate(() => handler(this.state, this.message));
+ }
+ }
+
+ once(eventName, handler) {
+ if (eventName === this.state) {
+ setImmediate(() => handler(this.state, this.message));
+ } else {
+ super.once(eventName, handler);
+ }
+ }
}
states.all.forEach(function (state) {
diff --git a/src/ui/public/chrome/api/__tests__/nav.js b/src/ui/public/chrome/api/__tests__/nav.js
index e3c89deedd60..2161c63d6ce7 100644
--- a/src/ui/public/chrome/api/__tests__/nav.js
+++ b/src/ui/public/chrome/api/__tests__/nav.js
@@ -36,5 +36,10 @@ describe('chrome nav apis', function () {
const chrome = getChrome();
expect(chrome.addBasePath('http://github.com/elastic/kibana')).to.be('http://github.com/elastic/kibana');
});
+
+ it('includes the query string', function () {
+ const chrome = getChrome();
+ expect(chrome.addBasePath('/app/kibana?a=b')).to.be(`${basePath}/app/kibana?a=b`);
+ });
});
});
diff --git a/src/ui/public/chrome/api/nav.js b/src/ui/public/chrome/api/nav.js
index 297df1543be3..0b630a2eccd1 100644
--- a/src/ui/public/chrome/api/nav.js
+++ b/src/ui/public/chrome/api/nav.js
@@ -18,7 +18,7 @@ export default function (chrome, internals) {
var isUrl = url && isString(url);
if (!isUrl) return url;
- var parsed = parse(url);
+ var parsed = parse(url, true);
if (!parsed.host && parsed.pathname) {
if (parsed.pathname[0] === '/') {
parsed.pathname = chrome.getBasePath() + parsed.pathname;
diff --git a/src/ui/public/notify/__tests__/notifier.js b/src/ui/public/notify/__tests__/notifier.js
index ed2df33aeede..a7d767e979d4 100644
--- a/src/ui/public/notify/__tests__/notifier.js
+++ b/src/ui/public/notify/__tests__/notifier.js
@@ -43,8 +43,8 @@ describe('Notifier', function () {
expect(notify('error').title).to.equal('Error');
});
- it('sets lifetime to Infinity', function () {
- expect(notify('error').lifetime).to.equal(Infinity);
+ it('sets lifetime to 5 minutes', function () {
+ expect(notify('error').lifetime).to.equal(300000);
});
it('allows reporting', function () {
diff --git a/src/ui/public/notify/notifier.js b/src/ui/public/notify/notifier.js
index 332961e94e41..e2ff33b3901e 100644
--- a/src/ui/public/notify/notifier.js
+++ b/src/ui/public/notify/notifier.js
@@ -229,7 +229,7 @@ Notifier.prototype.error = function (err, cb) {
content: formatMsg(err, this.from),
icon: 'warning',
title: 'Error',
- lifetime: Infinity,
+ lifetime: 300000,
actions: ['report', 'accept'],
stack: formatStack(err)
}, cb);
diff --git a/src/ui/public/notify/partials/toaster.html b/src/ui/public/notify/partials/toaster.html
index 52a2e83a067d..b1679f1082a2 100644
--- a/src/ui/public/notify/partials/toaster.html
+++ b/src/ui/public/notify/partials/toaster.html
@@ -16,6 +16,13 @@
ng-class="'btn-' + notif.type"
ng-click="notif.showStack = true"
>More Info
+