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 +