Merge branch '6.0' of github.com:elastic/kibana into 6.0

This commit is contained in:
jimgoodwin 2017-08-08 10:22:14 -04:00
commit 288ad3b639
25 changed files with 311 additions and 168 deletions

View file

@ -38,8 +38,6 @@ document.
`discover:aggs:terms:size`:: Determines how many terms will be visualized when clicking the "visualize" button, in the field drop downs, in the discover sidebar. The default value is `20`.
`doc_table:highlight`:: Highlight results in Discover and Saved Searches Dashboard. Highlighting makes request slow when
working on big documents. Set this property to `false` to disable highlighting.
`doc_table:highlight:all_fields`:: Improves highlighting by using a separate `highlight_query` that uses `all_fields` mode on
`query_string` queries. Set to `false` if you are using a `default_field` in your index.
`courier:maxSegmentCount`:: Kibana splits requests in the Discover app into segments to limit the size of requests sent to
the Elasticsearch cluster. This setting constrains the length of the segment list. Long segment lists can significantly
increase request processing time.

View file

@ -5,53 +5,19 @@ describe('getHighlightRequest', () => {
let configMock;
const getConfig = (key) => configMock[key];
const queryStringQuery = { query_string: { query: 'foo' } };
const queryStringWithDefaultFieldQuery = { query_string: { query: 'foo', default_field: 'bar' } };
const queryStringWithFieldQuery = { query_string: { query: 'foo', fields: ['bar'] } };
const rangeQuery = { range: { '@timestamp': { gte: 0, lte: 0 } } };
const boolQueryWithSingleCondition = {
bool: {
must: queryStringQuery,
}
};
const boolQueryWithMultipleConditions = {
bool: {
must: [
queryStringQuery,
rangeQuery
]
}
};
beforeEach(function () {
configMock = {};
configMock['doc_table:highlight'] = true;
configMock['doc_table:highlight:all_fields'] = true;
});
it('should be a function', () => {
expect(getHighlightRequest).to.be.a(Function);
});
it('should add the all_fields param with query_string query without modifying original query', () => {
const request = getHighlightRequest(queryStringQuery, getConfig);
expect(request.fields['*']).to.have.property('highlight_query');
expect(request.fields['*'].highlight_query.query_string).to.have.property('all_fields');
expect(queryStringQuery.query_string).to.not.have.property('all_fields');
});
it('should add the all_fields param with bool query with single condition without modifying original query', () => {
const request = getHighlightRequest(boolQueryWithSingleCondition, getConfig);
expect(request.fields['*']).to.have.property('highlight_query');
expect(request.fields['*'].highlight_query.bool.must.query_string).to.have.property('all_fields');
expect(queryStringQuery.query_string).to.not.have.property('all_fields');
});
it('should add the all_fields param with bool query with multiple conditions without modifying original query', () => {
const request = getHighlightRequest(boolQueryWithMultipleConditions, getConfig);
expect(request.fields['*']).to.have.property('highlight_query');
expect(request.fields['*'].highlight_query.bool.must).to.have.length(boolQueryWithMultipleConditions.bool.must.length);
expect(request.fields['*'].highlight_query.bool.must[0].query_string).to.have.property('all_fields');
expect(queryStringQuery.query_string).to.not.have.property('all_fields');
it('should not modify the original query', () => {
getHighlightRequest(queryStringQuery, getConfig);
expect(queryStringQuery.query_string).to.not.have.property('highlight');
});
it('should return undefined if highlighting is turned off', () => {
@ -60,12 +26,6 @@ describe('getHighlightRequest', () => {
expect(request).to.be(undefined);
});
it('should not add the highlight_query param if all_fields is turned off', () => {
configMock['doc_table:highlight:all_fields'] = false;
const request = getHighlightRequest(queryStringQuery, getConfig);
expect(request.fields['*']).to.not.have.property('highlight_query');
});
it('should enable/disable highlighting if config is changed', () => {
let request = getHighlightRequest(queryStringQuery, getConfig);
expect(request).to.not.be(undefined);
@ -74,20 +34,4 @@ describe('getHighlightRequest', () => {
request = getHighlightRequest(queryStringQuery, getConfig);
expect(request).to.be(undefined);
});
it('should not add the all_fields param with query_string query when default_field is specified', () => {
const request = getHighlightRequest(queryStringWithDefaultFieldQuery, getConfig);
expect(request.fields['*']).to.have.property('highlight_query');
expect(request.fields['*'].highlight_query.query_string).to.have.property('default_field');
expect(request.fields['*'].highlight_query.query_string).to.not.have.property('all_fields');
expect(queryStringQuery.query_string).to.not.have.property('all_fields');
});
it('should not add the all_fields param with query_string query when fields are specified', () => {
const request = getHighlightRequest(queryStringWithFieldQuery, getConfig);
expect(request.fields['*']).to.have.property('highlight_query');
expect(request.fields['*'].highlight_query.query_string).to.have.property('fields');
expect(request.fields['*'].highlight_query.query_string).to.not.have.property('all_fields');
expect(queryStringQuery.query_string).to.not.have.property('all_fields');
});
});

View file

@ -1,43 +1,15 @@
import _ from 'lodash';
import { highlightTags } from './highlight_tags';
const FRAGMENT_SIZE = Math.pow(2, 31) - 1; // Max allowed value for fragment_size (limit of a java int)
/**
* Returns a clone of the query with `"all_fields": true` set on any `query_string` queries
*/
function getHighlightQuery(query) {
const clone = _.cloneDeep(query);
if (
_.has(clone, 'query_string')
&& !_.has(clone, ['query_string', 'default_field'])
&& !_.has(clone, ['query_string', 'fields'])
) {
clone.query_string.all_fields = true;
} else if (_.has(clone, 'bool.must')) {
if (Array.isArray(clone.bool.must)) {
clone.bool.must = clone.bool.must.map(getHighlightQuery);
} else {
clone.bool.must = getHighlightQuery(clone.bool.must);
}
}
return clone;
}
export function getHighlightRequest(query, getConfig) {
if (!getConfig('doc_table:highlight')) return;
const fieldsParams = getConfig('doc_table:highlight:all_fields')
? { highlight_query: getHighlightQuery(query) }
: {};
return {
pre_tags: [highlightTags.pre],
post_tags: [highlightTags.post],
fields: {
'*': fieldsParams
'*': {}
},
fragment_size: FRAGMENT_SIZE
};

View file

@ -7,8 +7,8 @@
class="exitFullScreenMode"
ng-click="exitFullScreenMode()"
>
<span class="exitFullScreenModeLogo"></span>
<span class="exitFullScreenModeText">
<span class="exitFullScreenModeLogo" data-test-subj="exitFullScreenModeLogo"></span>
<span class="exitFullScreenModeText" data-test-subj="exitFullScreenModeText">
Exit full screen
<span class="kuiIcon fa fa-angle-left"></span>
</span>

View file

@ -19,6 +19,7 @@
padding: 0;
border: none;
background: none;
z-index: 5;
}

View file

@ -4,24 +4,24 @@
>
<div class="kuiLocalDropdownTitle">Add Panels</div>
<ul class="nav nav-tabs">
<li ng-class="{active: mode == 'visualization'}">
<a
ng-click="mode='visualization'"
aria-label="List visualizations"
>
Visualization
</a>
</li>
<li ng-class="{active: mode == 'search'}">
<a
ng-click="mode='search'"
aria-label="List saved searches"
>
Saved Search
</a>
</li>
</ul>
<div class="kuiTabs">
<button
ng-class="{ 'kuiTab-isSelected': mode == 'visualization'}"
class="kuiTab"
ng-click="mode='visualization'"
aria-label="List visualizations"
>
Visualization
</button>
<button
ng-class="{ 'kuiTab-isSelected': mode == 'search' }"
class="kuiTab"
ng-click="mode='search'"
aria-label="List saved searches"
>
Saved Search
</button>
</div>
<div class="list-group-item list-group-item--noBorder" ng-switch-when="visualization">
<saved-object-finder

View file

@ -25,7 +25,7 @@ require('ui/index_patterns/route_setup/load_default')({
uiModules
.get('apps/management')
.directive('kbnManagementApp', function (Private, $location, timefilter, buildNum, buildSha) {
.directive('kbnManagementApp', function (Private, $location, timefilter) {
return {
restrict: 'E',
template: appTemplate,
@ -46,8 +46,6 @@ uiModules
item.active = `#${$location.path()}`.indexOf(item.url) > -1;
});
}
management.getSection('kibana').info = `Build ${buildNum}, Commit SHA ${buildSha.substr(0, 8)}`;
}
};
});

View file

@ -9,7 +9,6 @@
<div
ng-if="section.visibleItems.length > 0"
ng-repeat="section in sections"
ng-class="{ 'management-section-info-expanded': section.showInfo }"
class="page-row"
>
<div class="kuiPanel management-panel">
@ -22,15 +21,6 @@
{{::section.display}}
</div>
</div>
<div class="kuiPanelHeaderSection" ng-if="section.info">
<div class="kuiText">
<span
class="fa fa-info-circle management-panel__heading-icon--secondary"
ng-click="section.showInfo = !!!section.showInfo"
></span>
</div>
</div>
</div>
<div class="kuiPanelBody management-panel__body">
@ -55,10 +45,6 @@
</li>
</ul>
</div>
<div class="management-section-info">
{{::section.info}}
</div>
</div>
</div>
</div>

View file

@ -55,20 +55,6 @@ kbn-management-landing {
}
}
.management-section-info {
bottom: 10px;
display: none;
color: @kibanaPink1;
font-size: 0.8em;
position: absolute;
}
.management-section-info-expanded {
.management-section-info {
display: block;
}
}
/**
* 1. Set icon size.
* 2. Hack the panel title to move to the left a bit.
@ -102,10 +88,6 @@ kbn-management-landing {
background-image: url("~ui/icons/logstash-gray.svg");
}
.management-panel__heading-icon--secondary {
font-size: 0.9em;
padding: 5px;
}
}
kbn-management-objects {

View file

@ -10,7 +10,7 @@ export function getUiSettingDefaults() {
readonly: true
},
'query:queryString:options': {
value: '{ "analyze_wildcard": true }',
value: '{ "analyze_wildcard": true, "default_field": "*" }',
description: '<a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-query-string-query.html" target="_blank">Options</a> for the lucene query string parser',
type: 'json'
},
@ -91,11 +91,6 @@ export function getUiSettingDefaults() {
description: 'Highlight results in Discover and Saved Searches Dashboard.' +
'Highlighting makes requests slow when working on big documents.',
},
'doc_table:highlight:all_fields': {
value: true,
description: 'Improves highlighting by using a separate "highlight_query" that uses "all_fields" mode on "query_string" queries. ' +
'Set to false if you are using a "default_field" in your index.',
},
'courier:maxSegmentCount': {
value: 30,
description: 'Requests in discover are split into segments to prevent massive requests from being sent to ' +

View file

@ -43,4 +43,10 @@
</tr>
</table>
</div>
<footer class="row">
<div class="col-xs-12 text-right build-info">
Build {{::ui.buildInfo.num}}, Commit SHA {{::ui.buildInfo.sha}}
</div>
</footer>
</div>

View file

@ -8,10 +8,15 @@ import { uiModules } from 'ui/modules';
const chrome = require('ui/chrome')
.setRootTemplate(require('plugins/status_page/status_page.html'))
.setRootController('ui', function ($http) {
.setRootController('ui', function ($http, buildNum, buildSha) {
const ui = this;
ui.loading = false;
ui.buildInfo = {
num: buildNum,
sha: buildSha.substr(0, 8)
};
ui.refresh = function () {
ui.loading = true;

View file

@ -178,3 +178,7 @@
.overall_state_red {
.state(@status-red, @icon-red);
}
.build-info {
color: #555;
}

View file

@ -134,16 +134,6 @@ module.directive('savedObjectFinder', function ($location, $injector, kbnUrl, Pr
//key handler for the filter text box
self.filterKeyDown = function ($event) {
switch (keyMap[$event.keyCode]) {
case 'tab':
if (self.hitCount === 0) return;
self.selector.index = 0;
self.selector.enabled = true;
selectTopHit();
$event.preventDefault();
break;
case 'enter':
if (self.hitCount !== 1) return;

View file

@ -9,7 +9,6 @@ export class ManagementSection {
* @param {number|null} options.order
* @param {string|null} options.display - defaults to id
* @param {string|null} options.url - defaults to ''
* @param {string|null} options.info
* @param {boolean|null} options.visible - defaults to true
* @param {boolean|null} options.disabled - defaults to false
* @param {string|null} options.tooltip - defaults to ''

View file

@ -133,7 +133,6 @@ a {
.app-container {
> * {
position: relative;
z-index: 0;
}
.kibana-nav-options {

View file

@ -92,12 +92,16 @@
// /src/ui/public/styles/bootstrap/list-group.less
.list-group-item {
background-color: @list-group-bg;
border: 0 none transparent;
border: 1px solid @gray7;
&:nth-child(even) {
background-color: @gray4;
}
}
.list-group-item--noBorder {
border-top: 0;
}
a.list-group-item,
button.list-group-item {
color: @list-group-link-color;
@ -224,6 +228,14 @@
}
}
saved-object-finder, paginated-selectable-list {
ul.li-striped {
li {
border: none;
}
}
}
.cell-hover {
background-color: @table-cell-hover-bg;

View file

@ -15,6 +15,7 @@
- [Don't use multiple modifier classes together](#dont-use-multiple-modifier-classes-together)
- [How to apply DRY](#how-to-apply-dry)
- [Compelling reasons for using mixins](#compelling-reasons-for-using-mixins)
- [The Open/Closed Principle](#the-openclosed-principle)
## Selecting elements
@ -103,6 +104,8 @@ Our CSS naming convention is based on BEM:
* [BEM 101 (CSS Tricks)](https://css-tricks.com/bem-101/)
* [Getting your head around BEM syntax (CSS Wizardry)](http://csswizardry.com/2013/01/mindbemding-getting-your-head-round-bem-syntax/)
* [CSS for BEM (bem.info)](https://en.bem.info/methodology/css/)
* [CSS Guidelines](https://cssguidelin.es/)
## Concepts
@ -461,3 +464,115 @@ border-radius changes for all buttons, you only need to change it there. Or if
the designers anticipate that all new types of buttons should have the same
border-radius, then you can just extend this mixin when you create a new button
base class.
### The Open/Closed Principle
References:
* [The Open/Closed Principle on bem.info](https://en.bem.info/methodology/css/#openclosed-principle)
* [The Open/Closed Principle in CSS Guidelines](https://cssguidelin.es/#the-openclosed-principle)
* [The Open/Closed Principle on Wikipedia](https://en.wikipedia.org/wiki/Open/closed_principle)
Formally the open/closed principle reads
> Software entities (classes, modules, functions, etc.) should be **open for
> extension**, but **closed for modification**.
Applied to CSS, this means that CSS rulesets should be treated as immutable.
Once a declaration block for a specific selector has been defined, its style
should not be overridden in a different ruleset using the same selector:
```css
// BAD
.button {
color: blue;
font-size: 1.5em;
padding: 16px;
}
.header .button {
font-size: 1em;
padding: 4px;
}
```
Not only does this example violate the semantics of a BEM block, it also
**modifies** the meaning of `.button` depending on the context. Instead, this
could be expressed using a block modifier or a completely separate class which
is kept DRY using mixins:
```css
// GOOD
.button {
color: blue;
font-size: 1.5em;
}
.button--small {
font-size: 1em;
padding: 4px;
}
```
#### Exception: Block Groups
It is a common occurrence that groups of blocks within a container should be
styled differently that single blocks in order to indicate their association.
But using pure BEM mixes of blocks and group modifiers would sometimes require
a large number of modifiers to be applied to multiple elements to achieve that,
e.g.:
```css
.kuiCard { /* ... */ }
.kuiCard__description { /* ... */ }
.kuiCardGroup { /* ... */ }
.kuiCardGroup__card { /* ... */ }
.kuiCardGroup__cardDescription { /* ... */ }
```
```html
<div class="kuiCardGroup">
<div class="kuiCard kuiCardGroup__card">
<div class="kuiCard__description kuiCardGroup__cardDescription">
Card Description
</div>
</div>
</div>
```
To avoid the combinatorial explosion of classes with such groupings and thier
modifiers, it is permissible to nest a block's selector under another block's
selector if:
* The relationship is of a very narrow "`element` to `elementGroup`" kind that
is apparent from the block names.
* The rulesets are colocated in the same component directory.
```css
.kuiCard { /* ... */ }
.kuiCard__description { /* ... */ }
.kuiCardGroup { /* ... */ }
.kuiCardGroup .kuiCard { /* ... */ }
.kuiCardGroup .kuiCard__description { /* ... */ }
```
#### Exception: Normalization/Reset
We cannot control the selectors introduced by third-party stylesheets and these
selectors may not adhere to our styleguide, e.g. `a` or `input[type="text"]`.
In these cases, we are forced to duplicate these selectors within our own
stylesheets and override those styles to control their look and feel.
When this happens, it is important to add comments that make it clear why these
selectors exist and which third-party dependencies they override. We should
also define these selectors in files which refer back to the dependency, e.g. a
file named `ui_select_overrides.less` will contain styles overriding those
introduced by the `ui-select` dependency.

View file

@ -220,8 +220,57 @@ export default function ({ getService, getPageObjects }) {
});
});
describe('full screen mode', () => {
it('option not available in edit mode', async () => {
const exists = await PageObjects.dashboard.fullScreenModeMenuItemExists();
expect(exists).to.be(false);
});
it('available in view mode', async () => {
await PageObjects.dashboard.saveDashboard('full screen test');
const exists = await PageObjects.dashboard.fullScreenModeMenuItemExists();
expect(exists).to.be(true);
});
it('hides the chrome', async () => {
let isChromeVisible = await PageObjects.common.isChromeVisible();
expect(isChromeVisible).to.be(true);
await PageObjects.dashboard.clickFullScreenMode();
await retry.try(async () => {
isChromeVisible = await PageObjects.common.isChromeVisible();
expect(isChromeVisible).to.be(false);
});
});
it('displays exit full screen logo button', async () => {
const exists = await PageObjects.dashboard.exitFullScreenLogoButtonExists();
expect(exists).to.be(true);
});
it('displays exit full screen logo button when panel is expanded', async () => {
await PageObjects.dashboard.toggleExpandPanel();
const exists = await PageObjects.dashboard.exitFullScreenTextButtonExists();
expect(exists).to.be(true);
});
it('exits when the text button is clicked on', async () => {
const logoButton = await PageObjects.dashboard.getExitFullScreenLogoButton();
await remote.moveMouseTo(logoButton);
await PageObjects.dashboard.clickExitFullScreenTextButton();
await retry.try(async () => {
const isChromeVisible = await PageObjects.common.isChromeVisible();
expect(isChromeVisible).to.be(true);
});
});
});
describe('add new visualization link', () => {
it('adds a new visualization', async () => {
await PageObjects.dashboard.clickEdit();
await PageObjects.dashboard.clickAddVisualization();
await PageObjects.dashboard.clickAddNewVisualizationLink();
await PageObjects.visualize.clickAreaChart();

View file

@ -33,6 +33,39 @@ export function DashboardPageProvider({ getService, getPageObjects }) {
return logstash;
}
async clickFullScreenMode() {
log.debug(`clickFullScreenMode`);
await testSubjects.click('dashboardFullScreenMode');
}
async fullScreenModeMenuItemExists() {
return await testSubjects.exists('dashboardFullScreenMode');
}
async exitFullScreenTextButtonExists() {
return await testSubjects.exists('exitFullScreenModeText');
}
async getExitFullScreenTextButton() {
return await testSubjects.find('exitFullScreenModeText');
}
async exitFullScreenLogoButtonExists() {
return await testSubjects.exists('exitFullScreenModeLogo');
}
async getExitFullScreenLogoButton() {
return await testSubjects.find('exitFullScreenModeLogo');
}
async clickExitFullScreenLogoButton() {
await testSubjects.click('exitFullScreenModeLogo');
}
async clickExitFullScreenTextButton() {
await testSubjects.click('exitFullScreenModeText');
}
/**
* Returns true if already on the dashboard landing page (that page doesn't have a link to itself).
* @returns {Promise<boolean>}

View file

@ -1,4 +1,10 @@
$tabBackgroundColor: #FFF;
$tabHoverBackgroundColor: #F2F2F2;
// Dark theme colors
$tabColor--darkTheme: $globalTextColor--darkTheme;
$tabBackgroundColor--darkTheme: #333333;
$tabHoverBackgroundColor--darkTheme: $globalBackgroundColor--darkTheme;
$tabBorderColor--darkTheme: $globalBackgroundColor--darkTheme;
@import "tabs";

View file

@ -1,6 +1,10 @@
.kuiTabs {
display: flex;
border-bottom: $globalBorderThin;
@include darkTheme {
border-bottom: 1px solid $tabBorderColor--darkTheme;
}
}
@ -19,10 +23,15 @@
color: $globalSubduedTextColor;
background-color: $tabBackgroundColor; /* 1 */
border: 1px solid $globalBorderColor;
border-bottom-width: 1px;
border-radius: 0; /* 1 */
margin-bottom: -1px; /* 3 */
@include darkTheme {
color: $tabColor--darkTheme;
background-color: $tabBackgroundColor--darkTheme;
border-color: $tabBorderColor--darkTheme;
}
& + & {
border-left: none;
@ -44,16 +53,33 @@
z-index: 1;
color: $globalLinkColor;
border: 1px solid $globalSelectedBorderColor !important;
@include darkTheme {
color: $tabColor--darkTheme;
background-color: $tabBackgroundColor--darkTheme;
border-color: $tabBorderColor--darkTheme !important;
}
}
&:hover:not(.kuiTab-isSelected) {
color: $globalLinkHoverColor;
background-color: $tabHoverBackgroundColor;
@include darkTheme {
color: $globalLinkColor-isHover--darkTheme;
background-color: $tabHoverBackgroundColor--darkTheme;
}
}
&.kuiTab-isSelected {
cursor: default;
color: $globalFontColor;
border-bottom-color: $tabBackgroundColor;
@include darkTheme {
color: $tabColor--darkTheme;
background-color: $tabBackgroundColor--darkTheme;
border-bottom-color: $tabBackgroundColor--darkTheme;
}
}
}

View file

@ -2913,6 +2913,8 @@ main {
display: -ms-flexbox;
display: flex;
border-bottom: 1px solid #D9D9D9; }
.theme-dark .kuiTabs {
border-bottom: 1px solid #777777; }
/**
* 1. Override button styles (some of which are from Bootstrap).
@ -2933,11 +2935,14 @@ main {
background-color: #FFF;
/* 1 */
border: 1px solid #D9D9D9;
border-bottom-width: 1px;
border-radius: 0;
/* 1 */
margin-bottom: -1px;
/* 3 */ }
.theme-dark .kuiTab {
color: #cecece;
background-color: #333333;
border-color: #777777; }
.kuiTab + .kuiTab {
border-left: none; }
.kuiTab + .kuiTab:focus:not(.kuiTab-isSelected):not(:active) {
@ -2955,13 +2960,24 @@ main {
z-index: 1;
color: #0079a5;
border: 1px solid #0079a5 !important; }
.theme-dark .kuiTab:focus:not(.kuiTab-isSelected):not(:active) {
color: #cecece;
background-color: #333333;
border-color: #777777 !important; }
.kuiTab:hover:not(.kuiTab-isSelected) {
color: #006E8A;
background-color: #F2F2F2; }
.theme-dark .kuiTab:hover:not(.kuiTab-isSelected) {
color: #def2f6;
background-color: #777777; }
.kuiTab.kuiTab-isSelected {
cursor: default;
color: #191E23;
border-bottom-color: #FFF; }
.theme-dark .kuiTab.kuiTab-isSelected {
color: #cecece;
background-color: #333333;
border-bottom-color: #333333; }
/**
* 1. Allow container to deteermine font-size and line-height.

View file

@ -32,7 +32,7 @@ class KuiTabsExample extends React.Component {
this.setState({
selectedTabId: id,
});
}
};
renderTabs() {
return this.tabs.map((tab,index) => (

View file

@ -34,6 +34,13 @@ export default props => (
<GuideDemo>
<Tabs />
</GuideDemo>
<GuideText>
Dark themed tabs
</GuideText>
<GuideDemo isDarkTheme={true}>
<Tabs />
</GuideDemo>
</GuideSection>
</GuidePage>