} [options.fields]
* @property {string} [options.namespace]
+ * @property {object} [options.hasReference] - { type, id }
* @returns {promise} - { saved_objects: [{ id, type, version, attributes }], total, per_page, page }
*/
async find(options = {}) {
diff --git a/src/ui/public/agg_types/buckets/terms.js b/src/ui/public/agg_types/buckets/terms.js
index 55e0625cec694..28bf458d03d32 100644
--- a/src/ui/public/agg_types/buckets/terms.js
+++ b/src/ui/public/agg_types/buckets/terms.js
@@ -108,10 +108,15 @@ export const termsBucketAgg = new BucketAggType({
const filterAgg = buildOtherBucketAgg(aggConfigs, aggConfig, resp);
nestedSearchSource.setField('aggs', filterAgg);
- const request = inspectorAdapters.requests.start('Other bucket', {
- description: `This request counts the number of documents that fall
- outside the criterion of the data buckets.`
- });
+ const request = inspectorAdapters.requests.start(
+ i18n.translate('common.ui.aggTypes.buckets.terms.otherBucketTitle', { defaultMessage: 'Other bucket' }),
+ {
+ description: i18n.translate('common.ui.aggTypes.buckets.terms.otherBucketDescription', {
+ defaultMessage: 'This request counts the number of documents that fall ' +
+ 'outside the criterion of the data buckets.'
+ }),
+ }
+ );
nestedSearchSource.getSearchRequestBody().then(body => {
request.json(body);
});
@@ -161,7 +166,9 @@ export const termsBucketAgg = new BucketAggType({
try {
return agg.makeLabel();
} catch (e) {
- return '- agg not valid -';
+ return i18n.translate('common.ui.aggTypes.buckets.terms.aggNotValidLabel', {
+ defaultMessage: '- agg not valid -',
+ });
}
};
diff --git a/src/ui/public/agg_types/controls/ranges.html b/src/ui/public/agg_types/controls/ranges.html
index 4255c671628e1..e24b6f4378857 100644
--- a/src/ui/public/agg_types/controls/ranges.html
+++ b/src/ui/public/agg_types/controls/ranges.html
@@ -39,7 +39,7 @@
@@ -121,28 +146,83 @@
>
diff --git a/src/ui/public/filter_bar/filter_bar.js b/src/ui/public/filter_bar/filter_bar.js
index 0a1648ac75d4a..88cc6146706a7 100644
--- a/src/ui/public/filter_bar/filter_bar.js
+++ b/src/ui/public/filter_bar/filter_bar.js
@@ -37,7 +37,7 @@ export { disableFilter, enableFilter, toggleFilterDisabled } from './lib/disable
const module = uiModules.get('kibana');
-module.directive('filterBar', function (Private, Promise, getAppState) {
+module.directive('filterBar', function (Private, Promise, getAppState, i18n) {
const mapAndFlattenFilters = Private(FilterBarLibMapAndFlattenFiltersProvider);
const mapFlattenAndWrapFilters = Private(FilterBarLibMapFlattenAndWrapFiltersProvider);
const extractTimeFilter = Private(FilterBarLibExtractTimeFilterProvider);
@@ -74,20 +74,25 @@ module.directive('filterBar', function (Private, Promise, getAppState) {
return pill[pill.length - 1].offsetTop > 10;
};
+ const collapseFilterTooltip = i18n('common.ui.filterBar.collapseFilterTooltip', {
+ defaultMessage: 'Collapse filter bar \n to show less'
+ });
+ const expandFilterTooltip = i18n('common.ui.filterBar.expandFilterTooltip', { defaultMessage: 'Expand filter bar \n to show more' });
+
$scope.filterNavToggle = {
isOpen: true,
- tooltipContent: 'Collapse filter bar \n to show less'
+ tooltipContent: collapseFilterTooltip
};
$scope.toggleFilterShown = () => {
const collapser = $elem.find('.filter-nav-link__collapser');
const filterPanelPill = $elem.find('.filter-panel__pill');
if ($scope.filterNavToggle.isOpen) {
- $scope.filterNavToggle.tooltipContent = 'Expand filter bar \n to show more';
+ $scope.filterNavToggle.tooltipContent = expandFilterTooltip;
collapser.attr('aria-expanded', 'false');
filterPanelPill.attr('style', 'width: calc(100% - 80px)');
} else {
- $scope.filterNavToggle.tooltipContent = 'Collapse filter bar \n to show less';
+ $scope.filterNavToggle.tooltipContent = collapseFilterTooltip;
collapser.attr('aria-expanded', 'true');
filterPanelPill.attr('style', 'width: auto');
}
diff --git a/src/ui/public/filter_bar/filter_pill/filter_pill.html b/src/ui/public/filter_bar/filter_pill/filter_pill.html
index f79d42665e8fc..f1cdadad492f6 100644
--- a/src/ui/public/filter_bar/filter_pill/filter_pill.html
+++ b/src/ui/public/filter_bar/filter_pill/filter_pill.html
@@ -13,7 +13,11 @@
aria-disabled="{{pill.filter.meta.disabled}}"
>
- NOT
+
{{ pill.filter.meta.alias }}
{{ pill.filter.meta.key }}:
"{{ pill.filter.meta.value }}"
@@ -26,8 +30,8 @@
data-test-subj="disableFilter-{{ pill.filter.meta.key }}"
ng-focus="pill.activateActions()"
ng-blur="pill.deactivateActions()"
- aria-label="{{pill.filter.meta.disabled ? 'Enable filter' : 'Disable filter'}}"
- tooltip="{{pill.filter.meta.disabled ? 'Enable filter' : 'Disable filter'}}"
+ aria-label="{{pill.filter.meta.disabled ? pill.i18n.enableFilterAriaLabel : pill.i18n.disableFilterAriaLabel}}"
+ tooltip="{{pill.filter.meta.disabled ? pill.i18n.enableFilterTooltip : pill.i18n.disableFilterTooltip}}"
tooltip-append-to-body="true"
>
@@ -40,8 +44,8 @@
data-test-subj="pinFilter-{{ pill.filter.meta.key }}"
ng-focus="pill.activateActions()"
ng-blur="pill.deactivateActions()"
- aria-label="{{pill.filter.$state.store == 'globalState' ? 'Unpin filter' : 'Pin filter'}}"
- tooltip="{{pill.filter.$state.store == 'globalState' ? 'Unpin filter' : 'Pin filter'}}"
+ aria-label="{{pill.filter.$state.store == 'globalState' ? pill.i18n.unpinFilterAriaLabel : pill.i18n.pinFilterAriaLabel}}"
+ tooltip="{{pill.filter.$state.store == 'globalState' ? pill.i18n.unpinFilterTooltip : pill.i18n.pinFilterTooltip}}"
tooltip-append-to-body="true"
>
@@ -54,8 +58,8 @@
data-test-subj="invertFilter-{{ pill.filter.meta.key }}"
ng-focus="pill.activateActions()"
ng-blur="pill.deactivateActions()"
- aria-label="{{pill.filter.meta.negate ? 'Include matches' : 'Exclude matches'}}"
- tooltip="{{pill.filter.meta.negate ? 'Include matches' : 'Exclude matches'}}"
+ aria-label="{{pill.filter.meta.negate ? pill.i18n.includeMatchesAriaLabel : pill.i18n.excludeMatchesAriaLabel}}"
+ tooltip="{{pill.filter.meta.negate ? pill.i18n.includeMatchesTooltip : pill.i18n.excludeMatchesTooltip}}"
tooltip-append-to-body="true"
>
@@ -67,8 +71,8 @@
ng-click="pill.onDeleteFilter(pill.filter)"
ng-focus="pill.activateActions()"
ng-blur="pill.deactivateActions()"
- aria-label="Remove filter"
- tooltip="Remove filter"
+ aria-label="{{ ::'common.ui.filterBar.filterPill.removeFilterAriaLabel' | i18n: { defaultMessage: 'Remove filter' } }}"
+ tooltip="{{ ::'common.ui.filterBar.filterPill.removeFilterTooltip' | i18n: { defaultMessage: 'Remove filter' } }}"
tooltip-append-to-body="true"
>
@@ -80,14 +84,14 @@
ng-disabled="pill.isControlledByPanel()"
ng-focus="pill.activateActions()"
ng-blur="pill.deactivateActions()"
- aria-label="Edit filter"
- tooltip="Edit filter"
+ aria-label="{{ ::'common.ui.filterBar.filterPill.editFilterAriaLabel' | i18n: { defaultMessage: 'Edit filter' } }}"
+ tooltip="{{ ::'common.ui.filterBar.filterPill.editFilterTooltip' | i18n: { defaultMessage: 'Edit filter' } }}"
tooltip-append-to-body="true"
data-test-subj="editFilter"
>
diff --git a/src/ui/public/filter_bar/filter_pill/filter_pill.js b/src/ui/public/filter_bar/filter_pill/filter_pill.js
index 03b19427af930..cd15d9df7d888 100644
--- a/src/ui/public/filter_bar/filter_pill/filter_pill.js
+++ b/src/ui/public/filter_bar/filter_pill/filter_pill.js
@@ -23,7 +23,7 @@ import { uiModules } from '../../modules';
const module = uiModules.get('kibana');
-module.directive('filterPill', function () {
+module.directive('filterPill', function (i18n) {
return {
template,
restrict: 'E',
@@ -51,6 +51,20 @@ module.directive('filterPill', function () {
return _.has(this.filter, 'meta.controlledBy');
};
+ this.i18n = {
+ enableFilterAriaLabel: i18n('common.ui.filterBar.filterPill.enableFilterAriaLabel', { defaultMessage: 'Enable filter' }),
+ enableFilterTooltip: i18n('common.ui.filterBar.filterPill.enableFilterTooltip', { defaultMessage: 'Enable filter' }),
+ disableFilterAriaLabel: i18n('common.ui.filterBar.filterPill.disableFilterAriaLabel', { defaultMessage: 'Disable filter' }),
+ disableFilterTooltip: i18n('common.ui.filterBar.filterPill.disableFilterTooltip', { defaultMessage: 'Disable filter' }),
+ pinFilterAriaLabel: i18n('common.ui.filterBar.filterPill.pinFilterAriaLabel', { defaultMessage: 'Pin filter' }),
+ pinFilterTooltip: i18n('common.ui.filterBar.filterPill.pinFilterTooltip', { defaultMessage: 'Pin filter' }),
+ unpinFilterAriaLabel: i18n('common.ui.filterBar.filterPill.unpinFilterAriaLabel', { defaultMessage: 'Unpin filter' }),
+ unpinFilterTooltip: i18n('common.ui.filterBar.filterPill.unpinFilterTooltip', { defaultMessage: 'Unpin filter' }),
+ includeMatchesAriaLabel: i18n('common.ui.filterBar.filterPill.includeMatchesAriaLabel', { defaultMessage: 'Include matches' }),
+ includeMatchesTooltip: i18n('common.ui.filterBar.filterPill.includeMatchesTooltip', { defaultMessage: 'Include matches' }),
+ excludeMatchesAriaLabel: i18n('common.ui.filterBar.filterPill.excludeMatchesAriaLabel', { defaultMessage: 'Exclude matches' }),
+ excludeMatchesTooltip: i18n('common.ui.filterBar.filterPill.excludeMatchesTooltip', { defaultMessage: 'Exclude matches' }),
+ };
}
};
});
diff --git a/src/ui/public/filter_editor/filter_editor.html b/src/ui/public/filter_editor/filter_editor.html
index 0b69a1d5661d8..7070f6ac8e653 100644
--- a/src/ui/public/filter_editor/filter_editor.html
+++ b/src/ui/public/filter_editor/filter_editor.html
@@ -1,16 +1,22 @@
@@ -98,14 +123,14 @@
+ i18n-id="common.ui.filterEditor.labelLabel"
+ i18n-default-message="Label"
+ >
- Cancel
-
+ i18n-id="common.ui.filterEditor.cancelButtonLabel"
+ i18n-default-message="Cancel"
+ >
+ i18n-id="common.ui.filterEditor.saveButtonLabel"
+ i18n-default-message="Save"
+ >
diff --git a/src/ui/public/filter_editor/filter_field_select.html b/src/ui/public/filter_editor/filter_field_select.html
index 65c45b1bae7b0..1aef71c2b0bb9 100644
--- a/src/ui/public/filter_editor/filter_field_select.html
+++ b/src/ui/public/filter_editor/filter_field_select.html
@@ -4,7 +4,7 @@
on-select="onSelect({ field: field })"
uis-open-close="resetLimit()"
>
-
+
-
+
{{$select.selected.name}}
diff --git a/src/ui/public/filter_editor/lib/filter_operators.js b/src/ui/public/filter_editor/lib/filter_operators.js
index 140928eb1912d..a7a81aff3ddcf 100644
--- a/src/ui/public/filter_editor/lib/filter_operators.js
+++ b/src/ui/public/filter_editor/lib/filter_operators.js
@@ -19,48 +19,66 @@
import _ from 'lodash';
+import { i18n } from '@kbn/i18n';
+
export const FILTER_OPERATORS = [
{
- name: 'is',
+ name: i18n.translate('common.ui.filterEditor.operators.isLabel', {
+ defaultMessage: 'is'
+ }),
type: 'phrase',
negate: false,
},
{
- name: 'is not',
+ name: i18n.translate('common.ui.filterEditor.operators.isNotLabel', {
+ defaultMessage: 'is not'
+ }),
type: 'phrase',
negate: true,
},
{
- name: 'is one of',
+ name: i18n.translate('common.ui.filterEditor.operators.isOneOfLabel', {
+ defaultMessage: 'is one of'
+ }),
type: 'phrases',
negate: false,
fieldTypes: ['string', 'number', 'date', 'ip', 'geo_point', 'geo_shape']
},
{
- name: 'is not one of',
+ name: i18n.translate('common.ui.filterEditor.operators.isNotOneOfLabel', {
+ defaultMessage: 'is not one of'
+ }),
type: 'phrases',
negate: true,
fieldTypes: ['string', 'number', 'date', 'ip', 'geo_point', 'geo_shape']
},
{
- name: 'is between',
+ name: i18n.translate('common.ui.filterEditor.operators.isBetweenLabel', {
+ defaultMessage: 'is between'
+ }),
type: 'range',
negate: false,
fieldTypes: ['number', 'date', 'ip'],
},
{
- name: 'is not between',
+ name: i18n.translate('common.ui.filterEditor.operators.isNotBetweenLabel', {
+ defaultMessage: 'is not between'
+ }),
type: 'range',
negate: true,
fieldTypes: ['number', 'date', 'ip'],
},
{
- name: 'exists',
+ name: i18n.translate('common.ui.filterEditor.operators.existsLabel', {
+ defaultMessage: 'exists'
+ }),
type: 'exists',
negate: false,
},
{
- name: 'does not exist',
+ name: i18n.translate('common.ui.filterEditor.operators.doesNotExistLabel', {
+ defaultMessage: 'does not exist'
+ }),
type: 'exists',
negate: true,
},
diff --git a/src/ui/public/filter_editor/params_editor/filter_params_phrase_editor.html b/src/ui/public/filter_editor/params_editor/filter_params_phrase_editor.html
index 36d509f28dece..67d8acc8ed682 100644
--- a/src/ui/public/filter_editor/params_editor/filter_params_phrase_editor.html
+++ b/src/ui/public/filter_editor/params_editor/filter_params_phrase_editor.html
@@ -5,7 +5,7 @@
spinner-enabled="true"
spinner-class="kuiIcon kuiIcon--basic fa-spinner fa-spin"
>
-
+
- Accepted date formats
-
+ i18n-id="common.ui.filterEditor.filterParamsPhraseEditor.acceptedDateFormatsLinkText"
+ i18n-default-message="Accepted date formats"
+ >
diff --git a/src/ui/public/filter_editor/params_editor/filter_params_phrases_editor.html b/src/ui/public/filter_editor/params_editor/filter_params_phrases_editor.html
index 4a2935c4ba0b7..d2caea1066db1 100644
--- a/src/ui/public/filter_editor/params_editor/filter_params_phrases_editor.html
+++ b/src/ui/public/filter_editor/params_editor/filter_params_phrases_editor.html
@@ -6,7 +6,7 @@
spinner-class="kuiIcon kuiIcon--basic fa-spinner fa-spin"
>
- Accepted date formats
-
+ i18n-id="common.ui.filterEditor.filterParamsRangeEditor.acceptedDateFormatsLinkText"
+ i18n-default-message="Accepted date formats"
+ >
diff --git a/src/ui/public/notify/partials/toaster.html b/src/ui/public/notify/partials/toaster.html
index 49b229d9c3ab8..5d5b0ab72af83 100644
--- a/src/ui/public/notify/partials/toaster.html
+++ b/src/ui/public/notify/partials/toaster.html
@@ -85,10 +85,14 @@
ng-if="notif.isTimed()"
class="kbnToaster__countdown"
ng-click="notif.cancelTimer()"
- title="Stop"
+ title="{{ ::'common.ui.notify.toaster.stopCountdownButtonTooltip' | i18n: { defaultMessage: 'Stop' } }}"
>
- {{ notif.timeRemaining }}s
+
diff --git a/src/ui/public/pager_control/components/tool_bar_pager_text/tool_bar_pager_text.html b/src/ui/public/pager_control/components/tool_bar_pager_text/tool_bar_pager_text.html
index b7e1014282199..72bbc3833630b 100644
--- a/src/ui/public/pager_control/components/tool_bar_pager_text/tool_bar_pager_text.html
+++ b/src/ui/public/pager_control/components/tool_bar_pager_text/tool_bar_pager_text.html
@@ -1,3 +1,11 @@
- {{ toolBarPagerText.startItem | number }}–{{ toolBarPagerText.endItem | number }} of {{ toolBarPagerText.totalItems | number }}
+
\ No newline at end of file
diff --git a/src/ui/public/persisted_log/persisted_log.ts b/src/ui/public/persisted_log/persisted_log.ts
index 209607b5a9a09..0824d17757311 100644
--- a/src/ui/public/persisted_log/persisted_log.ts
+++ b/src/ui/public/persisted_log/persisted_log.ts
@@ -18,6 +18,8 @@
*/
import _ from 'lodash';
+import * as Rx from 'rxjs';
+import { map } from 'rxjs/operators';
import { Storage } from 'ui/storage';
const localStorage = new Storage(window.localStorage);
@@ -40,6 +42,8 @@ export class PersistedLog {
public storage: Storage;
public items: T[];
+ private update$ = new Rx.BehaviorSubject(undefined);
+
constructor(name: string, options: PersistedLogOptions = {}, storage = localStorage) {
this.name = name;
this.maxLength =
@@ -76,10 +80,15 @@ export class PersistedLog {
// persist the stack
this.storage.set(this.name, this.items);
+ this.update$.next(undefined);
return this.items;
}
public get() {
return _.cloneDeep(this.items);
}
+
+ public get$() {
+ return this.update$.pipe(map(() => this.get()));
+ }
}
diff --git a/src/ui/public/persisted_log/recently_accessed.ts b/src/ui/public/persisted_log/recently_accessed.ts
index 906646c6b49ab..45309db879ed2 100644
--- a/src/ui/public/persisted_log/recently_accessed.ts
+++ b/src/ui/public/persisted_log/recently_accessed.ts
@@ -51,6 +51,10 @@ class RecentlyAccessed {
public get() {
return this.history.get();
}
+
+ public get$() {
+ return this.history.get$();
+ }
}
export const recentlyAccessed = new RecentlyAccessed();
diff --git a/src/ui/public/query_bar/_index.scss b/src/ui/public/query_bar/_index.scss
index 81a69fd89db99..b6634debbfa96 100644
--- a/src/ui/public/query_bar/_index.scss
+++ b/src/ui/public/query_bar/_index.scss
@@ -1,4 +1,4 @@
// SASSTODO: Formalize this color in Kibana's styling constants
$typeaheadConjunctionColor: #7800A6;
-@import 'components/typeahead/index';
\ No newline at end of file
+@import './components/index';
diff --git a/src/ui/public/query_bar/components/__snapshots__/query_bar.test.tsx.snap b/src/ui/public/query_bar/components/__snapshots__/query_bar.test.tsx.snap
index fb092e9f684c0..ec7b3c074e89b 100644
--- a/src/ui/public/query_bar/components/__snapshots__/query_bar.test.tsx.snap
+++ b/src/ui/public/query_bar/components/__snapshots__/query_bar.test.tsx.snap
@@ -3,6 +3,7 @@
exports[`QueryBar Should disable autoFocus on EuiFieldText when disableAutoFocus prop is true 1`] = `
-
-
-
+ />
`;
@@ -112,6 +105,7 @@ exports[`QueryBar Should disable autoFocus on EuiFieldText when disableAutoFocus
exports[`QueryBar Should pass the query language to the language switcher 1`] = `
-
-
-
+ />
`;
@@ -221,6 +207,7 @@ exports[`QueryBar Should pass the query language to the language switcher 1`] =
exports[`QueryBar Should render the given query 1`] = `
-
-
-
+ />
`;
diff --git a/src/ui/public/query_bar/components/_index.scss b/src/ui/public/query_bar/components/_index.scss
new file mode 100644
index 0000000000000..e17c416c13546
--- /dev/null
+++ b/src/ui/public/query_bar/components/_index.scss
@@ -0,0 +1,2 @@
+@import './query_bar';
+@import './typeahead/index';
diff --git a/src/ui/public/query_bar/components/_query_bar.scss b/src/ui/public/query_bar/components/_query_bar.scss
new file mode 100644
index 0000000000000..f104c20daf064
--- /dev/null
+++ b/src/ui/public/query_bar/components/_query_bar.scss
@@ -0,0 +1,14 @@
+@include euiBreakpoint('xs', 's') {
+ .kbnQueryBar--withDatePicker {
+ > :last-child {
+ // EUI Flexbox adds too much margin between responded items, this just moves the last one up
+ margin-top: -$euiSize;
+ }
+ }
+}
+
+@include euiBreakpoint('m', 'l', 'xl') {
+ .kbnQueryBar__datePickerWrapper {
+ max-width: 40vw;
+ }
+}
diff --git a/src/ui/public/query_bar/components/query_bar.test.tsx b/src/ui/public/query_bar/components/query_bar.test.tsx
index 363464a5ca96e..8df14e4cf3210 100644
--- a/src/ui/public/query_bar/components/query_bar.test.tsx
+++ b/src/ui/public/query_bar/components/query_bar.test.tsx
@@ -207,8 +207,14 @@ describe('QueryBar', () => {
component.find(QueryLanguageSwitcher).simulate('selectLanguage', 'lucene');
expect(mockStorage.set).toHaveBeenCalledWith('kibana.userQueryLanguage', 'lucene');
expect(mockCallback).toHaveBeenCalledWith({
- query: '',
- language: 'lucene',
+ dateRange: {
+ from: 'now-15m',
+ to: 'now',
+ },
+ query: {
+ query: '',
+ language: 'lucene',
+ },
});
});
@@ -235,8 +241,14 @@ describe('QueryBar', () => {
expect(mockCallback).toHaveBeenCalledTimes(1);
expect(mockCallback).toHaveBeenCalledWith({
- query: 'extension:jpg',
- language: 'kuery',
+ dateRange: {
+ from: 'now-15m',
+ to: 'now',
+ },
+ query: {
+ query: 'extension:jpg',
+ language: 'kuery',
+ },
});
});
diff --git a/src/ui/public/query_bar/components/query_bar.tsx b/src/ui/public/query_bar/components/query_bar.tsx
index af91fea37eb43..5ffae8dc24743 100644
--- a/src/ui/public/query_bar/components/query_bar.tsx
+++ b/src/ui/public/query_bar/components/query_bar.tsx
@@ -19,12 +19,15 @@
import { IndexPattern } from 'ui/index_patterns';
-import { compact, debounce, isEqual } from 'lodash';
+import classNames from 'classnames';
+import _ from 'lodash';
+import { compact, debounce, get, isEqual } from 'lodash';
import React, { Component } from 'react';
import { getFromLegacyIndexPattern } from 'ui/index_patterns/static_utils';
import { kfetch } from 'ui/kfetch';
import { PersistedLog } from 'ui/persisted_log';
import { Storage } from 'ui/storage';
+import { timeHistory } from 'ui/timefilter/time_history';
import {
AutocompleteSuggestion,
AutocompleteSuggestionType,
@@ -36,15 +39,12 @@ import { matchPairs } from '../lib/match_pairs';
import { QueryLanguageSwitcher } from './language_switcher';
import { SuggestionsComponent } from './typeahead/suggestions_component';
-import {
- EuiButton,
- EuiFieldText,
- EuiFlexGroup,
- EuiFlexItem,
- EuiOutsideClickDetector,
-} from '@elastic/eui';
+import { EuiFieldText, EuiFlexGroup, EuiFlexItem, EuiOutsideClickDetector } from '@elastic/eui';
+
+// @ts-ignore
+import { EuiSuperDatePicker, EuiSuperUpdateButton } from '@elastic/eui';
-import { FormattedMessage, InjectedIntl, injectI18n } from '@kbn/i18n/react';
+import { InjectedIntl, injectI18n } from '@kbn/i18n/react';
const KEY_CODES = {
LEFT: 37,
@@ -66,14 +66,25 @@ interface Query {
language: string;
}
+interface DateRange {
+ from: string;
+ to: string;
+}
+
interface Props {
query: Query;
- onSubmit: (query: { query: string | object; language: string }) => void;
+ onSubmit: (payload: { dateRange: DateRange; query: Query }) => void;
disableAutoFocus?: boolean;
appName: string;
indexPatterns: IndexPattern[];
store: Storage;
intl: InjectedIntl;
+ showDatePicker?: boolean;
+ dateRangeFrom?: string;
+ dateRangeTo?: string;
+ isRefreshPaused?: boolean;
+ refreshInterval?: number;
+ onRefreshChange?: (isPaused: boolean, refreshInterval: number) => void;
}
interface State {
@@ -84,6 +95,9 @@ interface State {
suggestions: AutocompleteSuggestion[];
suggestionLimit: number;
currentProps?: Props;
+ dateRangeFrom: string;
+ dateRangeTo: string;
+ isDateRangeInvalid: boolean;
}
export class QueryBarUI extends Component {
@@ -92,25 +106,41 @@ export class QueryBarUI extends Component {
return null;
}
+ let nextQuery = null;
if (nextProps.query.query !== prevState.query.query) {
- return {
- query: {
- query: toUser(nextProps.query.query),
- language: nextProps.query.language,
- },
- currentProps: nextProps,
+ nextQuery = {
+ query: toUser(nextProps.query.query),
+ language: nextProps.query.language,
};
} else if (nextProps.query.language !== prevState.query.language) {
- return {
- query: {
- query: '',
- language: nextProps.query.language,
- },
- currentProps: nextProps,
+ nextQuery = {
+ query: '',
+ language: nextProps.query.language,
};
}
- return { currentProps: nextProps };
+ let nextDateRange = null;
+ if (
+ nextProps.dateRangeFrom !== get(prevState, 'currentProps.dateRangeFrom') ||
+ nextProps.dateRangeTo !== get(prevState, 'currentProps.dateRangeTo')
+ ) {
+ nextDateRange = {
+ dateRangeFrom: nextProps.dateRangeFrom,
+ dateRangeTo: nextProps.dateRangeTo,
+ };
+ }
+
+ const nextState: any = {
+ currentProps: nextProps,
+ };
+ if (nextQuery) {
+ nextState.query = nextQuery;
+ }
+ if (nextDateRange) {
+ nextState.dateRangeFrom = nextDateRange.dateRangeFrom;
+ nextState.dateRangeTo = nextDateRange.dateRangeTo;
+ }
+ return nextState;
}
/*
@@ -136,6 +166,9 @@ export class QueryBarUI extends Component {
index: null,
suggestions: [],
suggestionLimit: 50,
+ dateRangeFrom: _.get(this.props, 'dateRangeFrom', 'now-15m'),
+ dateRangeTo: _.get(this.props, 'dateRangeTo', 'now'),
+ isDateRangeInvalid: false,
};
public updateSuggestions = debounce(async () => {
@@ -151,7 +184,15 @@ export class QueryBarUI extends Component {
private persistedLog: PersistedLog | null = null;
public isDirty = () => {
- return this.state.query.query !== this.props.query.query;
+ if (!this.props.showDatePicker) {
+ return this.state.query.query !== this.props.query.query;
+ }
+
+ return (
+ this.state.query.query !== this.props.query.query ||
+ this.state.dateRangeFrom !== this.props.dateRangeFrom ||
+ this.state.dateRangeTo !== this.props.dateRangeTo
+ );
};
public increaseLimit = () => {
@@ -322,6 +363,22 @@ export class QueryBarUI extends Component {
this.onInputChange(event.target.value);
};
+ public onTimeChange = ({
+ start,
+ end,
+ isInvalid,
+ }: {
+ start: string;
+ end: string;
+ isInvalid: boolean;
+ }) => {
+ this.setState({
+ dateRangeFrom: start,
+ dateRangeTo: end,
+ isDateRangeInvalid: isInvalid,
+ });
+ };
+
public onKeyUp = (event: React.KeyboardEvent) => {
if ([KEY_CODES.LEFT, KEY_CODES.RIGHT, KEY_CODES.HOME, KEY_CODES.END].includes(event.keyCode)) {
this.setState({ isSuggestionsVisible: true });
@@ -408,9 +465,20 @@ export class QueryBarUI extends Component {
this.persistedLog.add(this.state.query.query);
}
+ timeHistory.add({
+ from: this.state.dateRangeFrom,
+ to: this.state.dateRangeTo,
+ });
+
this.props.onSubmit({
- query: fromUser(this.state.query.query),
- language: this.state.query.language,
+ query: {
+ query: fromUser(this.state.query.query),
+ language: this.state.query.language,
+ },
+ dateRange: {
+ from: this.state.dateRangeFrom,
+ to: this.state.dateRangeTo,
+ },
});
this.setState({ isSuggestionsVisible: false });
};
@@ -427,8 +495,14 @@ export class QueryBarUI extends Component {
this.props.store.set('kibana.userQueryLanguage', language);
this.props.onSubmit({
- query: '',
- language,
+ query: {
+ query: '',
+ language,
+ },
+ dateRange: {
+ from: this.state.dateRangeFrom,
+ to: this.state.dateRangeTo,
+ },
});
};
@@ -462,8 +536,16 @@ export class QueryBarUI extends Component {
}
public render() {
+ const classes = classNames('kbnQueryBar', {
+ 'kbnQueryBar--withDatePicker': this.props.showDatePicker,
+ });
+
return (
-
+
{/* position:relative required on container so the suggestions appear under the query bar*/}
@@ -533,30 +615,74 @@ export class QueryBarUI extends Component {
-
-
- {this.isDirty() ? (
-
- ) : (
-
- )}
-
-
+ {this.renderUpdateButton()}
);
}
+
+ private renderUpdateButton() {
+ const button = (
+
+ );
+ if (this.props.showDatePicker) {
+ return (
+
+ {this.renderDatePicker()}
+ {button}
+
+ );
+ } else {
+ return button;
+ }
+ }
+
+ private renderDatePicker() {
+ if (!this.props.showDatePicker) {
+ return null;
+ }
+
+ const recentlyUsedRanges = timeHistory
+ .get()
+ .map(({ from, to }: { from: string; to: string }) => {
+ return {
+ start: from,
+ end: to,
+ };
+ });
+
+ const commonlyUsedRanges = config
+ .get('timepicker:quickRanges')
+ .map(({ from, to, display }: { from: string; to: string; display: string }) => {
+ return {
+ start: from,
+ end: to,
+ label: display,
+ };
+ });
+
+ return (
+
+
+
+ );
+ }
}
+// @ts-ignore
export const QueryBar = injectI18n(QueryBarUI);
diff --git a/src/ui/public/saved_objects/saved_object.js b/src/ui/public/saved_objects/saved_object.js
index 9287b9e313d8f..ed3bbfe9b0fb1 100644
--- a/src/ui/public/saved_objects/saved_object.js
+++ b/src/ui/public/saved_objects/saved_object.js
@@ -20,11 +20,12 @@
import _ from 'lodash';
export class SavedObject {
- constructor(client, { id, type, version, attributes, error, migrationVersion } = {}) {
+ constructor(client, { id, type, version, attributes, error, migrationVersion, references } = {}) {
this._client = client;
this.id = id;
this.type = type;
this.attributes = attributes || {};
+ this.references = references || [];
this._version = version;
this.migrationVersion = migrationVersion;
if (error) {
@@ -46,9 +47,17 @@ export class SavedObject {
save() {
if (this.id) {
- return this._client.update(this.type, this.id, this.attributes, { migrationVersion: this.migrationVersion });
+ return this._client.update(
+ this.type,
+ this.id,
+ this.attributes,
+ {
+ migrationVersion: this.migrationVersion,
+ references: this.references,
+ },
+ );
} else {
- return this._client.create(this.type, this.attributes, { migrationVersion: this.migrationVersion });
+ return this._client.create(this.type, this.attributes, { migrationVersion: this.migrationVersion, references: this.references });
}
}
diff --git a/src/ui/public/saved_objects/saved_objects_client.js b/src/ui/public/saved_objects/saved_objects_client.js
index eba1acebabe4b..0ee4c2ff47ad3 100644
--- a/src/ui/public/saved_objects/saved_objects_client.js
+++ b/src/ui/public/saved_objects/saved_objects_client.js
@@ -51,6 +51,7 @@ export class SavedObjectsClient {
* @property {string} [options.id] - force id on creation, not recommended
* @property {boolean} [options.overwrite=false]
* @property {object} [options.migrationVersion]
+ * @property {array} [options.references] [{ name, type, id }]
* @returns {promise} - SavedObject({ id, type, version, attributes })
*/
create = (type, attributes = {}, options = {}) => {
@@ -61,7 +62,17 @@ export class SavedObjectsClient {
const path = this._getPath([type, options.id]);
const query = _.pick(options, ['overwrite']);
- return this._request({ method: 'POST', path, query, body: { attributes, migrationVersion: options.migrationVersion } })
+ return this
+ ._request({
+ method: 'POST',
+ path,
+ query,
+ body: {
+ attributes,
+ migrationVersion: options.migrationVersion,
+ references: options.references,
+ },
+ })
.catch(error => {
if (isAutoCreateIndexError(error)) {
return showAutoCreateIndexErrorPage();
@@ -75,7 +86,7 @@ export class SavedObjectsClient {
/**
* Creates multiple documents at once
*
- * @param {array} objects - [{ type, id, attributes, migrationVersion }]
+ * @param {array} objects - [{ type, id, attributes, references, migrationVersion }]
* @param {object} [options={}]
* @property {boolean} [options.overwrite=false]
* @returns {promise} - { savedObjects: [{ id, type, version, attributes, error: { message } }]}
@@ -117,6 +128,7 @@ export class SavedObjectsClient {
* @property {integer} [options.page=1]
* @property {integer} [options.perPage=20]
* @property {array} options.fields
+ * @property {object} [options.hasReference] - { type, id }
* @returns {promise} - { savedObjects: [ SavedObject({ id, type, version, attributes }) ]}
*/
find = (options = {}) => {
@@ -178,9 +190,10 @@ export class SavedObjectsClient {
* @param {object} options
* @prop {integer} options.version - ensures version matches that of persisted object
* @prop {object} options.migrationVersion - The optional migrationVersion of this document
+ * @prop {array} option.references - the references of the saved object
* @returns {promise}
*/
- update(type, id, attributes, { version, migrationVersion } = {}) {
+ update(type, id, attributes, { version, migrationVersion, references } = {}) {
if (!type || !id || !attributes) {
return Promise.reject(new Error('requires type, id and attributes'));
}
@@ -189,6 +202,7 @@ export class SavedObjectsClient {
const body = {
attributes,
migrationVersion,
+ references,
version
};
diff --git a/src/ui/public/styles/disable_animations/disable_animations.css b/src/ui/public/styles/disable_animations/disable_animations.css
index 9cf9d9eb4e5f2..a5ca0f417e669 100644
--- a/src/ui/public/styles/disable_animations/disable_animations.css
+++ b/src/ui/public/styles/disable_animations/disable_animations.css
@@ -11,4 +11,7 @@
-webkit-transition-duration: 0s !important;
transition-duration: 0s !important;
+
+ -webkit-transition-delay: 0s !important;
+ transition-delay: 0s !important;
}
diff --git a/src/legacy/core_plugins/kibana/server/lib/export/collect_dashboards.js b/src/ui/public/timefilter/time_history.d.ts
similarity index 56%
rename from src/legacy/core_plugins/kibana/server/lib/export/collect_dashboards.js
rename to src/ui/public/timefilter/time_history.d.ts
index 969c2add1364d..4a7331dbb8c58 100644
--- a/src/legacy/core_plugins/kibana/server/lib/export/collect_dashboards.js
+++ b/src/ui/public/timefilter/time_history.d.ts
@@ -17,27 +17,15 @@
* under the License.
*/
-import { collectPanels } from './collect_panels';
-
-export async function collectDashboards(savedObjectsClient, ids) {
-
- if (ids.length === 0) return [];
-
- const objects = ids.map(id => {
- return {
- type: 'dashboard',
- id: id
- };
- });
-
- const { saved_objects: savedObjects } = await savedObjectsClient.bulkGet(objects);
- const results = await Promise.all(savedObjects.map(d => collectPanels(savedObjectsClient, d)));
-
- return results
- .reduce((acc, result) => acc.concat(result), [])
- .reduce((acc, obj) => {
- if (!acc.find(o => o.id === obj.id)) acc.push(obj);
- return acc;
- }, []);
+interface TimeRange {
+ from: string;
+ to: string;
+ mode?: string;
+}
+export interface TimeHistory {
+ add: (options: TimeRange) => void;
+ get: () => TimeRange[];
}
+
+export const timeHistory: TimeHistory;
diff --git a/test/api_integration/apis/management/saved_objects/relationships.js b/test/api_integration/apis/management/saved_objects/relationships.js
index 45b0a8b82e4a2..e31a5fe3aaa7e 100644
--- a/test/api_integration/apis/management/saved_objects/relationships.js
+++ b/test/api_integration/apis/management/saved_objects/relationships.js
@@ -40,8 +40,8 @@ export default function ({ getService }) {
after(() => esArchiver.unload('management/saved_objects'));
const SEARCH_RESPONSE_SCHEMA = Joi.object().keys({
- visualizations: GENERIC_RESPONSE_SCHEMA,
- indexPatterns: GENERIC_RESPONSE_SCHEMA,
+ visualization: GENERIC_RESPONSE_SCHEMA,
+ 'index-pattern': GENERIC_RESPONSE_SCHEMA,
});
describe('searches', async () => {
@@ -61,13 +61,13 @@ export default function ({ getService }) {
.expect(200)
.then(resp => {
expect(resp.body).to.eql({
- visualizations: [
+ visualization: [
{
id: 'a42c0580-3224-11e8-a572-ffca06da1357',
title: 'VisualizationFromSavedSearch',
},
],
- indexPatterns: [
+ 'index-pattern': [
{
id: '8963ca30-3224-11e8-a572-ffca06da1357',
title: 'saved_objects*',
@@ -85,7 +85,7 @@ export default function ({ getService }) {
describe('dashboards', async () => {
const DASHBOARD_RESPONSE_SCHEMA = Joi.object().keys({
- visualizations: GENERIC_RESPONSE_SCHEMA,
+ visualization: GENERIC_RESPONSE_SCHEMA,
});
it('should validate dashboard response schema', async () => {
@@ -104,7 +104,7 @@ export default function ({ getService }) {
.expect(200)
.then(resp => {
expect(resp.body).to.eql({
- visualizations: [
+ visualization: [
{
id: 'add810b0-3224-11e8-a572-ffca06da1357',
title: 'Visualization',
@@ -128,7 +128,8 @@ export default function ({ getService }) {
describe('visualizations', async () => {
const VISUALIZATIONS_RESPONSE_SCHEMA = Joi.object().keys({
- dashboards: GENERIC_RESPONSE_SCHEMA,
+ dashboard: GENERIC_RESPONSE_SCHEMA,
+ search: GENERIC_RESPONSE_SCHEMA,
});
it('should validate visualization response schema', async () => {
@@ -147,7 +148,13 @@ export default function ({ getService }) {
.expect(200)
.then(resp => {
expect(resp.body).to.eql({
- dashboards: [
+ search: [
+ {
+ id: '960372e0-3224-11e8-a572-ffca06da1357',
+ title: 'OneRecord'
+ },
+ ],
+ dashboard: [
{
id: 'b70c7ae0-3224-11e8-a572-ffca06da1357',
title: 'Dashboard',
@@ -166,8 +173,8 @@ export default function ({ getService }) {
describe('index patterns', async () => {
const INDEX_PATTERN_RESPONSE_SCHEMA = Joi.object().keys({
- searches: GENERIC_RESPONSE_SCHEMA,
- visualizations: GENERIC_RESPONSE_SCHEMA,
+ search: GENERIC_RESPONSE_SCHEMA,
+ visualization: GENERIC_RESPONSE_SCHEMA,
});
it('should validate visualization response schema', async () => {
@@ -186,13 +193,13 @@ export default function ({ getService }) {
.expect(200)
.then(resp => {
expect(resp.body).to.eql({
- searches: [
+ search: [
{
id: '960372e0-3224-11e8-a572-ffca06da1357',
title: 'OneRecord',
},
],
- visualizations: [
+ visualization: [
{
id: 'add810b0-3224-11e8-a572-ffca06da1357',
title: 'Visualization',
diff --git a/test/api_integration/apis/saved_objects/bulk_create.js b/test/api_integration/apis/saved_objects/bulk_create.js
index 153dda4691fa6..074af9f775dde 100644
--- a/test/api_integration/apis/saved_objects/bulk_create.js
+++ b/test/api_integration/apis/saved_objects/bulk_create.js
@@ -69,7 +69,8 @@ export default function ({ getService }) {
version: 1,
attributes: {
title: 'A great new dashboard'
- }
+ },
+ references: [],
},
]
});
@@ -101,7 +102,8 @@ export default function ({ getService }) {
version: 1,
attributes: {
title: 'An existing visualization'
- }
+ },
+ references: [],
},
{
type: 'dashboard',
@@ -110,7 +112,8 @@ export default function ({ getService }) {
version: 1,
attributes: {
title: 'A great new dashboard'
- }
+ },
+ references: [],
},
]
});
diff --git a/test/api_integration/apis/saved_objects/bulk_get.js b/test/api_integration/apis/saved_objects/bulk_get.js
index 68773e5124039..da208a5cbe70a 100644
--- a/test/api_integration/apis/saved_objects/bulk_get.js
+++ b/test/api_integration/apis/saved_objects/bulk_get.js
@@ -68,7 +68,15 @@ export default function ({ getService }) {
visState: resp.body.saved_objects[0].attributes.visState,
uiStateJSON: resp.body.saved_objects[0].attributes.uiStateJSON,
kibanaSavedObjectMeta: resp.body.saved_objects[0].attributes.kibanaSavedObjectMeta
- }
+ },
+ migrationVersion: {
+ visualization: '7.0.0',
+ },
+ references: [{
+ name: 'kibanaSavedObjectMeta.searchSourceJSON.index',
+ type: 'index-pattern',
+ id: '91200a00-9efd-11e7-acb3-3dab96693fab',
+ }],
},
{
id: 'does not exist',
@@ -86,7 +94,8 @@ export default function ({ getService }) {
attributes: {
buildNum: 8467,
defaultIndex: '91200a00-9efd-11e7-acb3-3dab96693fab'
- }
+ },
+ references: [],
}
]
});
diff --git a/test/api_integration/apis/saved_objects/create.js b/test/api_integration/apis/saved_objects/create.js
index 379539928ebaf..a4e66318fb01e 100644
--- a/test/api_integration/apis/saved_objects/create.js
+++ b/test/api_integration/apis/saved_objects/create.js
@@ -54,7 +54,11 @@ export default function ({ getService }) {
version: 1,
attributes: {
title: 'My favorite vis'
- }
+ },
+ migrationVersion: {
+ visualization: '7.0.0',
+ },
+ references: [],
});
});
});
@@ -95,7 +99,11 @@ export default function ({ getService }) {
version: 1,
attributes: {
title: 'My favorite vis'
- }
+ },
+ migrationVersion: {
+ visualization: '7.0.0',
+ },
+ references: [],
});
});
diff --git a/test/api_integration/apis/saved_objects/find.js b/test/api_integration/apis/saved_objects/find.js
index c9b1e9fc73f4a..515f4501517bc 100644
--- a/test/api_integration/apis/saved_objects/find.js
+++ b/test/api_integration/apis/saved_objects/find.js
@@ -45,7 +45,8 @@ export default function ({ getService }) {
version: 1,
attributes: {
'title': 'Count of requests'
- }
+ },
+ references: [],
}
]
});
diff --git a/test/api_integration/apis/saved_objects/get.js b/test/api_integration/apis/saved_objects/get.js
index 22ea4798f4324..0734918f5f3e4 100644
--- a/test/api_integration/apis/saved_objects/get.js
+++ b/test/api_integration/apis/saved_objects/get.js
@@ -42,6 +42,9 @@ export default function ({ getService }) {
type: 'visualization',
updated_at: '2017-09-21T18:51:23.794Z',
version: resp.body.version,
+ migrationVersion: {
+ visualization: '7.0.0',
+ },
attributes: {
title: 'Count of requests',
description: '',
@@ -50,7 +53,12 @@ export default function ({ getService }) {
visState: resp.body.attributes.visState,
uiStateJSON: resp.body.attributes.uiStateJSON,
kibanaSavedObjectMeta: resp.body.attributes.kibanaSavedObjectMeta
- }
+ },
+ references: [{
+ type: 'index-pattern',
+ name: 'kibanaSavedObjectMeta.searchSourceJSON.index',
+ id: '91200a00-9efd-11e7-acb3-3dab96693fab',
+ }],
});
})
));
diff --git a/test/api_integration/apis/saved_objects/migrations.js b/test/api_integration/apis/saved_objects/migrations.js
index 260609d3b881e..a4993658837f2 100644
--- a/test/api_integration/apis/saved_objects/migrations.js
+++ b/test/api_integration/apis/saved_objects/migrations.js
@@ -85,11 +85,11 @@ export default ({ getService }) => {
// The docs in the alias have been migrated
assert.deepEqual(await fetchDocs({ callCluster, index }), [
- { id: 'bar:i', type: 'bar', migrationVersion: { bar: '1.9.0' }, bar: { mynum: 68 } },
- { id: 'bar:o', type: 'bar', migrationVersion: { bar: '1.9.0' }, bar: { mynum: 6 } },
- { id: 'baz:u', type: 'baz', baz: { title: 'Terrific!' } },
- { id: 'foo:a', type: 'foo', migrationVersion: { foo: '1.0.0' }, foo: { name: 'FOO A' } },
- { id: 'foo:e', type: 'foo', migrationVersion: { foo: '1.0.0' }, foo: { name: 'FOOEY' } },
+ { id: 'bar:i', type: 'bar', migrationVersion: { bar: '1.9.0' }, bar: { mynum: 68 }, references: [] },
+ { id: 'bar:o', type: 'bar', migrationVersion: { bar: '1.9.0' }, bar: { mynum: 6 }, references: [] },
+ { id: 'baz:u', type: 'baz', baz: { title: 'Terrific!' }, references: [] },
+ { id: 'foo:a', type: 'foo', migrationVersion: { foo: '1.0.0' }, foo: { name: 'FOO A' }, references: [] },
+ { id: 'foo:e', type: 'foo', migrationVersion: { foo: '1.0.0' }, foo: { name: 'FOOEY' }, references: [] },
]);
});
@@ -131,10 +131,10 @@ export default ({ getService }) => {
// The index for the initial migration has not been destroyed...
assert.deepEqual(await fetchDocs({ callCluster, index: `${index}_2` }), [
- { id: 'bar:i', type: 'bar', migrationVersion: { bar: '1.9.0' }, bar: { mynum: 68 } },
- { id: 'bar:o', type: 'bar', migrationVersion: { bar: '1.9.0' }, bar: { mynum: 6 } },
- { id: 'foo:a', type: 'foo', migrationVersion: { foo: '1.0.0' }, foo: { name: 'FOO A' } },
- { id: 'foo:e', type: 'foo', migrationVersion: { foo: '1.0.0' }, foo: { name: 'FOOEY' } },
+ { id: 'bar:i', type: 'bar', migrationVersion: { bar: '1.9.0' }, bar: { mynum: 68 }, references: [] },
+ { id: 'bar:o', type: 'bar', migrationVersion: { bar: '1.9.0' }, bar: { mynum: 6 }, references: [] },
+ { id: 'foo:a', type: 'foo', migrationVersion: { foo: '1.0.0' }, foo: { name: 'FOO A' }, references: [] },
+ { id: 'foo:e', type: 'foo', migrationVersion: { foo: '1.0.0' }, foo: { name: 'FOOEY' }, references: [] },
]);
// The docs were migrated again...
@@ -144,15 +144,17 @@ export default ({ getService }) => {
type: 'bar',
migrationVersion: { bar: '2.3.4' },
bar: { mynum: 68, name: 'NAME i' },
+ references: [],
},
{
id: 'bar:o',
type: 'bar',
migrationVersion: { bar: '2.3.4' },
bar: { mynum: 6, name: 'NAME o' },
+ references: [],
},
- { id: 'foo:a', type: 'foo', migrationVersion: { foo: '2.0.1' }, foo: { name: 'FOO Av2' } },
- { id: 'foo:e', type: 'foo', migrationVersion: { foo: '2.0.1' }, foo: { name: 'FOOEYv2' } },
+ { id: 'foo:a', type: 'foo', migrationVersion: { foo: '2.0.1' }, foo: { name: 'FOO Av2' }, references: [] },
+ { id: 'foo:e', type: 'foo', migrationVersion: { foo: '2.0.1' }, foo: { name: 'FOOEYv2' }, references: [] },
]);
});
@@ -203,7 +205,7 @@ export default ({ getService }) => {
// The docs in the alias have been migrated
assert.deepEqual(await fetchDocs({ callCluster, index }), [
- { id: 'foo:lotr', type: 'foo', migrationVersion: { foo: '1.0.0' }, foo: { name: 'LOTR' } },
+ { id: 'foo:lotr', type: 'foo', migrationVersion: { foo: '1.0.0' }, foo: { name: 'LOTR' }, references: [] },
]);
});
});
diff --git a/test/api_integration/apis/saved_objects/update.js b/test/api_integration/apis/saved_objects/update.js
index e6ca3d0317bf3..a00ab69783cb0 100644
--- a/test/api_integration/apis/saved_objects/update.js
+++ b/test/api_integration/apis/saved_objects/update.js
@@ -51,7 +51,8 @@ export default function ({ getService }) {
version: 2,
attributes: {
title: 'My second favorite vis'
- }
+ },
+ references: [],
});
});
});
diff --git a/test/functional/apps/discover/_discover.js b/test/functional/apps/discover/_discover.js
index 64e2a2fdc952e..dad40daf0d6a7 100644
--- a/test/functional/apps/discover/_discover.js
+++ b/test/functional/apps/discover/_discover.js
@@ -18,6 +18,7 @@
*/
import expect from 'expect.js';
+import moment from 'moment';
export default function ({ getService, getPageObjects }) {
const log = getService('log');
@@ -153,8 +154,13 @@ export default function ({ getService, getPageObjects }) {
await PageObjects.visualize.waitForVisualization();
await PageObjects.discover.brushHistogram(0, 1);
await PageObjects.visualize.waitForVisualization();
- const actualTimeString = await PageObjects.header.getPrettyDuration();
- expect(actualTimeString).to.be('September 19th 2015, 23:59:02.606 to September 20th 2015, 02:56:40.744');
+ const newFromTime = await PageObjects.header.getFromTime();
+ const newToTime = await PageObjects.header.getToTime();
+
+ const newDurationHours = moment.duration(moment(newToTime) - moment(newFromTime)).asHours();
+ if (newDurationHours < 1 || newDurationHours >= 5) {
+ throw new Error(`expected new duration of ${newDurationHours} hours to be between 1 and 5 hours`);
+ }
});
it('should show correct initial chart interval of Auto', async function () {
diff --git a/test/functional/apps/discover/index.js b/test/functional/apps/discover/index.js
index 420c0de35115c..6e7aedc250351 100644
--- a/test/functional/apps/discover/index.js
+++ b/test/functional/apps/discover/index.js
@@ -25,7 +25,7 @@ export default function ({ getService, loadTestFile }) {
this.tags('ciGroup6');
before(function () {
- return browser.setWindowSize(1200, 800);
+ return browser.setWindowSize(1250, 800);
});
after(function unloadMakelogs() {
diff --git a/test/functional/apps/visualize/_pie_chart.js b/test/functional/apps/visualize/_pie_chart.js
index dcab846c277a1..3b9442e1ffad0 100644
--- a/test/functional/apps/visualize/_pie_chart.js
+++ b/test/functional/apps/visualize/_pie_chart.js
@@ -213,6 +213,69 @@ export default function ({ getService, getPageObjects }) {
});
});
describe('multi series slice', () => {
+ before(async () => {
+ log.debug('navigateToApp visualize');
+ await PageObjects.visualize.navigateToNewVisualization();
+ log.debug('clickPieChart');
+ await PageObjects.visualize.clickPieChart();
+ await PageObjects.visualize.clickNewSearch();
+ log.debug('Set absolute time range from \"' + fromTime + '\" to \"' + toTime + '\"');
+ await PageObjects.header.setAbsoluteRange(fromTime, toTime);
+ log.debug('select bucket Split Slices');
+ await PageObjects.visualize.clickBucket('Split Slices');
+ log.debug('Click aggregation Histogram');
+ await PageObjects.visualize.selectAggregation('Histogram');
+ log.debug('Click field memory');
+ await PageObjects.visualize.selectField('memory');
+ await PageObjects.header.waitUntilLoadingHasFinished();
+ await PageObjects.common.sleep(1003);
+ log.debug('setNumericInterval 4000');
+ await PageObjects.visualize.setNumericInterval('40000');
+ log.debug('Toggle previous editor');
+ await PageObjects.visualize.toggleAggregationEditor(2);
+ await PageObjects.visualize.clickAddBucket();
+ log.debug('select bucket Split Slices');
+ await PageObjects.visualize.clickBucket('Split Slices');
+ await PageObjects.visualize.selectAggregation('Terms');
+ await PageObjects.visualize.selectField('geo.dest');
+ await PageObjects.visualize.clickGo();
+ });
+
+ it ('should show correct chart', async () => {
+ const expectedTableData = [ [ '0', '55', 'CN', '14' ], [ '0', '55', 'IN', '9' ], [ '0', '55', 'MX', '3' ],
+ [ '0', '55', 'US', '3' ], [ '0', '55', 'BR', '2' ], [ '40,000', '50', 'CN', '7' ],
+ [ '40,000', '50', 'IN', '7' ], [ '40,000', '50', 'US', '5' ], [ '40,000', '50', 'MY', '3' ],
+ [ '40,000', '50', 'ET', '2' ], [ '80,000', '41', 'CN', '9' ], [ '80,000', '41', 'IN', '4' ],
+ [ '80,000', '41', 'US', '4' ], [ '80,000', '41', 'BR', '3' ], [ '80,000', '41', 'IT', '2' ],
+ [ '120,000', '43', 'CN', '8' ], [ '120,000', '43', 'IN', '5' ], [ '120,000', '43', 'US', '4' ],
+ [ '120,000', '43', 'JP', '3' ], [ '120,000', '43', 'RU', '3' ], [ '160,000', '44', 'CN', '15' ],
+ [ '160,000', '44', 'IN', '5' ], [ '160,000', '44', 'IQ', '2' ], [ '160,000', '44', 'JP', '2' ],
+ [ '160,000', '44', 'NG', '2' ], [ '200,000', '40', 'IN', '7' ], [ '200,000', '40', 'CN', '6' ],
+ [ '200,000', '40', 'MX', '3' ], [ '200,000', '40', 'BR', '2' ], [ '200,000', '40', 'ID', '2' ],
+ [ '240,000', '46', 'CN', '6' ], [ '240,000', '46', 'IN', '6' ], [ '240,000', '46', 'US', '6' ],
+ [ '240,000', '46', 'NG', '3' ], [ '240,000', '46', 'CH', '2' ], [ '280,000', '39', 'CN', '11' ],
+ [ '280,000', '39', 'IN', '5' ], [ '280,000', '39', 'BR', '2' ], [ '280,000', '39', 'IT', '2' ],
+ [ '280,000', '39', 'NG', '2' ], [ '320,000', '40', 'CN', '7' ], [ '320,000', '40', 'US', '6' ],
+ [ '320,000', '40', 'MX', '4' ], [ '320,000', '40', 'BD', '2' ], [ '320,000', '40', 'ID', '2' ],
+ [ '360,000', '47', 'IN', '8' ], [ '360,000', '47', 'CN', '6' ], [ '360,000', '47', 'US', '4' ],
+ [ '360,000', '47', 'BD', '3' ], [ '360,000', '47', 'BR', '2' ] ];
+
+ await inspector.open();
+ await inspector.setTablePageSize(50);
+ await inspector.expectTableData(expectedTableData);
+ await inspector.close();
+ });
+
+ it('should correctly filter on legend', async () => {
+ const expectedTableData = [ '0', 'CN', '40,000', 'CN', '80,000', 'CN', '120,000', 'CN', '160,000', 'CN',
+ '200,000', 'CN', '240,000', 'CN', '280,000', 'CN', '320,000', 'CN', '360,000', 'CN' ];
+ await PageObjects.visualize.filterLegend('CN');
+ await PageObjects.visualize.waitForVisualization();
+ await pieChart.expectPieChartLabels(expectedTableData);
+ await filterBar.removeFilter('geo.dest');
+ await PageObjects.visualize.waitForVisualization();
+ });
+
it('should still showing pie chart when a subseries have zero data', async function () {
await PageObjects.visualize.navigateToNewVisualization();
log.debug('clickPieChart');
diff --git a/test/functional/apps/visualize/_vertical_bar_chart.js b/test/functional/apps/visualize/_vertical_bar_chart.js
index 330f99d53340d..0954f4e5e7f88 100644
--- a/test/functional/apps/visualize/_vertical_bar_chart.js
+++ b/test/functional/apps/visualize/_vertical_bar_chart.js
@@ -23,6 +23,7 @@ export default function ({ getService, getPageObjects }) {
const log = getService('log');
const retry = getService('retry');
const inspector = getService('inspector');
+ const filterBar = getService('filterBar');
const PageObjects = getPageObjects(['common', 'visualize', 'header']);
describe('vertical bar chart', function () {
@@ -257,6 +258,16 @@ export default function ({ getService, getPageObjects }) {
const legendEntries = await PageObjects.visualize.getLegendEntries();
expect(legendEntries).to.eql(expectedEntries);
});
+
+ it ('should correctly filter by legend', async () => {
+ await PageObjects.visualize.filterLegend('200');
+ await PageObjects.visualize.waitForVisualization();
+ const legendEntries = await PageObjects.visualize.getLegendEntries();
+ const expectedEntries = ['200'];
+ expect(legendEntries).to.eql(expectedEntries);
+ await filterBar.removeFilter('response.raw');
+ await PageObjects.visualize.waitForVisualization();
+ });
});
describe('vertical bar with multiple splits', function () {
diff --git a/test/functional/config.js b/test/functional/config.js
index aabc2c5eaea32..86d38e1782d0a 100644
--- a/test/functional/config.js
+++ b/test/functional/config.js
@@ -33,6 +33,7 @@ import {
VisualBuilderPageProvider,
TimelionPageProvider,
SharePageProvider,
+ TimePickerPageProvider,
} from './page_objects';
import {
@@ -94,6 +95,7 @@ export default async function ({ readConfigFile }) {
visualBuilder: VisualBuilderPageProvider,
timelion: TimelionPageProvider,
share: SharePageProvider,
+ timePicker: TimePickerPageProvider,
},
services: {
es: commonConfig.get('services.es'),
diff --git a/test/functional/page_objects/common_page.js b/test/functional/page_objects/common_page.js
index bb66169815b50..1a7d671055d24 100644
--- a/test/functional/page_objects/common_page.js
+++ b/test/functional/page_objects/common_page.js
@@ -90,9 +90,17 @@ export function CommonPageProvider({ getService, getPageObjects }) {
}
- navigateToApp(appName) {
+ /**
+ * @param {string} appName - name of the app
+ * @param {object} [opts] - optional options object
+ * @param {object} [opts.appConfig] - overrides for appConfig, e.g. { pathname, hash }
+ */
+ navigateToApp(appName, opts = { appConfig: {} }) {
const self = this;
- const appUrl = getUrl.noAuth(config.get('servers.kibana'), config.get(['apps', appName]));
+ const appUrl = getUrl.noAuth(config.get('servers.kibana'), {
+ ...config.get(['apps', appName]),
+ ...opts.appConfig,
+ });
log.debug('navigating to ' + appName + ' url: ' + appUrl);
function navigateTo(url) {
diff --git a/test/functional/page_objects/home_page.js b/test/functional/page_objects/home_page.js
index 54c64e4bf0ed5..7c0d2f7faba63 100644
--- a/test/functional/page_objects/home_page.js
+++ b/test/functional/page_objects/home_page.js
@@ -22,11 +22,6 @@ export function HomePageProvider({ getService }) {
const retry = getService('retry');
class HomePage {
-
- async clickKibanaIcon() {
- await testSubjects.click('kibanaLogo');
- }
-
async clickSynopsis(title) {
await testSubjects.click(`homeSynopsisLink${title}`);
}
diff --git a/test/functional/page_objects/index.js b/test/functional/page_objects/index.js
index 04fc7240480ff..5d561a42e2fa2 100644
--- a/test/functional/page_objects/index.js
+++ b/test/functional/page_objects/index.js
@@ -32,3 +32,4 @@ export { PointSeriesPageProvider } from './point_series_page';
export { VisualBuilderPageProvider } from './visual_builder_page';
export { TimelionPageProvider } from './timelion_page';
export { SharePageProvider } from './share_page';
+export { TimePickerPageProvider } from './time_picker';
diff --git a/test/functional/page_objects/time_picker.js b/test/functional/page_objects/time_picker.js
new file mode 100644
index 0000000000000..77ba480c2907f
--- /dev/null
+++ b/test/functional/page_objects/time_picker.js
@@ -0,0 +1,122 @@
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+export function TimePickerPageProvider({ getService }) {
+ const log = getService('log');
+ const retry = getService('retry');
+ const find = getService('find');
+ const testSubjects = getService('testSubjects');
+
+ class TimePickerPage {
+
+ async isQuickSelectMenuOpen() {
+ return await testSubjects.exists('superDatePickerQuickMenu');
+ }
+
+ async openQuickSelectTimeMenu() {
+ log.debug('openQuickSelectTimeMenu');
+ const isMenuOpen = await this.isQuickSelectMenuOpen();
+ if (!isMenuOpen) {
+ log.debug('opening quick select menu');
+ await retry.try(async () => {
+ await testSubjects.click('superDatePickerToggleQuickMenuButton');
+ });
+ }
+ }
+
+ async closeQuickSelectTimeMenu() {
+ log.debug('closeQuickSelectTimeMenu');
+ const isMenuOpen = await this.isQuickSelectMenuOpen();
+ if (isMenuOpen) {
+ log.debug('closing quick select menu');
+ await retry.try(async () => {
+ await testSubjects.click('superDatePickerToggleQuickMenuButton');
+ });
+ }
+ }
+
+ async showStartEndTimes() {
+ const isShowDatesButton = await testSubjects.exists('superDatePickerShowDatesButton');
+ if (isShowDatesButton) {
+ await testSubjects.click('superDatePickerShowDatesButton');
+ }
+ }
+
+ async getRefreshConfig(keepQuickSelectOpen = false) {
+ await this.openQuickSelectTimeMenu();
+ const interval = await testSubjects.getAttribute('superDatePickerRefreshIntervalInput', 'value');
+
+ let selectedUnit;
+ const select = await testSubjects.find('superDatePickerRefreshIntervalUnitsSelect');
+ const options = await find.allDescendantDisplayedByCssSelector('option', select);
+ await Promise.all(options.map(async (optionElement) => {
+ const isSelected = await optionElement.isSelected();
+ if (isSelected) {
+ selectedUnit = await optionElement.getVisibleText();
+ }
+ }));
+
+ const toggleButtonText = await testSubjects.getVisibleText('superDatePickerToggleRefreshButton');
+ if (!keepQuickSelectOpen) {
+ await this.closeQuickSelectTimeMenu();
+ }
+
+ return {
+ interval,
+ units: selectedUnit,
+ isPaused: toggleButtonText === 'Start' ? true : false
+ };
+ }
+
+ async getTimeConfig() {
+ await this.showStartEndTimes();
+ const start = await testSubjects.getVisibleText('superDatePickerstartDatePopoverButton');
+ const end = await testSubjects.getVisibleText('superDatePickerendDatePopoverButton');
+ return {
+ start,
+ end
+ };
+ }
+
+ async pauseAutoRefresh() {
+ log.debug('pauseAutoRefresh');
+ const refreshConfig = await this.getRefreshConfig(true);
+ if (!refreshConfig.isPaused) {
+ log.debug('pause auto refresh');
+ await testSubjects.click('superDatePickerToggleRefreshButton');
+ await this.closeQuickSelectTimeMenu();
+ }
+
+ await this.closeQuickSelectTimeMenu();
+ }
+
+ async resumeAutoRefresh() {
+ log.debug('resumeAutoRefresh');
+ const refreshConfig = await this.getRefreshConfig(true);
+ if (refreshConfig.isPaused) {
+ log.debug('resume auto refresh');
+ await testSubjects.click('superDatePickerToggleRefreshButton');
+ }
+
+ await this.closeQuickSelectTimeMenu();
+ }
+ }
+
+ return new TimePickerPage();
+}
diff --git a/test/functional/services/apps_menu.js b/test/functional/services/apps_menu.js
index 2d7e7f49cf682..d57ad68f9297f 100644
--- a/test/functional/services/apps_menu.js
+++ b/test/functional/services/apps_menu.js
@@ -21,7 +21,7 @@ export function AppsMenuProvider({ getService }) {
const testSubjects = getService('testSubjects');
const log = getService('log');
const retry = getService('retry');
- const flyout = getService('flyout');
+ const globalNav = getService('globalNav');
return new class AppsMenu {
async readLinks() {
@@ -42,38 +42,31 @@ export function AppsMenuProvider({ getService }) {
}
async clickLink(appTitle) {
- log.debug(`click "${appTitle}" tab`);
- await this._ensureMenuOpen();
- const container = await testSubjects.find('appsMenu');
- const link = await container.findByPartialLinkText(appTitle);
- await link.click();
+ try {
+ log.debug(`click "${appTitle}" tab`);
+ await this._ensureMenuOpen();
+ const container = await testSubjects.find('appsMenu');
+ const link = await container.findByPartialLinkText(appTitle);
+ await link.click();
+ } finally {
+ await this._ensureMenuClosed();
+ }
}
async _ensureMenuOpen() {
- // some apps render flyouts that cover the global nav menu, so we make sure all flyouts are
- // closed before trying to use the appsMenu
- await flyout.ensureAllClosed();
-
- if (!await testSubjects.exists('appsMenu')) {
- await testSubjects.click('appsMenuButton');
- await retry.waitFor('apps menu displayed', async () => (
- await testSubjects.exists('appsMenu')
+ if (!await testSubjects.exists('navDrawer&expanded')) {
+ await testSubjects.moveMouseTo('navDrawer');
+ await retry.waitFor('apps drawer open', async () => (
+ await testSubjects.exists('navDrawer&expanded')
));
}
}
async _ensureMenuClosed() {
- const [appsMenuButtonExists, appsMenuExists] = await Promise.all([
- testSubjects.exists('appsMenuButton'),
- testSubjects.exists('appsMenu')
- ]);
-
- if (appsMenuButtonExists && appsMenuExists) {
- await testSubjects.click('appsMenuButton');
- await retry.waitFor('user menu closed', async () => (
- !await testSubjects.exists('appsMenu')
- ));
- }
+ await globalNav.moveMouseToLogo();
+ await retry.waitFor('apps drawer closed', async () => (
+ await testSubjects.exists('navDrawer&collapsed')
+ ));
}
};
}
diff --git a/test/functional/services/global_nav.js b/test/functional/services/global_nav.js
index 3cfcfc4e29012..4719f8172aa3a 100644
--- a/test/functional/services/global_nav.js
+++ b/test/functional/services/global_nav.js
@@ -21,6 +21,10 @@ export function GlobalNavProvider({ getService }) {
const testSubjects = getService('testSubjects');
return new class GlobalNav {
+ async moveMouseToLogo() {
+ await testSubjects.moveMouseTo('headerGlobalNav logo');
+ }
+
async clickLogo() {
return await testSubjects.click('headerGlobalNav logo');
}
diff --git a/x-pack/package.json b/x-pack/package.json
index 79ead4b403719..48d39046fbf97 100644
--- a/x-pack/package.json
+++ b/x-pack/package.json
@@ -120,7 +120,7 @@
},
"dependencies": {
"@elastic/datemath": "5.0.2",
- "@elastic/eui": "6.7.2",
+ "@elastic/eui": "6.7.4",
"@elastic/node-crypto": "0.1.2",
"@elastic/numeral": "2.3.2",
"@kbn/babel-preset": "1.0.0",
diff --git a/x-pack/plugins/apm/public/components/app/TransactionDetails/Transaction/WaterfallContainer/Waterfall/waterfall_helpers/__snapshots__/waterfall_helpers.test.ts.snap b/x-pack/plugins/apm/public/components/app/TransactionDetails/Transaction/WaterfallContainer/Waterfall/waterfall_helpers/__snapshots__/waterfall_helpers.test.ts.snap
index 9fd18e285d0d4..4684f18241212 100644
--- a/x-pack/plugins/apm/public/components/app/TransactionDetails/Transaction/WaterfallContainer/Waterfall/waterfall_helpers/__snapshots__/waterfall_helpers.test.ts.snap
+++ b/x-pack/plugins/apm/public/components/app/TransactionDetails/Transaction/WaterfallContainer/Waterfall/waterfall_helpers/__snapshots__/waterfall_helpers.test.ts.snap
@@ -1,5 +1,29 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
+exports[`waterfall_helpers getWaterfallItems should handle cyclic references 1`] = `
+Array [
+ Object {
+ "childIds": Array [
+ "a",
+ ],
+ "id": "a",
+ "offset": 0,
+ "skew": 0,
+ "timestamp": 10,
+ },
+ Object {
+ "childIds": Array [
+ "a",
+ ],
+ "id": "a",
+ "offset": 10,
+ "parentId": "a",
+ "skew": undefined,
+ "timestamp": 20,
+ },
+]
+`;
+
exports[`waterfall_helpers getWaterfallItems should order items correctly 1`] = `
Array [
Object {
diff --git a/x-pack/plugins/apm/public/components/app/TransactionDetails/Transaction/WaterfallContainer/Waterfall/waterfall_helpers/waterfall_helpers.test.ts b/x-pack/plugins/apm/public/components/app/TransactionDetails/Transaction/WaterfallContainer/Waterfall/waterfall_helpers/waterfall_helpers.test.ts
index 70e517d4ff365..6dcc6c032cf50 100644
--- a/x-pack/plugins/apm/public/components/app/TransactionDetails/Transaction/WaterfallContainer/Waterfall/waterfall_helpers/waterfall_helpers.test.ts
+++ b/x-pack/plugins/apm/public/components/app/TransactionDetails/Transaction/WaterfallContainer/Waterfall/waterfall_helpers/waterfall_helpers.test.ts
@@ -98,6 +98,20 @@ describe('waterfall_helpers', () => {
getWaterfallItems(childrenByParentId, entryTransactionItem)
).toMatchSnapshot();
});
+
+ it('should handle cyclic references', () => {
+ const items = [
+ { id: 'a', timestamp: 10 } as IWaterfallItem,
+ { id: 'a', parentId: 'a', timestamp: 20 } as IWaterfallItem
+ ];
+ const childrenByParentId = groupBy(items, hit =>
+ hit.parentId ? hit.parentId : 'root'
+ );
+ const entryTransactionItem = childrenByParentId.root[0];
+ expect(
+ getWaterfallItems(childrenByParentId, entryTransactionItem)
+ ).toMatchSnapshot();
+ });
});
describe('getClockSkew', () => {
diff --git a/x-pack/plugins/apm/public/components/app/TransactionDetails/Transaction/WaterfallContainer/Waterfall/waterfall_helpers/waterfall_helpers.ts b/x-pack/plugins/apm/public/components/app/TransactionDetails/Transaction/WaterfallContainer/Waterfall/waterfall_helpers/waterfall_helpers.ts
index 9807787727448..4ecd9d8bf6678 100644
--- a/x-pack/plugins/apm/public/components/app/TransactionDetails/Transaction/WaterfallContainer/Waterfall/waterfall_helpers/waterfall_helpers.ts
+++ b/x-pack/plugins/apm/public/components/app/TransactionDetails/Transaction/WaterfallContainer/Waterfall/waterfall_helpers/waterfall_helpers.ts
@@ -155,10 +155,15 @@ export function getWaterfallItems(
childrenByParentId: IWaterfallGroup,
entryTransactionItem: IWaterfallItem
) {
+ const visitedWaterfallItemSet = new Set();
function getSortedChildren(
item: IWaterfallItem,
parentItem?: IWaterfallItem
): IWaterfallItem[] {
+ if (visitedWaterfallItemSet.has(item)) {
+ return [];
+ }
+ visitedWaterfallItemSet.add(item);
const children = sortBy(childrenByParentId[item.id] || [], 'timestamp');
item.childIds = children.map(child => child.id);
diff --git a/x-pack/plugins/apm/public/components/shared/charts/CustomPlot/Legends.js b/x-pack/plugins/apm/public/components/shared/charts/CustomPlot/Legends.js
index 440f93ef409e1..7d2f3a1b7e04d 100644
--- a/x-pack/plugins/apm/public/components/shared/charts/CustomPlot/Legends.js
+++ b/x-pack/plugins/apm/public/components/shared/charts/CustomPlot/Legends.js
@@ -19,8 +19,7 @@ import {
const Container = styled.div`
display: flex;
- align-items: center;
- justify-content: space-around;
+ margin-left: ${px(unit * 5)};
flex-wrap: wrap;
/* add margin to all direct descendant divs */
diff --git a/x-pack/plugins/apm/public/components/shared/charts/CustomPlot/test/__snapshots__/CustomPlot.test.js.snap b/x-pack/plugins/apm/public/components/shared/charts/CustomPlot/test/__snapshots__/CustomPlot.test.js.snap
index c5bbba6b8c830..37dfb61f95f8f 100644
--- a/x-pack/plugins/apm/public/components/shared/charts/CustomPlot/test/__snapshots__/CustomPlot.test.js.snap
+++ b/x-pack/plugins/apm/public/components/shared/charts/CustomPlot/test/__snapshots__/CustomPlot.test.js.snap
@@ -2673,14 +2673,7 @@ Array [
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
- -webkit-align-items: center;
- -webkit-box-align: center;
- -ms-flex-align: center;
- align-items: center;
- -webkit-box-pack: space-around;
- -webkit-justify-content: space-around;
- -ms-flex-pack: space-around;
- justify-content: space-around;
+ margin-left: 80px;
-webkit-flex-wrap: wrap;
-ms-flex-wrap: wrap;
flex-wrap: wrap;
@@ -5716,14 +5709,7 @@ Array [
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
- -webkit-align-items: center;
- -webkit-box-align: center;
- -ms-flex-align: center;
- align-items: center;
- -webkit-box-pack: space-around;
- -webkit-justify-content: space-around;
- -ms-flex-pack: space-around;
- justify-content: space-around;
+ margin-left: 80px;
-webkit-flex-wrap: wrap;
-ms-flex-wrap: wrap;
flex-wrap: wrap;
diff --git a/x-pack/plugins/canvas/canvas_plugin_src/uis/arguments/image_upload/forms/file.js b/x-pack/plugins/canvas/canvas_plugin_src/uis/arguments/image_upload/forms/file.js
index af8dc1cf37d13..c51c949568dc2 100644
--- a/x-pack/plugins/canvas/canvas_plugin_src/uis/arguments/image_upload/forms/file.js
+++ b/x-pack/plugins/canvas/canvas_plugin_src/uis/arguments/image_upload/forms/file.js
@@ -5,11 +5,21 @@
*/
import React from 'react';
import PropTypes from 'prop-types';
+import { EuiFilePicker } from '@elastic/eui';
import { Loading } from '../../../../../public/components/loading/loading';
-import { FileUpload } from '../../../../../public/components/file_upload';
-export const FileForm = ({ loading, onUpload }) =>
- loading ? : ;
+export const FileForm = ({ loading, onChange }) =>
+ loading ? (
+
+ ) : (
+
+ );
FileForm.propTypes = {
loading: PropTypes.bool,
diff --git a/x-pack/plugins/canvas/canvas_plugin_src/uis/arguments/image_upload/index.js b/x-pack/plugins/canvas/canvas_plugin_src/uis/arguments/image_upload/index.js
index d40182a1121cd..e667169b99815 100644
--- a/x-pack/plugins/canvas/canvas_plugin_src/uis/arguments/image_upload/index.js
+++ b/x-pack/plugins/canvas/canvas_plugin_src/uis/arguments/image_upload/index.js
@@ -7,6 +7,7 @@
import React from 'react';
import PropTypes from 'prop-types';
import { EuiSpacer, EuiButtonGroup } from '@elastic/eui';
+import { get } from 'lodash';
import { AssetPicker } from '../../../../public/components/asset_picker';
import { elasticOutline } from '../../../lib/elastic_outline';
import { resolveFromArgs } from '../../../../common/lib/resolve_dataurl';
@@ -14,6 +15,7 @@ import { isValidHttpUrl } from '../../../../common/lib/httpurl';
import { encode } from '../../../../common/lib/dataurl';
import { templateFromReactComponent } from '../../../../public/lib/template_from_react_component';
import './image_upload.scss';
+import { VALID_IMAGE_TYPES } from '../../../../common/lib/constants';
import { FileForm, LinkForm } from './forms';
class ImageUpload extends React.Component {
@@ -71,17 +73,21 @@ class ImageUpload extends React.Component {
handleUpload = files => {
const { onAssetAdd } = this.props;
- const [upload] = files;
- this.setState({ loading: true }); // start loading indicator
+ const [file] = files;
- encode(upload)
- .then(dataurl => onAssetAdd('dataurl', dataurl))
- .then(assetId => {
- this.updateAST(assetId);
+ const [type, subtype] = get(file, 'type', '').split('/');
+ if (type === 'image' && VALID_IMAGE_TYPES.indexOf(subtype) >= 0) {
+ this.setState({ loading: true }); // start loading indicator
- // this component can go away when onValueChange is called, check for _isMounted
- this._isMounted && this.setState({ loading: false }); // set loading state back to false
- });
+ encode(file)
+ .then(dataurl => onAssetAdd('dataurl', dataurl))
+ .then(assetId => {
+ this.updateAST(assetId);
+
+ // this component can go away when onValueChange is called, check for _isMounted
+ this._isMounted && this.setState({ loading: false }); // set loading state back to false
+ });
+ }
};
changeUrlType = optionId => {
@@ -119,7 +125,7 @@ class ImageUpload extends React.Component {
);
const forms = {
- file: ,
+ file: ,
link: (
this.setState({ isModalVisible: true });
closeModal = () => this.setState({ isModalVisible: false });
@@ -52,6 +59,13 @@ export class AssetManager extends React.PureComponent {
this.props.removeAsset(this.state.deleteId);
};
+ handleFileUpload = files => {
+ this.setState({ loading: true });
+ Promise.all(Array.from(files).map(file => this.props.onAssetAdd(file))).finally(() => {
+ this._isMounted && this.setState({ loading: false });
+ });
+ };
+
addElement = assetId => {
this.props.addImageElement(assetId);
};
@@ -132,16 +146,32 @@ export class AssetManager extends React.PureComponent {
);
render() {
- const { isModalVisible } = this.state;
+ const { isModalVisible, loading } = this.state;
+ const { assets } = this.props;
const assetMaxLimit = 25000;
const assetsTotal = Math.round(
- this.props.assets.reduce((total, asset) => total + asset.value.length, 0) / 1024
+ assets.reduce((total, asset) => total + asset.value.length, 0) / 1024
);
const percentageUsed = Math.round((assetsTotal / assetMaxLimit) * 100);
+ const emptyAssets = (
+
+ No available assets}
+ titleSize="s"
+ body={
+
+ Upload your assets above to get started
+
+ }
+ />
+
+ );
+
const assetModal = isModalVisible ? (
Manage workpad assets
+
+
+ {loading ? (
+
+ ) : (
+
+ )}
+
+
+
+
+
+
+ Below are the image assets that you added to this workpad. To reclaim space, delete
+ assets that you no longer need. Unfortunately, any assets that are actually in use
+ cannot be determined at this time.
+
+
+
+ {assets.length ? (
+
+ {assets.map(this.renderAsset)}
+
+ ) : (
+ emptyAssets
+ )}
+
+
{percentageUsed}% space used
-
-
-
-
- Below are the image assets that you added to this workpad. To reclaim space, delete
- assets that you no longer need. Unfortunately, any assets that are actually in use
- cannot be determined at this time.
-
-
-
- {this.props.assets.map(this.renderAsset)}
-
-
-
Close
diff --git a/x-pack/plugins/canvas/public/components/asset_manager/asset_manager.scss b/x-pack/plugins/canvas/public/components/asset_manager/asset_manager.scss
index 80ab585c963c2..84534971d0ec5 100644
--- a/x-pack/plugins/canvas/public/components/asset_manager/asset_manager.scss
+++ b/x-pack/plugins/canvas/public/components/asset_manager/asset_manager.scss
@@ -1,5 +1,4 @@
.canvasAssetManager {
-
.canvasAssetManager__modalHeader {
flex-wrap: wrap;
}
@@ -15,8 +14,6 @@
flex-grow: 0;
min-width: 40%;
align-items: center;
- justify-content: flex-end;
- padding-right: $euiSize;
@include euiBreakpoint('xs', 's') {
flex-grow: 1;
@@ -27,6 +24,11 @@
margin: 0;
}
+ .canvasAssetManager__fileUploadWrapper {
+ justify-content: flex-end;
+ padding-right: $euiSize;
+ }
+
// ASSETS LIST
.canvasAssetManager__asset {
@@ -34,6 +36,11 @@
overflow: hidden; // hides image from outer panel boundaries
}
+ .canvasAssetManager__emptyPanel {
+ max-width: 400px;
+ margin: 0 auto;
+ }
+
.canvasAssetManager__thumb {
margin: -$euiSizeS;
margin-bottom: 0;
@@ -52,4 +59,8 @@
opacity: 0; // only show the background image (which will properly keep proportions)
}
}
+
+ .canvasAssetManager__modalFooter {
+ justify-content: space-between;
+ }
}
diff --git a/x-pack/plugins/canvas/public/components/asset_manager/index.js b/x-pack/plugins/canvas/public/components/asset_manager/index.js
index 2417e572e1a02..878928a452c56 100644
--- a/x-pack/plugins/canvas/public/components/asset_manager/index.js
+++ b/x-pack/plugins/canvas/public/components/asset_manager/index.js
@@ -6,14 +6,18 @@
import { connect } from 'react-redux';
import { compose, withProps } from 'recompose';
-import { set } from 'lodash';
+import { set, get } from 'lodash';
import { fromExpression, toExpression } from '@kbn/interpreter/common';
import { notify } from '../../lib/notify';
import { getAssets } from '../../state/selectors/assets';
-import { removeAsset } from '../../state/actions/assets';
+import { removeAsset, createAsset } from '../../state/actions/assets';
import { elementsRegistry } from '../../lib/elements_registry';
import { addElement } from '../../state/actions/elements';
import { getSelectedPage } from '../../state/selectors/workpad';
+import { encode } from '../../../common/lib/dataurl';
+import { getId } from '../../lib/get_id';
+import { findExistingAsset } from '../../lib/find_existing_asset';
+import { VALID_IMAGE_TYPES } from '../../../common/lib/constants';
import { AssetManager as Component } from './asset_manager';
const mapStateToProps = state => ({
@@ -44,15 +48,40 @@ const mapDispatchToProps = dispatch => ({
imageElement.expression = toExpression(newAST);
dispatch(addElement(pageId, imageElement));
},
+ onAssetAdd: (type, content) => {
+ // make the ID here and pass it into the action
+ const assetId = getId('asset');
+ dispatch(createAsset(type, content, assetId));
+
+ // then return the id, so the caller knows the id that will be created
+ return assetId;
+ },
removeAsset: assetId => dispatch(removeAsset(assetId)),
});
const mergeProps = (stateProps, dispatchProps, ownProps) => {
+ const { assets } = stateProps;
+ const { onAssetAdd } = dispatchProps;
return {
...ownProps,
...stateProps,
...dispatchProps,
addImageElement: dispatchProps.addImageElement(stateProps.selectedPage),
+ onAssetAdd: file => {
+ const [type, subtype] = get(file, 'type', '').split('/');
+ if (type === 'image' && VALID_IMAGE_TYPES.indexOf(subtype) >= 0) {
+ return encode(file).then(dataurl => {
+ const type = 'dataurl';
+ const existingId = findExistingAsset(type, dataurl, assets);
+ if (existingId) {
+ return existingId;
+ }
+ return onAssetAdd(type, dataurl);
+ });
+ }
+
+ return false;
+ },
};
};
diff --git a/x-pack/plugins/canvas/public/components/file_upload/file_upload.js b/x-pack/plugins/canvas/public/components/file_upload/file_upload.js
deleted file mode 100644
index 9640ab01bd158..0000000000000
--- a/x-pack/plugins/canvas/public/components/file_upload/file_upload.js
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License;
- * you may not use this file except in compliance with the Elastic License.
- */
-
-import React from 'react';
-import PropTypes from 'prop-types';
-import { EuiFilePicker } from '@elastic/eui';
-
-export const FileUpload = ({ id = '', className = 'canvasFileUpload', onUpload }) => (
-
-);
-
-FileUpload.propTypes = {
- id: PropTypes.string,
- className: PropTypes.string,
- onUpload: PropTypes.func.isRequired,
-};
diff --git a/x-pack/plugins/canvas/public/components/function_form/index.js b/x-pack/plugins/canvas/public/components/function_form/index.js
index fbde896361cb6..5ca12b26e48c7 100644
--- a/x-pack/plugins/canvas/public/components/function_form/index.js
+++ b/x-pack/plugins/canvas/public/components/function_form/index.js
@@ -21,6 +21,7 @@ import {
getContextForIndex,
} from '../../state/selectors/workpad';
import { getAssets } from '../../state/selectors/assets';
+import { findExistingAsset } from '../../lib/find_existing_asset';
import { FunctionForm as Component } from './function_form';
const mapStateToProps = (state, { expressionIndex }) => ({
@@ -93,9 +94,7 @@ const mergeProps = (stateProps, dispatchProps, ownProps) => {
onValueAdd: addArgument(element, pageId),
onValueRemove: deleteArgument(element, pageId),
onAssetAdd: (type, content) => {
- const existingId = Object.keys(assets).find(
- assetId => assets[assetId].type === type && assets[assetId].value === content
- );
+ const existingId = findExistingAsset(type, content, assets);
if (existingId) {
return existingId;
}
diff --git a/x-pack/plugins/canvas/public/components/workpad_header/index.js b/x-pack/plugins/canvas/public/components/workpad_header/index.js
index fec9c874744f3..e724b97b0bb4f 100644
--- a/x-pack/plugins/canvas/public/components/workpad_header/index.js
+++ b/x-pack/plugins/canvas/public/components/workpad_header/index.js
@@ -9,7 +9,6 @@ import { connect } from 'react-redux';
import { canUserWrite } from '../../state/selectors/app';
import { getWorkpadName, getSelectedPage, isWriteable } from '../../state/selectors/workpad';
import { setWriteable } from '../../state/actions/workpad';
-import { getAssets } from '../../state/selectors/assets';
import { addElement } from '../../state/actions/elements';
import { WorkpadHeader as Component } from './workpad_header';
@@ -18,7 +17,6 @@ const mapStateToProps = state => ({
canUserWrite: canUserWrite(state),
workpadName: getWorkpadName(state),
selectedPage: getSelectedPage(state),
- hasAssets: Object.keys(getAssets(state)).length ? true : false,
});
const mapDispatchToProps = dispatch => ({
diff --git a/x-pack/plugins/canvas/public/components/workpad_header/workpad_header.js b/x-pack/plugins/canvas/public/components/workpad_header/workpad_header.js
index c4fa1ce706229..88f92f7eb69e6 100644
--- a/x-pack/plugins/canvas/public/components/workpad_header/workpad_header.js
+++ b/x-pack/plugins/canvas/public/components/workpad_header/workpad_header.js
@@ -27,7 +27,6 @@ export const WorkpadHeader = ({
isWriteable,
canUserWrite,
toggleWriteable,
- hasAssets,
addElement,
setShowElementModal,
showElementModal,
@@ -115,11 +114,9 @@ export const WorkpadHeader = ({
{isWriteable ? (
- {hasAssets && (
-
-
-
- )}
+
+
+
date && moment(date).format('MMM D, YYYY @ h:mma');
@@ -79,7 +80,7 @@ export class WorkpadLoader extends React.PureComponent {
};
// create new workpad from uploaded JSON
- uploadWorkpad = async workpad => {
+ onUpload = async workpad => {
this.setState({ createPending: true });
await this.props.createWorkpad(workpad);
this._isMounted && this.setState({ createPending: false });
@@ -232,7 +233,7 @@ export class WorkpadLoader extends React.PureComponent {
return (
-
+
+ uploadWorkpad(file, this.onUpload)}
+ accept="application/json"
+ disabled={createPending || !canUserWrite}
+ />
);
if (!canUserWrite) {
diff --git a/x-pack/plugins/canvas/public/components/workpad_loader/workpad_upload.js b/x-pack/plugins/canvas/public/components/workpad_loader/workpad_upload.js
deleted file mode 100644
index 9c4372175b89f..0000000000000
--- a/x-pack/plugins/canvas/public/components/workpad_loader/workpad_upload.js
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License;
- * you may not use this file except in compliance with the Elastic License.
- */
-
-import React from 'react';
-import PropTypes from 'prop-types';
-import { EuiFilePicker } from '@elastic/eui';
-import { uploadWorkpad } from './upload_workpad';
-
-export const WorkpadUpload = ({ onUpload, ...rest }) => (
- uploadWorkpad(file, onUpload)}
- />
-);
-
-WorkpadUpload.propTypes = {
- onUpload: PropTypes.func.isRequired,
-};
diff --git a/x-pack/plugins/canvas/public/lib/find_existing_asset.js b/x-pack/plugins/canvas/public/lib/find_existing_asset.js
new file mode 100644
index 0000000000000..470d7797e6feb
--- /dev/null
+++ b/x-pack/plugins/canvas/public/lib/find_existing_asset.js
@@ -0,0 +1,12 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+export const findExistingAsset = (type, content, assets) => {
+ const existingId = Object.keys(assets).find(
+ assetId => assets[assetId].type === type && assets[assetId].value === content
+ );
+ return existingId;
+};
diff --git a/x-pack/plugins/canvas/public/state/middleware/aeroelastic.js b/x-pack/plugins/canvas/public/state/middleware/aeroelastic.js
index ac69230861f3e..052df02d43e8c 100644
--- a/x-pack/plugins/canvas/public/state/middleware/aeroelastic.js
+++ b/x-pack/plugins/canvas/public/state/middleware/aeroelastic.js
@@ -344,7 +344,10 @@ export const aeroelastic = ({ dispatch, getState }) => {
populateWithElements(page);
}
- if (action.type !== setMultiplePositions.toString()) {
+ if (
+ action.type !== setMultiplePositions.toString() &&
+ action.type !== elementLayer.toString()
+ ) {
unselectShape(prevPage);
}
diff --git a/x-pack/plugins/console_extensions/spec/generated/ccr.follow.json b/x-pack/plugins/console_extensions/spec/generated/ccr.follow.json
index 704cb082161ae..ba993d25c60ec 100644
--- a/x-pack/plugins/console_extensions/spec/generated/ccr.follow.json
+++ b/x-pack/plugins/console_extensions/spec/generated/ccr.follow.json
@@ -4,7 +4,7 @@
"PUT"
],
"patterns": [
- "{index}/_ccr/follow"
+ "{indices}/_ccr/follow"
],
"documentation": "https://www.elastic.co/guide/en/elasticsearch/reference/current/ccr-put-follow.html"
}
diff --git a/x-pack/plugins/console_extensions/spec/generated/ccr.follow_stats.json b/x-pack/plugins/console_extensions/spec/generated/ccr.follow_stats.json
index 47553262c95d2..6d72e12df17d4 100644
--- a/x-pack/plugins/console_extensions/spec/generated/ccr.follow_stats.json
+++ b/x-pack/plugins/console_extensions/spec/generated/ccr.follow_stats.json
@@ -4,7 +4,7 @@
"GET"
],
"patterns": [
- "{index}/_ccr/stats"
+ "{indices}/_ccr/stats"
],
"documentation": "https://www.elastic.co/guide/en/elasticsearch/reference/current/ccr-get-follow-stats.html"
}
diff --git a/x-pack/plugins/console_extensions/spec/generated/ccr.pause_follow.json b/x-pack/plugins/console_extensions/spec/generated/ccr.pause_follow.json
index 4dcb0fdaf9b87..72afa796e1964 100644
--- a/x-pack/plugins/console_extensions/spec/generated/ccr.pause_follow.json
+++ b/x-pack/plugins/console_extensions/spec/generated/ccr.pause_follow.json
@@ -4,7 +4,7 @@
"POST"
],
"patterns": [
- "{index}/_ccr/pause_follow"
+ "{indices}/_ccr/pause_follow"
],
"documentation": "https://www.elastic.co/guide/en/elasticsearch/reference/current/ccr-post-pause-follow.html"
}
diff --git a/x-pack/plugins/console_extensions/spec/generated/ccr.resume_follow.json b/x-pack/plugins/console_extensions/spec/generated/ccr.resume_follow.json
index 00b889d0d5f9a..3710cdb8cc577 100644
--- a/x-pack/plugins/console_extensions/spec/generated/ccr.resume_follow.json
+++ b/x-pack/plugins/console_extensions/spec/generated/ccr.resume_follow.json
@@ -4,7 +4,7 @@
"POST"
],
"patterns": [
- "{index}/_ccr/resume_follow"
+ "{indices}/_ccr/resume_follow"
],
"documentation": "https://www.elastic.co/guide/en/elasticsearch/reference/current/ccr-post-resume-follow.html"
}
diff --git a/x-pack/plugins/console_extensions/spec/generated/ccr.unfollow.json b/x-pack/plugins/console_extensions/spec/generated/ccr.unfollow.json
index 9d9d6868a2fc9..92759d8222c63 100644
--- a/x-pack/plugins/console_extensions/spec/generated/ccr.unfollow.json
+++ b/x-pack/plugins/console_extensions/spec/generated/ccr.unfollow.json
@@ -4,8 +4,8 @@
"POST"
],
"patterns": [
- "{index}/_ccr/unfollow"
+ "{indices}/_ccr/unfollow"
],
- "documentation": "https://www.elastic.co/guide/en/elasticsearch/reference/current/ccr-post-unfollow.html"
+ "documentation": "http://www.elastic.co/guide/en/elasticsearch/reference/current"
}
}
diff --git a/x-pack/plugins/console_extensions/spec/generated/ilm.remove_policy.json b/x-pack/plugins/console_extensions/spec/generated/ilm.remove_policy.json
index fc835953c2c6d..5a3c760386f10 100644
--- a/x-pack/plugins/console_extensions/spec/generated/ilm.remove_policy.json
+++ b/x-pack/plugins/console_extensions/spec/generated/ilm.remove_policy.json
@@ -4,8 +4,7 @@
"POST"
],
"patterns": [
- "{indices}/_ilm/remove",
- "_ilm/remove"
+ "{indices}/_ilm/remove"
],
"documentation": "https://www.elastic.co/guide/en/elasticsearch/reference/current/ilm-remove-policy.html"
}
diff --git a/x-pack/plugins/console_extensions/spec/generated/indices.freeze.json b/x-pack/plugins/console_extensions/spec/generated/indices.freeze.json
new file mode 100644
index 0000000000000..06e8c606f59f7
--- /dev/null
+++ b/x-pack/plugins/console_extensions/spec/generated/indices.freeze.json
@@ -0,0 +1,24 @@
+{
+ "indices.freeze": {
+ "url_params": {
+ "timeout": "",
+ "master_timeout": "",
+ "ignore_unavailable": "__flag__",
+ "allow_no_indices": "__flag__",
+ "expand_wildcards": [
+ "open",
+ "closed",
+ "none",
+ "all"
+ ],
+ "wait_for_active_shards": ""
+ },
+ "methods": [
+ "POST"
+ ],
+ "patterns": [
+ "{indices}/_freeze"
+ ],
+ "documentation": "https://www.elastic.co/guide/en/elasticsearch/reference/current/frozen.html"
+ }
+}
diff --git a/x-pack/plugins/console_extensions/spec/generated/indices.unfreeze.json b/x-pack/plugins/console_extensions/spec/generated/indices.unfreeze.json
new file mode 100644
index 0000000000000..186a671347240
--- /dev/null
+++ b/x-pack/plugins/console_extensions/spec/generated/indices.unfreeze.json
@@ -0,0 +1,24 @@
+{
+ "indices.unfreeze": {
+ "url_params": {
+ "timeout": "",
+ "master_timeout": "",
+ "ignore_unavailable": "__flag__",
+ "allow_no_indices": "__flag__",
+ "expand_wildcards": [
+ "open",
+ "closed",
+ "none",
+ "all"
+ ],
+ "wait_for_active_shards": ""
+ },
+ "methods": [
+ "POST"
+ ],
+ "patterns": [
+ "{indices}/_unfreeze"
+ ],
+ "documentation": "https://www.elastic.co/guide/en/elasticsearch/reference/current/frozen.html"
+ }
+}
diff --git a/x-pack/plugins/console_extensions/spec/generated/xpack.ml.close_job.json b/x-pack/plugins/console_extensions/spec/generated/ml.close_job.json
similarity index 78%
rename from x-pack/plugins/console_extensions/spec/generated/xpack.ml.close_job.json
rename to x-pack/plugins/console_extensions/spec/generated/ml.close_job.json
index 933f79a1028ed..310b0d125b1f9 100644
--- a/x-pack/plugins/console_extensions/spec/generated/xpack.ml.close_job.json
+++ b/x-pack/plugins/console_extensions/spec/generated/ml.close_job.json
@@ -1,5 +1,5 @@
{
- "xpack.ml.close_job": {
+ "ml.close_job": {
"url_params": {
"allow_no_jobs": "__flag__",
"force": "__flag__",
@@ -9,7 +9,7 @@
"POST"
],
"patterns": [
- "_xpack/ml/anomaly_detectors/{job_id}/_close"
+ "_ml/anomaly_detectors/{job_id}/_close"
],
"documentation": "http://www.elastic.co/guide/en/elasticsearch/reference/current/ml-close-job.html"
}
diff --git a/x-pack/plugins/console_extensions/spec/generated/xpack.ml.delete_filter.json b/x-pack/plugins/console_extensions/spec/generated/ml.delete_calendar.json
similarity index 51%
rename from x-pack/plugins/console_extensions/spec/generated/xpack.ml.delete_filter.json
rename to x-pack/plugins/console_extensions/spec/generated/ml.delete_calendar.json
index 5a4a8cd232448..97e5898072a08 100644
--- a/x-pack/plugins/console_extensions/spec/generated/xpack.ml.delete_filter.json
+++ b/x-pack/plugins/console_extensions/spec/generated/ml.delete_calendar.json
@@ -1,10 +1,10 @@
{
- "xpack.ml.delete_filter": {
+ "ml.delete_calendar": {
"methods": [
"DELETE"
],
"patterns": [
- "_xpack/ml/filters/{filter_id}"
+ "_ml/calendars/{calendar_id}"
]
}
}
diff --git a/x-pack/plugins/console_extensions/spec/generated/ml.delete_calendar_event.json b/x-pack/plugins/console_extensions/spec/generated/ml.delete_calendar_event.json
new file mode 100644
index 0000000000000..85ea5add0b60b
--- /dev/null
+++ b/x-pack/plugins/console_extensions/spec/generated/ml.delete_calendar_event.json
@@ -0,0 +1,10 @@
+{
+ "ml.delete_calendar_event": {
+ "methods": [
+ "DELETE"
+ ],
+ "patterns": [
+ "_ml/calendars/{calendar_id}/events/{event_id}"
+ ]
+ }
+}
diff --git a/x-pack/plugins/console_extensions/spec/generated/ml.delete_calendar_job.json b/x-pack/plugins/console_extensions/spec/generated/ml.delete_calendar_job.json
new file mode 100644
index 0000000000000..6665f52eeb90d
--- /dev/null
+++ b/x-pack/plugins/console_extensions/spec/generated/ml.delete_calendar_job.json
@@ -0,0 +1,10 @@
+{
+ "ml.delete_calendar_job": {
+ "methods": [
+ "DELETE"
+ ],
+ "patterns": [
+ "_ml/calendars/{calendar_id}/jobs/{job_id}"
+ ]
+ }
+}
diff --git a/x-pack/plugins/console_extensions/spec/generated/xpack.ml.delete_datafeed.json b/x-pack/plugins/console_extensions/spec/generated/ml.delete_datafeed.json
similarity index 76%
rename from x-pack/plugins/console_extensions/spec/generated/xpack.ml.delete_datafeed.json
rename to x-pack/plugins/console_extensions/spec/generated/ml.delete_datafeed.json
index af1d5564cf9ca..7c7f3c40f23bb 100644
--- a/x-pack/plugins/console_extensions/spec/generated/xpack.ml.delete_datafeed.json
+++ b/x-pack/plugins/console_extensions/spec/generated/ml.delete_datafeed.json
@@ -1,5 +1,5 @@
{
- "xpack.ml.delete_datafeed": {
+ "ml.delete_datafeed": {
"url_params": {
"force": "__flag__"
},
@@ -7,7 +7,7 @@
"DELETE"
],
"patterns": [
- "_xpack/ml/datafeeds/{datafeed_id}"
+ "_ml/datafeeds/{datafeed_id}"
],
"documentation": "http://www.elastic.co/guide/en/elasticsearch/reference/current/ml-delete-datafeed.html"
}
diff --git a/x-pack/plugins/console_extensions/spec/generated/ml.delete_expired_data.json b/x-pack/plugins/console_extensions/spec/generated/ml.delete_expired_data.json
new file mode 100644
index 0000000000000..4afa9e323b030
--- /dev/null
+++ b/x-pack/plugins/console_extensions/spec/generated/ml.delete_expired_data.json
@@ -0,0 +1,10 @@
+{
+ "ml.delete_expired_data": {
+ "methods": [
+ "DELETE"
+ ],
+ "patterns": [
+ "_ml/_delete_expired_data"
+ ]
+ }
+}
diff --git a/x-pack/plugins/console_extensions/spec/generated/ml.delete_filter.json b/x-pack/plugins/console_extensions/spec/generated/ml.delete_filter.json
new file mode 100644
index 0000000000000..8210a2acd71d0
--- /dev/null
+++ b/x-pack/plugins/console_extensions/spec/generated/ml.delete_filter.json
@@ -0,0 +1,10 @@
+{
+ "ml.delete_filter": {
+ "methods": [
+ "DELETE"
+ ],
+ "patterns": [
+ "_ml/filters/{filter_id}"
+ ]
+ }
+}
diff --git a/x-pack/plugins/console_extensions/spec/generated/ml.delete_forecast.json b/x-pack/plugins/console_extensions/spec/generated/ml.delete_forecast.json
new file mode 100644
index 0000000000000..971a761cc77e9
--- /dev/null
+++ b/x-pack/plugins/console_extensions/spec/generated/ml.delete_forecast.json
@@ -0,0 +1,16 @@
+{
+ "ml.delete_forecast": {
+ "url_params": {
+ "allow_no_forecasts": "__flag__",
+ "timeout": ""
+ },
+ "methods": [
+ "DELETE"
+ ],
+ "patterns": [
+ "_ml/anomaly_detectors/{job_id}/_forecast",
+ "_ml/anomaly_detectors/{job_id}/_forecast/{forecast_id}"
+ ],
+ "documentation": "http://www.elastic.co/guide/en/elasticsearch/reference/current/ml-delete-forecast.html"
+ }
+}
diff --git a/x-pack/plugins/console_extensions/spec/generated/xpack.ml.delete_job.json b/x-pack/plugins/console_extensions/spec/generated/ml.delete_job.json
similarity index 61%
rename from x-pack/plugins/console_extensions/spec/generated/xpack.ml.delete_job.json
rename to x-pack/plugins/console_extensions/spec/generated/ml.delete_job.json
index 26c45ad0fc6fb..ab518071bf765 100644
--- a/x-pack/plugins/console_extensions/spec/generated/xpack.ml.delete_job.json
+++ b/x-pack/plugins/console_extensions/spec/generated/ml.delete_job.json
@@ -1,13 +1,14 @@
{
- "xpack.ml.delete_job": {
+ "ml.delete_job": {
"url_params": {
- "force": "__flag__"
+ "force": "__flag__",
+ "wait_for_completion": "__flag__"
},
"methods": [
"DELETE"
],
"patterns": [
- "_xpack/ml/anomaly_detectors/{job_id}"
+ "_ml/anomaly_detectors/{job_id}"
],
"documentation": "http://www.elastic.co/guide/en/elasticsearch/reference/current/ml-delete-job.html"
}
diff --git a/x-pack/plugins/console_extensions/spec/generated/xpack.ml.delete_model_snapshot.json b/x-pack/plugins/console_extensions/spec/generated/ml.delete_model_snapshot.json
similarity index 61%
rename from x-pack/plugins/console_extensions/spec/generated/xpack.ml.delete_model_snapshot.json
rename to x-pack/plugins/console_extensions/spec/generated/ml.delete_model_snapshot.json
index faf9da66f3bee..53d45bf0498ab 100644
--- a/x-pack/plugins/console_extensions/spec/generated/xpack.ml.delete_model_snapshot.json
+++ b/x-pack/plugins/console_extensions/spec/generated/ml.delete_model_snapshot.json
@@ -1,10 +1,10 @@
{
- "xpack.ml.delete_model_snapshot": {
+ "ml.delete_model_snapshot": {
"methods": [
"DELETE"
],
"patterns": [
- "_xpack/ml/anomaly_detectors/{job_id}/model_snapshots/{snapshot_id}"
+ "_ml/anomaly_detectors/{job_id}/model_snapshots/{snapshot_id}"
],
"documentation": "http://www.elastic.co/guide/en/elasticsearch/reference/current/ml-delete-snapshot.html"
}
diff --git a/x-pack/plugins/console_extensions/spec/generated/ml.find_file_structure.json b/x-pack/plugins/console_extensions/spec/generated/ml.find_file_structure.json
new file mode 100644
index 0000000000000..93706ea628a28
--- /dev/null
+++ b/x-pack/plugins/console_extensions/spec/generated/ml.find_file_structure.json
@@ -0,0 +1,31 @@
+{
+ "ml.find_file_structure": {
+ "url_params": {
+ "lines_to_sample": 0,
+ "timeout": "",
+ "charset": "",
+ "format": [
+ "ndjson",
+ "xml",
+ "delimited",
+ "semi_structured_text"
+ ],
+ "has_header_row": "__flag__",
+ "column_names": [],
+ "delimiter": "",
+ "quote": "",
+ "should_trim_fields": "__flag__",
+ "grok_pattern": "",
+ "timestamp_field": "",
+ "timestamp_format": "",
+ "explain": "__flag__"
+ },
+ "methods": [
+ "POST"
+ ],
+ "patterns": [
+ "_ml/find_file_structure"
+ ],
+ "documentation": "http://www.elastic.co/guide/en/elasticsearch/reference/current/ml-file-structure.html"
+ }
+}
diff --git a/x-pack/plugins/console_extensions/spec/generated/xpack.ml.flush_job.json b/x-pack/plugins/console_extensions/spec/generated/ml.flush_job.json
similarity index 80%
rename from x-pack/plugins/console_extensions/spec/generated/xpack.ml.flush_job.json
rename to x-pack/plugins/console_extensions/spec/generated/ml.flush_job.json
index 190fa9813384e..2f496003a2834 100644
--- a/x-pack/plugins/console_extensions/spec/generated/xpack.ml.flush_job.json
+++ b/x-pack/plugins/console_extensions/spec/generated/ml.flush_job.json
@@ -1,5 +1,5 @@
{
- "xpack.ml.flush_job": {
+ "ml.flush_job": {
"url_params": {
"calc_interim": "__flag__",
"start": "",
@@ -11,7 +11,7 @@
"POST"
],
"patterns": [
- "_xpack/ml/anomaly_detectors/{job_id}/_flush"
+ "_ml/anomaly_detectors/{job_id}/_flush"
],
"documentation": "http://www.elastic.co/guide/en/elasticsearch/reference/current/ml-flush-job.html"
}
diff --git a/x-pack/plugins/console_extensions/spec/generated/xpack.ml.forecast.json b/x-pack/plugins/console_extensions/spec/generated/ml.forecast.json
similarity index 63%
rename from x-pack/plugins/console_extensions/spec/generated/xpack.ml.forecast.json
rename to x-pack/plugins/console_extensions/spec/generated/ml.forecast.json
index e96a5100e98dd..3a8849aad3e4d 100644
--- a/x-pack/plugins/console_extensions/spec/generated/xpack.ml.forecast.json
+++ b/x-pack/plugins/console_extensions/spec/generated/ml.forecast.json
@@ -1,5 +1,5 @@
{
- "xpack.ml.forecast": {
+ "ml.forecast": {
"url_params": {
"duration": "",
"expires_in": ""
@@ -8,7 +8,7 @@
"POST"
],
"patterns": [
- "_xpack/ml/anomaly_detectors/{job_id}/_forecast"
+ "_ml/anomaly_detectors/{job_id}/_forecast"
]
}
}
diff --git a/x-pack/plugins/console_extensions/spec/generated/xpack.ml.get_buckets.json b/x-pack/plugins/console_extensions/spec/generated/ml.get_buckets.json
similarity index 71%
rename from x-pack/plugins/console_extensions/spec/generated/xpack.ml.get_buckets.json
rename to x-pack/plugins/console_extensions/spec/generated/ml.get_buckets.json
index a63c47ab52429..2cbcb9d6155ec 100644
--- a/x-pack/plugins/console_extensions/spec/generated/xpack.ml.get_buckets.json
+++ b/x-pack/plugins/console_extensions/spec/generated/ml.get_buckets.json
@@ -1,5 +1,5 @@
{
- "xpack.ml.get_buckets": {
+ "ml.get_buckets": {
"url_params": {
"expand": "__flag__",
"exclude_interim": "__flag__",
@@ -16,8 +16,8 @@
"POST"
],
"patterns": [
- "_xpack/ml/anomaly_detectors/{job_id}/results/buckets/{timestamp}",
- "_xpack/ml/anomaly_detectors/{job_id}/results/buckets"
+ "_ml/anomaly_detectors/{job_id}/results/buckets/{timestamp}",
+ "_ml/anomaly_detectors/{job_id}/results/buckets"
],
"documentation": "http://www.elastic.co/guide/en/elasticsearch/reference/current/ml-get-bucket.html"
}
diff --git a/x-pack/plugins/console_extensions/spec/generated/xpack.ml.get_calendar_events.json b/x-pack/plugins/console_extensions/spec/generated/ml.get_calendar_events.json
similarity index 68%
rename from x-pack/plugins/console_extensions/spec/generated/xpack.ml.get_calendar_events.json
rename to x-pack/plugins/console_extensions/spec/generated/ml.get_calendar_events.json
index c6734d6cdc893..8999af6320dfa 100644
--- a/x-pack/plugins/console_extensions/spec/generated/xpack.ml.get_calendar_events.json
+++ b/x-pack/plugins/console_extensions/spec/generated/ml.get_calendar_events.json
@@ -1,5 +1,5 @@
{
- "xpack.ml.get_calendar_events": {
+ "ml.get_calendar_events": {
"url_params": {
"job_id": "",
"start": "",
@@ -11,7 +11,7 @@
"GET"
],
"patterns": [
- "_xpack/ml/calendars/{calendar_id}/events"
+ "_ml/calendars/{calendar_id}/events"
]
}
}
diff --git a/x-pack/plugins/console_extensions/spec/generated/xpack.ml.get_calendars.json b/x-pack/plugins/console_extensions/spec/generated/ml.get_calendars.json
similarity index 58%
rename from x-pack/plugins/console_extensions/spec/generated/xpack.ml.get_calendars.json
rename to x-pack/plugins/console_extensions/spec/generated/ml.get_calendars.json
index 0b014b7f000e5..87f582b5c364d 100644
--- a/x-pack/plugins/console_extensions/spec/generated/xpack.ml.get_calendars.json
+++ b/x-pack/plugins/console_extensions/spec/generated/ml.get_calendars.json
@@ -1,5 +1,5 @@
{
- "xpack.ml.get_calendars": {
+ "ml.get_calendars": {
"url_params": {
"from": 0,
"size": 0
@@ -9,8 +9,8 @@
"POST"
],
"patterns": [
- "_xpack/ml/calendars",
- "_xpack/ml/calendars/{calendar_id}"
+ "_ml/calendars",
+ "_ml/calendars/{calendar_id}"
]
}
}
diff --git a/x-pack/plugins/console_extensions/spec/generated/xpack.ml.get_categories.json b/x-pack/plugins/console_extensions/spec/generated/ml.get_categories.json
similarity index 58%
rename from x-pack/plugins/console_extensions/spec/generated/xpack.ml.get_categories.json
rename to x-pack/plugins/console_extensions/spec/generated/ml.get_categories.json
index 1157a0a375880..357a7b7fb0ccc 100644
--- a/x-pack/plugins/console_extensions/spec/generated/xpack.ml.get_categories.json
+++ b/x-pack/plugins/console_extensions/spec/generated/ml.get_categories.json
@@ -1,5 +1,5 @@
{
- "xpack.ml.get_categories": {
+ "ml.get_categories": {
"url_params": {
"from": 0,
"size": 0
@@ -9,8 +9,8 @@
"POST"
],
"patterns": [
- "_xpack/ml/anomaly_detectors/{job_id}/results/categories/{category_id}",
- "_xpack/ml/anomaly_detectors/{job_id}/results/categories/"
+ "_ml/anomaly_detectors/{job_id}/results/categories/{category_id}",
+ "_ml/anomaly_detectors/{job_id}/results/categories/"
],
"documentation": "http://www.elastic.co/guide/en/elasticsearch/reference/current/ml-get-category.html"
}
diff --git a/x-pack/plugins/console_extensions/spec/generated/xpack.ml.get_datafeed_stats.json b/x-pack/plugins/console_extensions/spec/generated/ml.get_datafeed_stats.json
similarity index 67%
rename from x-pack/plugins/console_extensions/spec/generated/xpack.ml.get_datafeed_stats.json
rename to x-pack/plugins/console_extensions/spec/generated/ml.get_datafeed_stats.json
index 8b5613da5c935..5c300e444c794 100644
--- a/x-pack/plugins/console_extensions/spec/generated/xpack.ml.get_datafeed_stats.json
+++ b/x-pack/plugins/console_extensions/spec/generated/ml.get_datafeed_stats.json
@@ -1,5 +1,5 @@
{
- "xpack.ml.get_datafeed_stats": {
+ "ml.get_datafeed_stats": {
"url_params": {
"allow_no_datafeeds": "__flag__"
},
@@ -7,8 +7,8 @@
"GET"
],
"patterns": [
- "_xpack/ml/datafeeds/{datafeed_id}/_stats",
- "_xpack/ml/datafeeds/_stats"
+ "_ml/datafeeds/{datafeed_id}/_stats",
+ "_ml/datafeeds/_stats"
],
"documentation": "http://www.elastic.co/guide/en/elasticsearch/reference/current/ml-get-datafeed-stats.html"
}
diff --git a/x-pack/plugins/console_extensions/spec/generated/xpack.ml.get_datafeeds.json b/x-pack/plugins/console_extensions/spec/generated/ml.get_datafeeds.json
similarity index 70%
rename from x-pack/plugins/console_extensions/spec/generated/xpack.ml.get_datafeeds.json
rename to x-pack/plugins/console_extensions/spec/generated/ml.get_datafeeds.json
index 1f44b4aba572a..9979a685426be 100644
--- a/x-pack/plugins/console_extensions/spec/generated/xpack.ml.get_datafeeds.json
+++ b/x-pack/plugins/console_extensions/spec/generated/ml.get_datafeeds.json
@@ -1,5 +1,5 @@
{
- "xpack.ml.get_datafeeds": {
+ "ml.get_datafeeds": {
"url_params": {
"allow_no_datafeeds": "__flag__"
},
@@ -7,8 +7,8 @@
"GET"
],
"patterns": [
- "_xpack/ml/datafeeds/{datafeed_id}",
- "_xpack/ml/datafeeds"
+ "_ml/datafeeds/{datafeed_id}",
+ "_ml/datafeeds"
],
"documentation": "http://www.elastic.co/guide/en/elasticsearch/reference/current/ml-get-datafeed.html"
}
diff --git a/x-pack/plugins/console_extensions/spec/generated/xpack.ml.get_filters.json b/x-pack/plugins/console_extensions/spec/generated/ml.get_filters.json
similarity index 57%
rename from x-pack/plugins/console_extensions/spec/generated/xpack.ml.get_filters.json
rename to x-pack/plugins/console_extensions/spec/generated/ml.get_filters.json
index 0e33294934ba4..9b06e618a0b0c 100644
--- a/x-pack/plugins/console_extensions/spec/generated/xpack.ml.get_filters.json
+++ b/x-pack/plugins/console_extensions/spec/generated/ml.get_filters.json
@@ -1,5 +1,5 @@
{
- "xpack.ml.get_filters": {
+ "ml.get_filters": {
"url_params": {
"from": 0,
"size": 0
@@ -8,8 +8,8 @@
"GET"
],
"patterns": [
- "_xpack/ml/filters",
- "_xpack/ml/filters/{filter_id}"
+ "_ml/filters",
+ "_ml/filters/{filter_id}"
]
}
}
diff --git a/x-pack/plugins/console_extensions/spec/generated/xpack.ml.get_influencers.json b/x-pack/plugins/console_extensions/spec/generated/ml.get_influencers.json
similarity index 80%
rename from x-pack/plugins/console_extensions/spec/generated/xpack.ml.get_influencers.json
rename to x-pack/plugins/console_extensions/spec/generated/ml.get_influencers.json
index a4a0a62a8fb5a..9471fac64d489 100644
--- a/x-pack/plugins/console_extensions/spec/generated/xpack.ml.get_influencers.json
+++ b/x-pack/plugins/console_extensions/spec/generated/ml.get_influencers.json
@@ -1,5 +1,5 @@
{
- "xpack.ml.get_influencers": {
+ "ml.get_influencers": {
"url_params": {
"exclude_interim": "__flag__",
"from": 0,
@@ -15,7 +15,7 @@
"POST"
],
"patterns": [
- "_xpack/ml/anomaly_detectors/{job_id}/results/influencers"
+ "_ml/anomaly_detectors/{job_id}/results/influencers"
],
"documentation": "http://www.elastic.co/guide/en/elasticsearch/reference/current/ml-get-influencer.html"
}
diff --git a/x-pack/plugins/console_extensions/spec/generated/xpack.ml.get_job_stats.json b/x-pack/plugins/console_extensions/spec/generated/ml.get_job_stats.json
similarity index 65%
rename from x-pack/plugins/console_extensions/spec/generated/xpack.ml.get_job_stats.json
rename to x-pack/plugins/console_extensions/spec/generated/ml.get_job_stats.json
index 644c1a81eb7c5..b28a2655cbefe 100644
--- a/x-pack/plugins/console_extensions/spec/generated/xpack.ml.get_job_stats.json
+++ b/x-pack/plugins/console_extensions/spec/generated/ml.get_job_stats.json
@@ -1,5 +1,5 @@
{
- "xpack.ml.get_job_stats": {
+ "ml.get_job_stats": {
"url_params": {
"allow_no_jobs": "__flag__"
},
@@ -7,8 +7,8 @@
"GET"
],
"patterns": [
- "_xpack/ml/anomaly_detectors/_stats",
- "_xpack/ml/anomaly_detectors/{job_id}/_stats"
+ "_ml/anomaly_detectors/_stats",
+ "_ml/anomaly_detectors/{job_id}/_stats"
],
"documentation": "http://www.elastic.co/guide/en/elasticsearch/reference/current/ml-get-job-stats.html"
}
diff --git a/x-pack/plugins/console_extensions/spec/generated/xpack.ml.get_jobs.json b/x-pack/plugins/console_extensions/spec/generated/ml.get_jobs.json
similarity index 68%
rename from x-pack/plugins/console_extensions/spec/generated/xpack.ml.get_jobs.json
rename to x-pack/plugins/console_extensions/spec/generated/ml.get_jobs.json
index 2621d8b56c2ec..8f7de906578d7 100644
--- a/x-pack/plugins/console_extensions/spec/generated/xpack.ml.get_jobs.json
+++ b/x-pack/plugins/console_extensions/spec/generated/ml.get_jobs.json
@@ -1,5 +1,5 @@
{
- "xpack.ml.get_jobs": {
+ "ml.get_jobs": {
"url_params": {
"allow_no_jobs": "__flag__"
},
@@ -7,8 +7,8 @@
"GET"
],
"patterns": [
- "_xpack/ml/anomaly_detectors/{job_id}",
- "_xpack/ml/anomaly_detectors"
+ "_ml/anomaly_detectors/{job_id}",
+ "_ml/anomaly_detectors"
],
"documentation": "http://www.elastic.co/guide/en/elasticsearch/reference/current/ml-get-job.html"
}
diff --git a/x-pack/plugins/console_extensions/spec/generated/xpack.ml.get_model_snapshots.json b/x-pack/plugins/console_extensions/spec/generated/ml.get_model_snapshots.json
similarity index 65%
rename from x-pack/plugins/console_extensions/spec/generated/xpack.ml.get_model_snapshots.json
rename to x-pack/plugins/console_extensions/spec/generated/ml.get_model_snapshots.json
index cf82bd258375f..a3b9702f4e4f0 100644
--- a/x-pack/plugins/console_extensions/spec/generated/xpack.ml.get_model_snapshots.json
+++ b/x-pack/plugins/console_extensions/spec/generated/ml.get_model_snapshots.json
@@ -1,5 +1,5 @@
{
- "xpack.ml.get_model_snapshots": {
+ "ml.get_model_snapshots": {
"url_params": {
"from": 0,
"size": 0,
@@ -13,8 +13,8 @@
"POST"
],
"patterns": [
- "_xpack/ml/anomaly_detectors/{job_id}/model_snapshots/{snapshot_id}",
- "_xpack/ml/anomaly_detectors/{job_id}/model_snapshots"
+ "_ml/anomaly_detectors/{job_id}/model_snapshots/{snapshot_id}",
+ "_ml/anomaly_detectors/{job_id}/model_snapshots"
],
"documentation": "http://www.elastic.co/guide/en/elasticsearch/reference/current/ml-get-snapshot.html"
}
diff --git a/x-pack/plugins/console_extensions/spec/generated/xpack.ml.get_overall_buckets.json b/x-pack/plugins/console_extensions/spec/generated/ml.get_overall_buckets.json
similarity index 79%
rename from x-pack/plugins/console_extensions/spec/generated/xpack.ml.get_overall_buckets.json
rename to x-pack/plugins/console_extensions/spec/generated/ml.get_overall_buckets.json
index ec6da8fb7a2a9..e89d63ae7f49f 100644
--- a/x-pack/plugins/console_extensions/spec/generated/xpack.ml.get_overall_buckets.json
+++ b/x-pack/plugins/console_extensions/spec/generated/ml.get_overall_buckets.json
@@ -1,5 +1,5 @@
{
- "xpack.ml.get_overall_buckets": {
+ "ml.get_overall_buckets": {
"url_params": {
"top_n": 0,
"bucket_span": "",
@@ -14,7 +14,7 @@
"POST"
],
"patterns": [
- "_xpack/ml/anomaly_detectors/{job_id}/results/overall_buckets"
+ "_ml/anomaly_detectors/{job_id}/results/overall_buckets"
],
"documentation": "http://www.elastic.co/guide/en/elasticsearch/reference/current/ml-get-overall-buckets.html"
}
diff --git a/x-pack/plugins/console_extensions/spec/generated/xpack.ml.get_records.json b/x-pack/plugins/console_extensions/spec/generated/ml.get_records.json
similarity index 81%
rename from x-pack/plugins/console_extensions/spec/generated/xpack.ml.get_records.json
rename to x-pack/plugins/console_extensions/spec/generated/ml.get_records.json
index e8159e97e1829..fd03c8d34214c 100644
--- a/x-pack/plugins/console_extensions/spec/generated/xpack.ml.get_records.json
+++ b/x-pack/plugins/console_extensions/spec/generated/ml.get_records.json
@@ -1,5 +1,5 @@
{
- "xpack.ml.get_records": {
+ "ml.get_records": {
"url_params": {
"exclude_interim": "__flag__",
"from": 0,
@@ -15,7 +15,7 @@
"POST"
],
"patterns": [
- "_xpack/ml/anomaly_detectors/{job_id}/results/records"
+ "_ml/anomaly_detectors/{job_id}/results/records"
],
"documentation": "http://www.elastic.co/guide/en/elasticsearch/reference/current/ml-get-record.html"
}
diff --git a/x-pack/plugins/console_extensions/spec/generated/xpack.ml.info.json b/x-pack/plugins/console_extensions/spec/generated/ml.info.json
similarity index 60%
rename from x-pack/plugins/console_extensions/spec/generated/xpack.ml.info.json
rename to x-pack/plugins/console_extensions/spec/generated/ml.info.json
index 6235f74cc6227..51b571776ead9 100644
--- a/x-pack/plugins/console_extensions/spec/generated/xpack.ml.info.json
+++ b/x-pack/plugins/console_extensions/spec/generated/ml.info.json
@@ -1,10 +1,10 @@
{
- "xpack.ml.info": {
+ "ml.info": {
"methods": [
"GET"
],
"patterns": [
- "_xpack/ml/info"
+ "_ml/info"
]
}
}
diff --git a/x-pack/plugins/console_extensions/spec/generated/xpack.ml.open_job.json b/x-pack/plugins/console_extensions/spec/generated/ml.open_job.json
similarity index 69%
rename from x-pack/plugins/console_extensions/spec/generated/xpack.ml.open_job.json
rename to x-pack/plugins/console_extensions/spec/generated/ml.open_job.json
index d45214d813005..cd330ec4822c0 100644
--- a/x-pack/plugins/console_extensions/spec/generated/xpack.ml.open_job.json
+++ b/x-pack/plugins/console_extensions/spec/generated/ml.open_job.json
@@ -1,10 +1,10 @@
{
- "xpack.ml.open_job": {
+ "ml.open_job": {
"methods": [
"POST"
],
"patterns": [
- "_xpack/ml/anomaly_detectors/{job_id}/_open"
+ "_ml/anomaly_detectors/{job_id}/_open"
],
"documentation": "http://www.elastic.co/guide/en/elasticsearch/reference/current/ml-open-job.html"
}
diff --git a/x-pack/plugins/console_extensions/spec/generated/ml.post_calendar_events.json b/x-pack/plugins/console_extensions/spec/generated/ml.post_calendar_events.json
new file mode 100644
index 0000000000000..89ce2df63315b
--- /dev/null
+++ b/x-pack/plugins/console_extensions/spec/generated/ml.post_calendar_events.json
@@ -0,0 +1,10 @@
+{
+ "ml.post_calendar_events": {
+ "methods": [
+ "POST"
+ ],
+ "patterns": [
+ "_ml/calendars/{calendar_id}/events"
+ ]
+ }
+}
diff --git a/x-pack/plugins/console_extensions/spec/generated/xpack.ml.post_data.json b/x-pack/plugins/console_extensions/spec/generated/ml.post_data.json
similarity index 76%
rename from x-pack/plugins/console_extensions/spec/generated/xpack.ml.post_data.json
rename to x-pack/plugins/console_extensions/spec/generated/ml.post_data.json
index 206d2e3e1c064..cc6f0b658e111 100644
--- a/x-pack/plugins/console_extensions/spec/generated/xpack.ml.post_data.json
+++ b/x-pack/plugins/console_extensions/spec/generated/ml.post_data.json
@@ -1,5 +1,5 @@
{
- "xpack.ml.post_data": {
+ "ml.post_data": {
"url_params": {
"reset_start": "",
"reset_end": ""
@@ -8,7 +8,7 @@
"POST"
],
"patterns": [
- "_xpack/ml/anomaly_detectors/{job_id}/_data"
+ "_ml/anomaly_detectors/{job_id}/_data"
],
"documentation": "http://www.elastic.co/guide/en/elasticsearch/reference/current/ml-post-data.html"
}
diff --git a/x-pack/plugins/console_extensions/spec/generated/xpack.ml.preview_datafeed.json b/x-pack/plugins/console_extensions/spec/generated/ml.preview_datafeed.json
similarity index 68%
rename from x-pack/plugins/console_extensions/spec/generated/xpack.ml.preview_datafeed.json
rename to x-pack/plugins/console_extensions/spec/generated/ml.preview_datafeed.json
index 9aeca7e1363a0..be3c3d466f37d 100644
--- a/x-pack/plugins/console_extensions/spec/generated/xpack.ml.preview_datafeed.json
+++ b/x-pack/plugins/console_extensions/spec/generated/ml.preview_datafeed.json
@@ -1,10 +1,10 @@
{
- "xpack.ml.preview_datafeed": {
+ "ml.preview_datafeed": {
"methods": [
"GET"
],
"patterns": [
- "_xpack/ml/datafeeds/{datafeed_id}/_preview"
+ "_ml/datafeeds/{datafeed_id}/_preview"
],
"documentation": "http://www.elastic.co/guide/en/elasticsearch/reference/current/ml-preview-datafeed.html"
}
diff --git a/x-pack/plugins/console_extensions/spec/generated/xpack.ml.put_filter.json b/x-pack/plugins/console_extensions/spec/generated/ml.put_calendar.json
similarity index 51%
rename from x-pack/plugins/console_extensions/spec/generated/xpack.ml.put_filter.json
rename to x-pack/plugins/console_extensions/spec/generated/ml.put_calendar.json
index 2a2c5815046d4..7452d1b4b9707 100644
--- a/x-pack/plugins/console_extensions/spec/generated/xpack.ml.put_filter.json
+++ b/x-pack/plugins/console_extensions/spec/generated/ml.put_calendar.json
@@ -1,10 +1,10 @@
{
- "xpack.ml.put_filter": {
+ "ml.put_calendar": {
"methods": [
"PUT"
],
"patterns": [
- "_xpack/ml/filters/{filter_id}"
+ "_ml/calendars/{calendar_id}"
]
}
}
diff --git a/x-pack/plugins/console_extensions/spec/generated/ml.put_calendar_job.json b/x-pack/plugins/console_extensions/spec/generated/ml.put_calendar_job.json
new file mode 100644
index 0000000000000..08dc3d77b5f25
--- /dev/null
+++ b/x-pack/plugins/console_extensions/spec/generated/ml.put_calendar_job.json
@@ -0,0 +1,10 @@
+{
+ "ml.put_calendar_job": {
+ "methods": [
+ "PUT"
+ ],
+ "patterns": [
+ "_ml/calendars/{calendar_id}/jobs/{job_id}"
+ ]
+ }
+}
diff --git a/x-pack/plugins/console_extensions/spec/generated/xpack.ml.put_datafeed.json b/x-pack/plugins/console_extensions/spec/generated/ml.put_datafeed.json
similarity index 71%
rename from x-pack/plugins/console_extensions/spec/generated/xpack.ml.put_datafeed.json
rename to x-pack/plugins/console_extensions/spec/generated/ml.put_datafeed.json
index db5cb27f4a790..a61f9ab465724 100644
--- a/x-pack/plugins/console_extensions/spec/generated/xpack.ml.put_datafeed.json
+++ b/x-pack/plugins/console_extensions/spec/generated/ml.put_datafeed.json
@@ -1,10 +1,10 @@
{
- "xpack.ml.put_datafeed": {
+ "ml.put_datafeed": {
"methods": [
"PUT"
],
"patterns": [
- "_xpack/ml/datafeeds/{datafeed_id}"
+ "_ml/datafeeds/{datafeed_id}"
],
"documentation": "http://www.elastic.co/guide/en/elasticsearch/reference/current/ml-put-datafeed.html"
}
diff --git a/x-pack/plugins/console_extensions/spec/generated/ml.put_filter.json b/x-pack/plugins/console_extensions/spec/generated/ml.put_filter.json
new file mode 100644
index 0000000000000..6d57c433d71f4
--- /dev/null
+++ b/x-pack/plugins/console_extensions/spec/generated/ml.put_filter.json
@@ -0,0 +1,10 @@
+{
+ "ml.put_filter": {
+ "methods": [
+ "PUT"
+ ],
+ "patterns": [
+ "_ml/filters/{filter_id}"
+ ]
+ }
+}
diff --git a/x-pack/plugins/console_extensions/spec/generated/xpack.ml.put_job.json b/x-pack/plugins/console_extensions/spec/generated/ml.put_job.json
similarity index 71%
rename from x-pack/plugins/console_extensions/spec/generated/xpack.ml.put_job.json
rename to x-pack/plugins/console_extensions/spec/generated/ml.put_job.json
index ecd8f59d77574..d8e38a0bd4b9d 100644
--- a/x-pack/plugins/console_extensions/spec/generated/xpack.ml.put_job.json
+++ b/x-pack/plugins/console_extensions/spec/generated/ml.put_job.json
@@ -1,10 +1,10 @@
{
- "xpack.ml.put_job": {
+ "ml.put_job": {
"methods": [
"PUT"
],
"patterns": [
- "_xpack/ml/anomaly_detectors/{job_id}"
+ "_ml/anomaly_detectors/{job_id}"
],
"documentation": "http://www.elastic.co/guide/en/elasticsearch/reference/current/ml-put-job.html"
}
diff --git a/x-pack/plugins/console_extensions/spec/generated/xpack.ml.revert_model_snapshot.json b/x-pack/plugins/console_extensions/spec/generated/ml.revert_model_snapshot.json
similarity index 67%
rename from x-pack/plugins/console_extensions/spec/generated/xpack.ml.revert_model_snapshot.json
rename to x-pack/plugins/console_extensions/spec/generated/ml.revert_model_snapshot.json
index 9193cbb80d2fd..7b6d74d47a711 100644
--- a/x-pack/plugins/console_extensions/spec/generated/xpack.ml.revert_model_snapshot.json
+++ b/x-pack/plugins/console_extensions/spec/generated/ml.revert_model_snapshot.json
@@ -1,5 +1,5 @@
{
- "xpack.ml.revert_model_snapshot": {
+ "ml.revert_model_snapshot": {
"url_params": {
"delete_intervening_results": "__flag__"
},
@@ -7,7 +7,7 @@
"POST"
],
"patterns": [
- "_xpack/ml/anomaly_detectors/{job_id}/model_snapshots/{snapshot_id}/_revert"
+ "_ml/anomaly_detectors/{job_id}/model_snapshots/{snapshot_id}/_revert"
],
"documentation": "http://www.elastic.co/guide/en/elasticsearch/reference/current/ml-revert-snapshot.html"
}
diff --git a/x-pack/plugins/console_extensions/spec/generated/ml.set_upgrade_mode.json b/x-pack/plugins/console_extensions/spec/generated/ml.set_upgrade_mode.json
new file mode 100644
index 0000000000000..ad1734033d9a5
--- /dev/null
+++ b/x-pack/plugins/console_extensions/spec/generated/ml.set_upgrade_mode.json
@@ -0,0 +1,15 @@
+{
+ "ml.set_upgrade_mode": {
+ "url_params": {
+ "enabled": "__flag__",
+ "timeout": ""
+ },
+ "methods": [
+ "POST"
+ ],
+ "patterns": [
+ "_ml/set_upgrade_mode"
+ ],
+ "documentation": "TODO"
+ }
+}
diff --git a/x-pack/plugins/console_extensions/spec/generated/xpack.ml.start_datafeed.json b/x-pack/plugins/console_extensions/spec/generated/ml.start_datafeed.json
similarity index 76%
rename from x-pack/plugins/console_extensions/spec/generated/xpack.ml.start_datafeed.json
rename to x-pack/plugins/console_extensions/spec/generated/ml.start_datafeed.json
index 40479c8c3f687..8171a792d7e33 100644
--- a/x-pack/plugins/console_extensions/spec/generated/xpack.ml.start_datafeed.json
+++ b/x-pack/plugins/console_extensions/spec/generated/ml.start_datafeed.json
@@ -1,5 +1,5 @@
{
- "xpack.ml.start_datafeed": {
+ "ml.start_datafeed": {
"url_params": {
"start": "",
"end": "",
@@ -9,7 +9,7 @@
"POST"
],
"patterns": [
- "_xpack/ml/datafeeds/{datafeed_id}/_start"
+ "_ml/datafeeds/{datafeed_id}/_start"
],
"documentation": "http://www.elastic.co/guide/en/elasticsearch/reference/current/ml-start-datafeed.html"
}
diff --git a/x-pack/plugins/console_extensions/spec/generated/xpack.ml.stop_datafeed.json b/x-pack/plugins/console_extensions/spec/generated/ml.stop_datafeed.json
similarity index 78%
rename from x-pack/plugins/console_extensions/spec/generated/xpack.ml.stop_datafeed.json
rename to x-pack/plugins/console_extensions/spec/generated/ml.stop_datafeed.json
index 2af514532f16a..b10fed7010a7f 100644
--- a/x-pack/plugins/console_extensions/spec/generated/xpack.ml.stop_datafeed.json
+++ b/x-pack/plugins/console_extensions/spec/generated/ml.stop_datafeed.json
@@ -1,5 +1,5 @@
{
- "xpack.ml.stop_datafeed": {
+ "ml.stop_datafeed": {
"url_params": {
"allow_no_datafeeds": "__flag__",
"force": "__flag__",
@@ -9,7 +9,7 @@
"POST"
],
"patterns": [
- "_xpack/ml/datafeeds/{datafeed_id}/_stop"
+ "_ml/datafeeds/{datafeed_id}/_stop"
],
"documentation": "http://www.elastic.co/guide/en/elasticsearch/reference/current/ml-stop-datafeed.html"
}
diff --git a/x-pack/plugins/console_extensions/spec/generated/xpack.ml.update_datafeed.json b/x-pack/plugins/console_extensions/spec/generated/ml.update_datafeed.json
similarity index 68%
rename from x-pack/plugins/console_extensions/spec/generated/xpack.ml.update_datafeed.json
rename to x-pack/plugins/console_extensions/spec/generated/ml.update_datafeed.json
index 953e08dd08c17..9c0d7502d2fbe 100644
--- a/x-pack/plugins/console_extensions/spec/generated/xpack.ml.update_datafeed.json
+++ b/x-pack/plugins/console_extensions/spec/generated/ml.update_datafeed.json
@@ -1,10 +1,10 @@
{
- "xpack.ml.update_datafeed": {
+ "ml.update_datafeed": {
"methods": [
"POST"
],
"patterns": [
- "_xpack/ml/datafeeds/{datafeed_id}/_update"
+ "_ml/datafeeds/{datafeed_id}/_update"
],
"documentation": "http://www.elastic.co/guide/en/elasticsearch/reference/current/ml-update-datafeed.html"
}
diff --git a/x-pack/plugins/console_extensions/spec/generated/ml.update_filter.json b/x-pack/plugins/console_extensions/spec/generated/ml.update_filter.json
new file mode 100644
index 0000000000000..3f48013c2be1c
--- /dev/null
+++ b/x-pack/plugins/console_extensions/spec/generated/ml.update_filter.json
@@ -0,0 +1,10 @@
+{
+ "ml.update_filter": {
+ "methods": [
+ "POST"
+ ],
+ "patterns": [
+ "_ml/filters/{filter_id}/_update"
+ ]
+ }
+}
diff --git a/x-pack/plugins/console_extensions/spec/generated/xpack.ml.update_job.json b/x-pack/plugins/console_extensions/spec/generated/ml.update_job.json
similarity index 68%
rename from x-pack/plugins/console_extensions/spec/generated/xpack.ml.update_job.json
rename to x-pack/plugins/console_extensions/spec/generated/ml.update_job.json
index e3c8abf72d908..7276183b2e0c9 100644
--- a/x-pack/plugins/console_extensions/spec/generated/xpack.ml.update_job.json
+++ b/x-pack/plugins/console_extensions/spec/generated/ml.update_job.json
@@ -1,10 +1,10 @@
{
- "xpack.ml.update_job": {
+ "ml.update_job": {
"methods": [
"POST"
],
"patterns": [
- "_xpack/ml/anomaly_detectors/{job_id}/_update"
+ "_ml/anomaly_detectors/{job_id}/_update"
],
"documentation": "http://www.elastic.co/guide/en/elasticsearch/reference/current/ml-update-job.html"
}
diff --git a/x-pack/plugins/console_extensions/spec/generated/xpack.ml.update_model_snapshot.json b/x-pack/plugins/console_extensions/spec/generated/ml.update_model_snapshot.json
similarity index 59%
rename from x-pack/plugins/console_extensions/spec/generated/xpack.ml.update_model_snapshot.json
rename to x-pack/plugins/console_extensions/spec/generated/ml.update_model_snapshot.json
index 848950d6f5394..80e533eb55826 100644
--- a/x-pack/plugins/console_extensions/spec/generated/xpack.ml.update_model_snapshot.json
+++ b/x-pack/plugins/console_extensions/spec/generated/ml.update_model_snapshot.json
@@ -1,10 +1,10 @@
{
- "xpack.ml.update_model_snapshot": {
+ "ml.update_model_snapshot": {
"methods": [
"POST"
],
"patterns": [
- "_xpack/ml/anomaly_detectors/{job_id}/model_snapshots/{snapshot_id}/_update"
+ "_ml/anomaly_detectors/{job_id}/model_snapshots/{snapshot_id}/_update"
],
"documentation": "http://www.elastic.co/guide/en/elasticsearch/reference/current/ml-update-snapshot.html"
}
diff --git a/x-pack/plugins/console_extensions/spec/generated/ml.upgrade.json b/x-pack/plugins/console_extensions/spec/generated/ml.upgrade.json
new file mode 100644
index 0000000000000..4603b7d5a5e4d
--- /dev/null
+++ b/x-pack/plugins/console_extensions/spec/generated/ml.upgrade.json
@@ -0,0 +1,14 @@
+{
+ "ml.upgrade": {
+ "url_params": {
+ "wait_for_completion": "__flag__"
+ },
+ "methods": [
+ "POST"
+ ],
+ "patterns": [
+ "_ml/_upgrade"
+ ],
+ "documentation": "TODO"
+ }
+}
diff --git a/x-pack/plugins/console_extensions/spec/generated/ml.validate.json b/x-pack/plugins/console_extensions/spec/generated/ml.validate.json
new file mode 100644
index 0000000000000..298c7cf6dce26
--- /dev/null
+++ b/x-pack/plugins/console_extensions/spec/generated/ml.validate.json
@@ -0,0 +1,10 @@
+{
+ "ml.validate": {
+ "methods": [
+ "POST"
+ ],
+ "patterns": [
+ "_ml/anomaly_detectors/_validate"
+ ]
+ }
+}
diff --git a/x-pack/plugins/console_extensions/spec/generated/ml.validate_detector.json b/x-pack/plugins/console_extensions/spec/generated/ml.validate_detector.json
new file mode 100644
index 0000000000000..5e6d7daeea772
--- /dev/null
+++ b/x-pack/plugins/console_extensions/spec/generated/ml.validate_detector.json
@@ -0,0 +1,10 @@
+{
+ "ml.validate_detector": {
+ "methods": [
+ "POST"
+ ],
+ "patterns": [
+ "_ml/anomaly_detectors/_validate/detector"
+ ]
+ }
+}
diff --git a/x-pack/plugins/console_extensions/spec/generated/xpack.monitoring.bulk.json b/x-pack/plugins/console_extensions/spec/generated/monitoring.bulk.json
similarity index 73%
rename from x-pack/plugins/console_extensions/spec/generated/xpack.monitoring.bulk.json
rename to x-pack/plugins/console_extensions/spec/generated/monitoring.bulk.json
index f98aa70ce7cd3..7cb56a9d79d6e 100644
--- a/x-pack/plugins/console_extensions/spec/generated/xpack.monitoring.bulk.json
+++ b/x-pack/plugins/console_extensions/spec/generated/monitoring.bulk.json
@@ -1,5 +1,5 @@
{
- "xpack.monitoring.bulk": {
+ "monitoring.bulk": {
"url_params": {
"system_id": "",
"system_api_version": "",
@@ -10,8 +10,8 @@
"PUT"
],
"patterns": [
- "_xpack/monitoring/_bulk",
- "_xpack/monitoring/{type}/_bulk"
+ "_monitoring/bulk",
+ "_monitoring/{type}/bulk"
],
"documentation": "http://www.elastic.co/guide/en/monitoring/current/appendix-api-bulk.html"
}
diff --git a/x-pack/plugins/console_extensions/spec/generated/security.get_user_privileges.json b/x-pack/plugins/console_extensions/spec/generated/security.get_user_privileges.json
index e5ada00828f73..1b939d2d9a29e 100644
--- a/x-pack/plugins/console_extensions/spec/generated/security.get_user_privileges.json
+++ b/x-pack/plugins/console_extensions/spec/generated/security.get_user_privileges.json
@@ -5,6 +5,7 @@
],
"patterns": [
"_security/user/_privileges"
- ]
+ ],
+ "documentation": "https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-get-user-privileges.html"
}
}
diff --git a/x-pack/plugins/console_extensions/spec/generated/xpack.graph.explore.json b/x-pack/plugins/console_extensions/spec/generated/xpack.graph.explore.json
index f140af08686e2..b2a74408995d7 100644
--- a/x-pack/plugins/console_extensions/spec/generated/xpack.graph.explore.json
+++ b/x-pack/plugins/console_extensions/spec/generated/xpack.graph.explore.json
@@ -9,8 +9,8 @@
"POST"
],
"patterns": [
- "{indices}/_xpack/graph/_explore",
- "{indices}/{type}/_xpack/graph/_explore"
+ "{indices}/_graph/explore",
+ "{indices}/{type}/_graph/explore"
],
"documentation": "https://www.elastic.co/guide/en/elasticsearch/reference/current/graph-explore-api.html"
}
diff --git a/x-pack/plugins/console_extensions/spec/generated/xpack.license.delete.json b/x-pack/plugins/console_extensions/spec/generated/xpack.license.delete.json
index a60c3b8f70f5c..492a0403be62c 100644
--- a/x-pack/plugins/console_extensions/spec/generated/xpack.license.delete.json
+++ b/x-pack/plugins/console_extensions/spec/generated/xpack.license.delete.json
@@ -4,7 +4,7 @@
"DELETE"
],
"patterns": [
- "_xpack/license"
+ "_license"
],
"documentation": "https://www.elastic.co/guide/en/x-pack/current/license-management.html"
}
diff --git a/x-pack/plugins/console_extensions/spec/generated/xpack.license.get.json b/x-pack/plugins/console_extensions/spec/generated/xpack.license.get.json
index f9ca4bc285ecb..ccd7d7eb77914 100644
--- a/x-pack/plugins/console_extensions/spec/generated/xpack.license.get.json
+++ b/x-pack/plugins/console_extensions/spec/generated/xpack.license.get.json
@@ -7,7 +7,7 @@
"GET"
],
"patterns": [
- "_xpack/license"
+ "_license"
],
"documentation": "https://www.elastic.co/guide/en/x-pack/current/license-management.html"
}
diff --git a/x-pack/plugins/console_extensions/spec/generated/xpack.license.get_basic_status.json b/x-pack/plugins/console_extensions/spec/generated/xpack.license.get_basic_status.json
index c83cdd4a95a8d..5a5488208e218 100644
--- a/x-pack/plugins/console_extensions/spec/generated/xpack.license.get_basic_status.json
+++ b/x-pack/plugins/console_extensions/spec/generated/xpack.license.get_basic_status.json
@@ -4,7 +4,7 @@
"GET"
],
"patterns": [
- "_xpack/license/basic_status"
+ "_license/basic_status"
],
"documentation": "https://www.elastic.co/guide/en/x-pack/current/license-management.html"
}
diff --git a/x-pack/plugins/console_extensions/spec/generated/xpack.license.get_trial_status.json b/x-pack/plugins/console_extensions/spec/generated/xpack.license.get_trial_status.json
index cd79e6fdc2c1e..251d899febf53 100644
--- a/x-pack/plugins/console_extensions/spec/generated/xpack.license.get_trial_status.json
+++ b/x-pack/plugins/console_extensions/spec/generated/xpack.license.get_trial_status.json
@@ -4,7 +4,7 @@
"GET"
],
"patterns": [
- "_xpack/license/trial_status"
+ "_license/trial_status"
],
"documentation": "https://www.elastic.co/guide/en/x-pack/current/license-management.html"
}
diff --git a/x-pack/plugins/console_extensions/spec/generated/xpack.license.post.json b/x-pack/plugins/console_extensions/spec/generated/xpack.license.post.json
index 6c5e2c65a56d6..79be105710904 100644
--- a/x-pack/plugins/console_extensions/spec/generated/xpack.license.post.json
+++ b/x-pack/plugins/console_extensions/spec/generated/xpack.license.post.json
@@ -8,7 +8,7 @@
"POST"
],
"patterns": [
- "_xpack/license"
+ "_license"
],
"documentation": "https://www.elastic.co/guide/en/x-pack/current/license-management.html"
}
diff --git a/x-pack/plugins/console_extensions/spec/generated/xpack.license.post_start_basic.json b/x-pack/plugins/console_extensions/spec/generated/xpack.license.post_start_basic.json
index 27da929b25eab..fb858a65c2322 100644
--- a/x-pack/plugins/console_extensions/spec/generated/xpack.license.post_start_basic.json
+++ b/x-pack/plugins/console_extensions/spec/generated/xpack.license.post_start_basic.json
@@ -7,7 +7,7 @@
"POST"
],
"patterns": [
- "_xpack/license/start_basic"
+ "_license/start_basic"
],
"documentation": "https://www.elastic.co/guide/en/x-pack/current/license-management.html"
}
diff --git a/x-pack/plugins/console_extensions/spec/generated/xpack.license.post_start_trial.json b/x-pack/plugins/console_extensions/spec/generated/xpack.license.post_start_trial.json
index 905b8b324d5ef..bd3eaf476e022 100644
--- a/x-pack/plugins/console_extensions/spec/generated/xpack.license.post_start_trial.json
+++ b/x-pack/plugins/console_extensions/spec/generated/xpack.license.post_start_trial.json
@@ -8,7 +8,7 @@
"POST"
],
"patterns": [
- "_xpack/license/start_trial"
+ "_license/start_trial"
],
"documentation": "https://www.elastic.co/guide/en/x-pack/current/license-management.html"
}
diff --git a/x-pack/plugins/console_extensions/spec/generated/xpack.migration.deprecations.json b/x-pack/plugins/console_extensions/spec/generated/xpack.migration.deprecations.json
index d8dbea2c53d7a..dad2695f0d14c 100644
--- a/x-pack/plugins/console_extensions/spec/generated/xpack.migration.deprecations.json
+++ b/x-pack/plugins/console_extensions/spec/generated/xpack.migration.deprecations.json
@@ -4,8 +4,8 @@
"GET"
],
"patterns": [
- "_xpack/migration/deprecations",
- "{indices}/_xpack/migration/deprecations"
+ "_migration/deprecations",
+ "{indices}/_migration/deprecations"
],
"documentation": "http://www.elastic.co/guide/en/migration/current/migration-api-deprecation.html"
}
diff --git a/x-pack/plugins/console_extensions/spec/generated/xpack.migration.get_assistance.json b/x-pack/plugins/console_extensions/spec/generated/xpack.migration.get_assistance.json
index dcd81df3770a2..4cc068ce2e460 100644
--- a/x-pack/plugins/console_extensions/spec/generated/xpack.migration.get_assistance.json
+++ b/x-pack/plugins/console_extensions/spec/generated/xpack.migration.get_assistance.json
@@ -14,8 +14,8 @@
"GET"
],
"patterns": [
- "_xpack/migration/assistance",
- "_xpack/migration/assistance/{indices}"
+ "_migration/assistance",
+ "_migration/assistance/{indices}"
],
"documentation": "https://www.elastic.co/guide/en/elasticsearch/reference/current/migration-api-assistance.html"
}
diff --git a/x-pack/plugins/console_extensions/spec/generated/xpack.migration.upgrade.json b/x-pack/plugins/console_extensions/spec/generated/xpack.migration.upgrade.json
index 331a93f176320..93186f31a0876 100644
--- a/x-pack/plugins/console_extensions/spec/generated/xpack.migration.upgrade.json
+++ b/x-pack/plugins/console_extensions/spec/generated/xpack.migration.upgrade.json
@@ -7,7 +7,7 @@
"POST"
],
"patterns": [
- "_xpack/migration/upgrade/{indices}"
+ "_migration/upgrade/{indices}"
],
"documentation": "https://www.elastic.co/guide/en/elasticsearch/reference/current/migration-api-upgrade.html"
}
diff --git a/x-pack/plugins/console_extensions/spec/generated/xpack.ml.delete_calendar.json b/x-pack/plugins/console_extensions/spec/generated/xpack.ml.delete_calendar.json
deleted file mode 100644
index d5e47c1d78c7c..0000000000000
--- a/x-pack/plugins/console_extensions/spec/generated/xpack.ml.delete_calendar.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
- "xpack.ml.delete_calendar": {
- "methods": [
- "DELETE"
- ],
- "patterns": [
- "_xpack/ml/calendars/{calendar_id}"
- ]
- }
-}
diff --git a/x-pack/plugins/console_extensions/spec/generated/xpack.ml.delete_calendar_event.json b/x-pack/plugins/console_extensions/spec/generated/xpack.ml.delete_calendar_event.json
deleted file mode 100644
index 2be7a261b1d20..0000000000000
--- a/x-pack/plugins/console_extensions/spec/generated/xpack.ml.delete_calendar_event.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
- "xpack.ml.delete_calendar_event": {
- "methods": [
- "DELETE"
- ],
- "patterns": [
- "_xpack/ml/calendars/{calendar_id}/events/{event_id}"
- ]
- }
-}
diff --git a/x-pack/plugins/console_extensions/spec/generated/xpack.ml.delete_calendar_job.json b/x-pack/plugins/console_extensions/spec/generated/xpack.ml.delete_calendar_job.json
deleted file mode 100644
index 7d3716f9ebfea..0000000000000
--- a/x-pack/plugins/console_extensions/spec/generated/xpack.ml.delete_calendar_job.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
- "xpack.ml.delete_calendar_job": {
- "methods": [
- "DELETE"
- ],
- "patterns": [
- "_xpack/ml/calendars/{calendar_id}/jobs/{job_id}"
- ]
- }
-}
diff --git a/x-pack/plugins/console_extensions/spec/generated/xpack.ml.delete_expired_data.json b/x-pack/plugins/console_extensions/spec/generated/xpack.ml.delete_expired_data.json
deleted file mode 100644
index e8c04ff315731..0000000000000
--- a/x-pack/plugins/console_extensions/spec/generated/xpack.ml.delete_expired_data.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
- "xpack.ml.delete_expired_data": {
- "methods": [
- "DELETE"
- ],
- "patterns": [
- "_xpack/ml/_delete_expired_data"
- ]
- }
-}
diff --git a/x-pack/plugins/console_extensions/spec/generated/xpack.ml.post_calendar_events.json b/x-pack/plugins/console_extensions/spec/generated/xpack.ml.post_calendar_events.json
deleted file mode 100644
index ec580842f5120..0000000000000
--- a/x-pack/plugins/console_extensions/spec/generated/xpack.ml.post_calendar_events.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
- "xpack.ml.post_calendar_events": {
- "methods": [
- "POST"
- ],
- "patterns": [
- "_xpack/ml/calendars/{calendar_id}/events"
- ]
- }
-}
diff --git a/x-pack/plugins/console_extensions/spec/generated/xpack.ml.put_calendar.json b/x-pack/plugins/console_extensions/spec/generated/xpack.ml.put_calendar.json
deleted file mode 100644
index 706373c53e852..0000000000000
--- a/x-pack/plugins/console_extensions/spec/generated/xpack.ml.put_calendar.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
- "xpack.ml.put_calendar": {
- "methods": [
- "PUT"
- ],
- "patterns": [
- "_xpack/ml/calendars/{calendar_id}"
- ]
- }
-}
diff --git a/x-pack/plugins/console_extensions/spec/generated/xpack.ml.put_calendar_job.json b/x-pack/plugins/console_extensions/spec/generated/xpack.ml.put_calendar_job.json
deleted file mode 100644
index 98a4db0bf0e0e..0000000000000
--- a/x-pack/plugins/console_extensions/spec/generated/xpack.ml.put_calendar_job.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
- "xpack.ml.put_calendar_job": {
- "methods": [
- "PUT"
- ],
- "patterns": [
- "_xpack/ml/calendars/{calendar_id}/jobs/{job_id}"
- ]
- }
-}
diff --git a/x-pack/plugins/console_extensions/spec/generated/xpack.ml.validate.json b/x-pack/plugins/console_extensions/spec/generated/xpack.ml.validate.json
deleted file mode 100644
index 9af94e51db0f5..0000000000000
--- a/x-pack/plugins/console_extensions/spec/generated/xpack.ml.validate.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
- "xpack.ml.validate": {
- "methods": [
- "POST"
- ],
- "patterns": [
- "_xpack/ml/anomaly_detectors/_validate"
- ]
- }
-}
diff --git a/x-pack/plugins/console_extensions/spec/generated/xpack.ml.validate_detector.json b/x-pack/plugins/console_extensions/spec/generated/xpack.ml.validate_detector.json
deleted file mode 100644
index de0d19b09619a..0000000000000
--- a/x-pack/plugins/console_extensions/spec/generated/xpack.ml.validate_detector.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
- "xpack.ml.validate_detector": {
- "methods": [
- "POST"
- ],
- "patterns": [
- "_xpack/ml/anomaly_detectors/_validate/detector"
- ]
- }
-}
diff --git a/x-pack/plugins/console_extensions/spec/generated/xpack.rollup.delete_job.json b/x-pack/plugins/console_extensions/spec/generated/xpack.rollup.delete_job.json
index a7c381c2ee7f9..586ebd6ff6723 100644
--- a/x-pack/plugins/console_extensions/spec/generated/xpack.rollup.delete_job.json
+++ b/x-pack/plugins/console_extensions/spec/generated/xpack.rollup.delete_job.json
@@ -4,7 +4,7 @@
"DELETE"
],
"patterns": [
- "_xpack/rollup/job/{id}"
+ "_rollup/job/{id}"
]
}
}
diff --git a/x-pack/plugins/console_extensions/spec/generated/xpack.rollup.get_jobs.json b/x-pack/plugins/console_extensions/spec/generated/xpack.rollup.get_jobs.json
index 54c535f3a81f7..657b68fc214b0 100644
--- a/x-pack/plugins/console_extensions/spec/generated/xpack.rollup.get_jobs.json
+++ b/x-pack/plugins/console_extensions/spec/generated/xpack.rollup.get_jobs.json
@@ -4,8 +4,8 @@
"GET"
],
"patterns": [
- "_xpack/rollup/job/{id}",
- "_xpack/rollup/job/"
+ "_rollup/job/{id}",
+ "_rollup/job/"
]
}
}
diff --git a/x-pack/plugins/console_extensions/spec/generated/xpack.rollup.get_rollup_caps.json b/x-pack/plugins/console_extensions/spec/generated/xpack.rollup.get_rollup_caps.json
index f619949e63be1..a8145f69eb50b 100644
--- a/x-pack/plugins/console_extensions/spec/generated/xpack.rollup.get_rollup_caps.json
+++ b/x-pack/plugins/console_extensions/spec/generated/xpack.rollup.get_rollup_caps.json
@@ -4,8 +4,8 @@
"GET"
],
"patterns": [
- "_xpack/rollup/data/{id}",
- "_xpack/rollup/data/"
+ "_rollup/data/{id}",
+ "_rollup/data/"
]
}
}
diff --git a/x-pack/plugins/console_extensions/spec/generated/xpack.rollup.get_rollup_index_caps.json b/x-pack/plugins/console_extensions/spec/generated/xpack.rollup.get_rollup_index_caps.json
new file mode 100644
index 0000000000000..e2f94ae5648ec
--- /dev/null
+++ b/x-pack/plugins/console_extensions/spec/generated/xpack.rollup.get_rollup_index_caps.json
@@ -0,0 +1,10 @@
+{
+ "xpack.rollup.get_rollup_index_caps": {
+ "methods": [
+ "GET"
+ ],
+ "patterns": [
+ "{indices}/_rollup/data"
+ ]
+ }
+}
diff --git a/x-pack/plugins/console_extensions/spec/generated/xpack.rollup.put_job.json b/x-pack/plugins/console_extensions/spec/generated/xpack.rollup.put_job.json
index d55fe948c450c..e36ec37c93b68 100644
--- a/x-pack/plugins/console_extensions/spec/generated/xpack.rollup.put_job.json
+++ b/x-pack/plugins/console_extensions/spec/generated/xpack.rollup.put_job.json
@@ -4,7 +4,7 @@
"PUT"
],
"patterns": [
- "_xpack/rollup/job/{id}"
+ "_rollup/job/{id}"
]
}
}
diff --git a/x-pack/plugins/console_extensions/spec/generated/xpack.rollup.rollup_search.json b/x-pack/plugins/console_extensions/spec/generated/xpack.rollup.rollup_search.json
index 544d86249b40d..f6a8caff17201 100644
--- a/x-pack/plugins/console_extensions/spec/generated/xpack.rollup.rollup_search.json
+++ b/x-pack/plugins/console_extensions/spec/generated/xpack.rollup.rollup_search.json
@@ -1,5 +1,9 @@
{
"xpack.rollup.rollup_search": {
+ "url_params": {
+ "typed_keys": "__flag__",
+ "rest_total_hits_as_int": "__flag__"
+ },
"methods": [
"GET",
"POST"
diff --git a/x-pack/plugins/console_extensions/spec/generated/xpack.rollup.start_job.json b/x-pack/plugins/console_extensions/spec/generated/xpack.rollup.start_job.json
index 7a1323f1f79b3..e7b1f48f8cdf5 100644
--- a/x-pack/plugins/console_extensions/spec/generated/xpack.rollup.start_job.json
+++ b/x-pack/plugins/console_extensions/spec/generated/xpack.rollup.start_job.json
@@ -4,7 +4,7 @@
"POST"
],
"patterns": [
- "_xpack/rollup/job/{id}/_start"
+ "_rollup/job/{id}/_start"
]
}
}
diff --git a/x-pack/plugins/console_extensions/spec/generated/xpack.rollup.stop_job.json b/x-pack/plugins/console_extensions/spec/generated/xpack.rollup.stop_job.json
index e185077e35f16..58706694e2ff4 100644
--- a/x-pack/plugins/console_extensions/spec/generated/xpack.rollup.stop_job.json
+++ b/x-pack/plugins/console_extensions/spec/generated/xpack.rollup.stop_job.json
@@ -1,10 +1,14 @@
{
"xpack.rollup.stop_job": {
+ "url_params": {
+ "wait_for_completion": "__flag__",
+ "timeout": ""
+ },
"methods": [
"POST"
],
"patterns": [
- "_xpack/rollup/job/{id}/_stop"
+ "_rollup/job/{id}/_stop"
]
}
}
diff --git a/x-pack/plugins/console_extensions/spec/generated/xpack.security.authenticate.json b/x-pack/plugins/console_extensions/spec/generated/xpack.security.authenticate.json
deleted file mode 100644
index 6ebef7ce874d9..0000000000000
--- a/x-pack/plugins/console_extensions/spec/generated/xpack.security.authenticate.json
+++ /dev/null
@@ -1,11 +0,0 @@
-{
- "xpack.security.authenticate": {
- "methods": [
- "GET"
- ],
- "patterns": [
- "_xpack/security/_authenticate"
- ],
- "documentation": "https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-authenticate.html"
- }
-}
diff --git a/x-pack/plugins/console_extensions/spec/generated/xpack.security.change_password.json b/x-pack/plugins/console_extensions/spec/generated/xpack.security.change_password.json
deleted file mode 100644
index a811501e4d71f..0000000000000
--- a/x-pack/plugins/console_extensions/spec/generated/xpack.security.change_password.json
+++ /dev/null
@@ -1,20 +0,0 @@
-{
- "xpack.security.change_password": {
- "url_params": {
- "refresh": [
- "true",
- "false",
- "wait_for"
- ]
- },
- "methods": [
- "PUT",
- "POST"
- ],
- "patterns": [
- "_xpack/security/user/{username}/_password",
- "_xpack/security/user/_password"
- ],
- "documentation": "https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-change-password.html"
- }
-}
diff --git a/x-pack/plugins/console_extensions/spec/generated/xpack.security.clear_cached_realms.json b/x-pack/plugins/console_extensions/spec/generated/xpack.security.clear_cached_realms.json
deleted file mode 100644
index 2ef0bfaf79df1..0000000000000
--- a/x-pack/plugins/console_extensions/spec/generated/xpack.security.clear_cached_realms.json
+++ /dev/null
@@ -1,14 +0,0 @@
-{
- "xpack.security.clear_cached_realms": {
- "url_params": {
- "usernames": []
- },
- "methods": [
- "POST"
- ],
- "patterns": [
- "_xpack/security/realm/{realms}/_clear_cache"
- ],
- "documentation": "https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-clear-cache.html"
- }
-}
diff --git a/x-pack/plugins/console_extensions/spec/generated/xpack.security.clear_cached_roles.json b/x-pack/plugins/console_extensions/spec/generated/xpack.security.clear_cached_roles.json
deleted file mode 100644
index 47baad3ef989f..0000000000000
--- a/x-pack/plugins/console_extensions/spec/generated/xpack.security.clear_cached_roles.json
+++ /dev/null
@@ -1,11 +0,0 @@
-{
- "xpack.security.clear_cached_roles": {
- "methods": [
- "POST"
- ],
- "patterns": [
- "_xpack/security/role/{name}/_clear_cache"
- ],
- "documentation": "https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-clear-role-cache.html"
- }
-}
diff --git a/x-pack/plugins/console_extensions/spec/generated/xpack.security.delete_role.json b/x-pack/plugins/console_extensions/spec/generated/xpack.security.delete_role.json
deleted file mode 100644
index ad95ac444ef98..0000000000000
--- a/x-pack/plugins/console_extensions/spec/generated/xpack.security.delete_role.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "xpack.security.delete_role": {
- "url_params": {
- "refresh": [
- "true",
- "false",
- "wait_for"
- ]
- },
- "methods": [
- "DELETE"
- ],
- "patterns": [
- "_xpack/security/role/{name}"
- ],
- "documentation": "https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-delete-role.html"
- }
-}
diff --git a/x-pack/plugins/console_extensions/spec/generated/xpack.security.delete_role_mapping.json b/x-pack/plugins/console_extensions/spec/generated/xpack.security.delete_role_mapping.json
deleted file mode 100644
index 0734c784b80f8..0000000000000
--- a/x-pack/plugins/console_extensions/spec/generated/xpack.security.delete_role_mapping.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "xpack.security.delete_role_mapping": {
- "url_params": {
- "refresh": [
- "true",
- "false",
- "wait_for"
- ]
- },
- "methods": [
- "DELETE"
- ],
- "patterns": [
- "_xpack/security/role_mapping/{name}"
- ],
- "documentation": "https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-delete-role-mapping.html"
- }
-}
diff --git a/x-pack/plugins/console_extensions/spec/generated/xpack.security.delete_user.json b/x-pack/plugins/console_extensions/spec/generated/xpack.security.delete_user.json
deleted file mode 100644
index 732721143503e..0000000000000
--- a/x-pack/plugins/console_extensions/spec/generated/xpack.security.delete_user.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "xpack.security.delete_user": {
- "url_params": {
- "refresh": [
- "true",
- "false",
- "wait_for"
- ]
- },
- "methods": [
- "DELETE"
- ],
- "patterns": [
- "_xpack/security/user/{username}"
- ],
- "documentation": "https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-delete-user.html"
- }
-}
diff --git a/x-pack/plugins/console_extensions/spec/generated/xpack.security.disable_user.json b/x-pack/plugins/console_extensions/spec/generated/xpack.security.disable_user.json
deleted file mode 100644
index b9151cf3685a1..0000000000000
--- a/x-pack/plugins/console_extensions/spec/generated/xpack.security.disable_user.json
+++ /dev/null
@@ -1,19 +0,0 @@
-{
- "xpack.security.disable_user": {
- "url_params": {
- "refresh": [
- "true",
- "false",
- "wait_for"
- ]
- },
- "methods": [
- "PUT",
- "POST"
- ],
- "patterns": [
- "_xpack/security/user/{username}/_disable"
- ],
- "documentation": "https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-disable-user.html"
- }
-}
diff --git a/x-pack/plugins/console_extensions/spec/generated/xpack.security.enable_user.json b/x-pack/plugins/console_extensions/spec/generated/xpack.security.enable_user.json
deleted file mode 100644
index 12d1b3c7cf0bb..0000000000000
--- a/x-pack/plugins/console_extensions/spec/generated/xpack.security.enable_user.json
+++ /dev/null
@@ -1,19 +0,0 @@
-{
- "xpack.security.enable_user": {
- "url_params": {
- "refresh": [
- "true",
- "false",
- "wait_for"
- ]
- },
- "methods": [
- "PUT",
- "POST"
- ],
- "patterns": [
- "_xpack/security/user/{username}/_enable"
- ],
- "documentation": "https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-enable-user.html"
- }
-}
diff --git a/x-pack/plugins/console_extensions/spec/generated/xpack.security.get_role.json b/x-pack/plugins/console_extensions/spec/generated/xpack.security.get_role.json
deleted file mode 100644
index e4b887e3d9329..0000000000000
--- a/x-pack/plugins/console_extensions/spec/generated/xpack.security.get_role.json
+++ /dev/null
@@ -1,12 +0,0 @@
-{
- "xpack.security.get_role": {
- "methods": [
- "GET"
- ],
- "patterns": [
- "_xpack/security/role/{name}",
- "_xpack/security/role"
- ],
- "documentation": "https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-get-role.html"
- }
-}
diff --git a/x-pack/plugins/console_extensions/spec/generated/xpack.security.get_role_mapping.json b/x-pack/plugins/console_extensions/spec/generated/xpack.security.get_role_mapping.json
deleted file mode 100644
index 45c935277c865..0000000000000
--- a/x-pack/plugins/console_extensions/spec/generated/xpack.security.get_role_mapping.json
+++ /dev/null
@@ -1,12 +0,0 @@
-{
- "xpack.security.get_role_mapping": {
- "methods": [
- "GET"
- ],
- "patterns": [
- "_xpack/security/role_mapping/{name}",
- "_xpack/security/role_mapping"
- ],
- "documentation": "https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-get-role-mapping.html"
- }
-}
diff --git a/x-pack/plugins/console_extensions/spec/generated/xpack.security.get_token.json b/x-pack/plugins/console_extensions/spec/generated/xpack.security.get_token.json
deleted file mode 100644
index 208d6e31346b7..0000000000000
--- a/x-pack/plugins/console_extensions/spec/generated/xpack.security.get_token.json
+++ /dev/null
@@ -1,11 +0,0 @@
-{
- "xpack.security.get_token": {
- "methods": [
- "POST"
- ],
- "patterns": [
- "_xpack/security/oauth2/token"
- ],
- "documentation": "https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-get-token.html"
- }
-}
diff --git a/x-pack/plugins/console_extensions/spec/generated/xpack.security.get_user.json b/x-pack/plugins/console_extensions/spec/generated/xpack.security.get_user.json
deleted file mode 100644
index d42d1afbb91c9..0000000000000
--- a/x-pack/plugins/console_extensions/spec/generated/xpack.security.get_user.json
+++ /dev/null
@@ -1,12 +0,0 @@
-{
- "xpack.security.get_user": {
- "methods": [
- "GET"
- ],
- "patterns": [
- "_xpack/security/user/{username}",
- "_xpack/security/user"
- ],
- "documentation": "https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-get-user.html"
- }
-}
diff --git a/x-pack/plugins/console_extensions/spec/generated/xpack.security.invalidate_token.json b/x-pack/plugins/console_extensions/spec/generated/xpack.security.invalidate_token.json
deleted file mode 100644
index e9ffac7bd5f92..0000000000000
--- a/x-pack/plugins/console_extensions/spec/generated/xpack.security.invalidate_token.json
+++ /dev/null
@@ -1,11 +0,0 @@
-{
- "xpack.security.invalidate_token": {
- "methods": [
- "DELETE"
- ],
- "patterns": [
- "_xpack/security/oauth2/token"
- ],
- "documentation": "https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-invalidate-token.html"
- }
-}
diff --git a/x-pack/plugins/console_extensions/spec/generated/xpack.security.put_role.json b/x-pack/plugins/console_extensions/spec/generated/xpack.security.put_role.json
deleted file mode 100644
index 6cc3523f8b647..0000000000000
--- a/x-pack/plugins/console_extensions/spec/generated/xpack.security.put_role.json
+++ /dev/null
@@ -1,19 +0,0 @@
-{
- "xpack.security.put_role": {
- "url_params": {
- "refresh": [
- "true",
- "false",
- "wait_for"
- ]
- },
- "methods": [
- "PUT",
- "POST"
- ],
- "patterns": [
- "_xpack/security/role/{name}"
- ],
- "documentation": "https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-put-role.html"
- }
-}
diff --git a/x-pack/plugins/console_extensions/spec/generated/xpack.security.put_role_mapping.json b/x-pack/plugins/console_extensions/spec/generated/xpack.security.put_role_mapping.json
deleted file mode 100644
index 7a426c420fffd..0000000000000
--- a/x-pack/plugins/console_extensions/spec/generated/xpack.security.put_role_mapping.json
+++ /dev/null
@@ -1,19 +0,0 @@
-{
- "xpack.security.put_role_mapping": {
- "url_params": {
- "refresh": [
- "true",
- "false",
- "wait_for"
- ]
- },
- "methods": [
- "PUT",
- "POST"
- ],
- "patterns": [
- "_xpack/security/role_mapping/{name}"
- ],
- "documentation": "https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-put-role-mapping.html"
- }
-}
diff --git a/x-pack/plugins/console_extensions/spec/generated/xpack.security.put_user.json b/x-pack/plugins/console_extensions/spec/generated/xpack.security.put_user.json
deleted file mode 100644
index 19a13b37c7d91..0000000000000
--- a/x-pack/plugins/console_extensions/spec/generated/xpack.security.put_user.json
+++ /dev/null
@@ -1,19 +0,0 @@
-{
- "xpack.security.put_user": {
- "url_params": {
- "refresh": [
- "true",
- "false",
- "wait_for"
- ]
- },
- "methods": [
- "PUT",
- "POST"
- ],
- "patterns": [
- "_xpack/security/user/{username}"
- ],
- "documentation": "https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-put-user.html"
- }
-}
diff --git a/x-pack/plugins/console_extensions/spec/generated/xpack.sql.clear_cursor.json b/x-pack/plugins/console_extensions/spec/generated/xpack.sql.clear_cursor.json
index f1b357e909bd6..037df31e3277a 100644
--- a/x-pack/plugins/console_extensions/spec/generated/xpack.sql.clear_cursor.json
+++ b/x-pack/plugins/console_extensions/spec/generated/xpack.sql.clear_cursor.json
@@ -4,7 +4,7 @@
"POST"
],
"patterns": [
- "_xpack/sql/close"
+ "_sql/close"
],
"documentation": "Clear SQL cursor"
}
diff --git a/x-pack/plugins/console_extensions/spec/generated/xpack.sql.query.json b/x-pack/plugins/console_extensions/spec/generated/xpack.sql.query.json
index 20b8502f79bfc..6f1f9fda541a6 100644
--- a/x-pack/plugins/console_extensions/spec/generated/xpack.sql.query.json
+++ b/x-pack/plugins/console_extensions/spec/generated/xpack.sql.query.json
@@ -8,7 +8,7 @@
"GET"
],
"patterns": [
- "_xpack/sql"
+ "_sql"
],
"documentation": "Execute SQL"
}
diff --git a/x-pack/plugins/console_extensions/spec/generated/xpack.sql.translate.json b/x-pack/plugins/console_extensions/spec/generated/xpack.sql.translate.json
index 737a57f9f5ca6..32f49659194a1 100644
--- a/x-pack/plugins/console_extensions/spec/generated/xpack.sql.translate.json
+++ b/x-pack/plugins/console_extensions/spec/generated/xpack.sql.translate.json
@@ -5,7 +5,7 @@
"GET"
],
"patterns": [
- "_xpack/sql/translate"
+ "_sql/translate"
],
"documentation": "Translate SQL into Elasticsearch queries"
}
diff --git a/x-pack/plugins/console_extensions/spec/generated/xpack.watcher.ack_watch.json b/x-pack/plugins/console_extensions/spec/generated/xpack.watcher.ack_watch.json
index 53edb6183e2d9..acda1c9e716dd 100644
--- a/x-pack/plugins/console_extensions/spec/generated/xpack.watcher.ack_watch.json
+++ b/x-pack/plugins/console_extensions/spec/generated/xpack.watcher.ack_watch.json
@@ -5,8 +5,8 @@
"POST"
],
"patterns": [
- "_xpack/watcher/watch/{watch_id}/_ack",
- "_xpack/watcher/watch/{watch_id}/_ack/{action_id}"
+ "_watcher/watch/{watch_id}/_ack",
+ "_watcher/watch/{watch_id}/_ack/{action_id}"
],
"documentation": "http://www.elastic.co/guide/en/elasticsearch/reference/current/watcher-api-ack-watch.html"
}
diff --git a/x-pack/plugins/console_extensions/spec/generated/xpack.watcher.activate_watch.json b/x-pack/plugins/console_extensions/spec/generated/xpack.watcher.activate_watch.json
index 57a1804b8918d..d69d581f01195 100644
--- a/x-pack/plugins/console_extensions/spec/generated/xpack.watcher.activate_watch.json
+++ b/x-pack/plugins/console_extensions/spec/generated/xpack.watcher.activate_watch.json
@@ -5,7 +5,7 @@
"POST"
],
"patterns": [
- "_xpack/watcher/watch/{watch_id}/_activate"
+ "_watcher/watch/{watch_id}/_activate"
],
"documentation": "https://www.elastic.co/guide/en/elasticsearch/reference/current/watcher-api-activate-watch.html"
}
diff --git a/x-pack/plugins/console_extensions/spec/generated/xpack.watcher.deactivate_watch.json b/x-pack/plugins/console_extensions/spec/generated/xpack.watcher.deactivate_watch.json
index dd1bf97787855..2bc0ad6d9df21 100644
--- a/x-pack/plugins/console_extensions/spec/generated/xpack.watcher.deactivate_watch.json
+++ b/x-pack/plugins/console_extensions/spec/generated/xpack.watcher.deactivate_watch.json
@@ -5,7 +5,7 @@
"POST"
],
"patterns": [
- "_xpack/watcher/watch/{watch_id}/_deactivate"
+ "_watcher/watch/{watch_id}/_deactivate"
],
"documentation": "https://www.elastic.co/guide/en/elasticsearch/reference/current/watcher-api-deactivate-watch.html"
}
diff --git a/x-pack/plugins/console_extensions/spec/generated/xpack.watcher.delete_watch.json b/x-pack/plugins/console_extensions/spec/generated/xpack.watcher.delete_watch.json
index 555e76fb9de2e..5f4ca7c6d464a 100644
--- a/x-pack/plugins/console_extensions/spec/generated/xpack.watcher.delete_watch.json
+++ b/x-pack/plugins/console_extensions/spec/generated/xpack.watcher.delete_watch.json
@@ -4,7 +4,7 @@
"DELETE"
],
"patterns": [
- "_xpack/watcher/watch/{id}"
+ "_watcher/watch/{id}"
],
"documentation": "http://www.elastic.co/guide/en/elasticsearch/reference/current/watcher-api-delete-watch.html"
}
diff --git a/x-pack/plugins/console_extensions/spec/generated/xpack.watcher.execute_watch.json b/x-pack/plugins/console_extensions/spec/generated/xpack.watcher.execute_watch.json
index 2c64b9b842038..3697792424e26 100644
--- a/x-pack/plugins/console_extensions/spec/generated/xpack.watcher.execute_watch.json
+++ b/x-pack/plugins/console_extensions/spec/generated/xpack.watcher.execute_watch.json
@@ -8,8 +8,8 @@
"POST"
],
"patterns": [
- "_xpack/watcher/watch/{id}/_execute",
- "_xpack/watcher/watch/_execute"
+ "_watcher/watch/{id}/_execute",
+ "_watcher/watch/_execute"
],
"documentation": "http://www.elastic.co/guide/en/elasticsearch/reference/current/watcher-api-execute-watch.html"
}
diff --git a/x-pack/plugins/console_extensions/spec/generated/xpack.watcher.get_watch.json b/x-pack/plugins/console_extensions/spec/generated/xpack.watcher.get_watch.json
index fc2a7d862fd9a..53aedbba8a5b4 100644
--- a/x-pack/plugins/console_extensions/spec/generated/xpack.watcher.get_watch.json
+++ b/x-pack/plugins/console_extensions/spec/generated/xpack.watcher.get_watch.json
@@ -4,7 +4,7 @@
"GET"
],
"patterns": [
- "_xpack/watcher/watch/{id}"
+ "_watcher/watch/{id}"
],
"documentation": "http://www.elastic.co/guide/en/elasticsearch/reference/current/watcher-api-get-watch.html"
}
diff --git a/x-pack/plugins/console_extensions/spec/generated/xpack.watcher.put_watch.json b/x-pack/plugins/console_extensions/spec/generated/xpack.watcher.put_watch.json
index bc6951d058f74..ac24ba1599263 100644
--- a/x-pack/plugins/console_extensions/spec/generated/xpack.watcher.put_watch.json
+++ b/x-pack/plugins/console_extensions/spec/generated/xpack.watcher.put_watch.json
@@ -9,7 +9,7 @@
"POST"
],
"patterns": [
- "_xpack/watcher/watch/{id}"
+ "_watcher/watch/{id}"
],
"documentation": "http://www.elastic.co/guide/en/elasticsearch/reference/current/watcher-api-put-watch.html"
}
diff --git a/x-pack/plugins/console_extensions/spec/generated/xpack.watcher.start.json b/x-pack/plugins/console_extensions/spec/generated/xpack.watcher.start.json
index 769b9e4e9c941..489965e741944 100644
--- a/x-pack/plugins/console_extensions/spec/generated/xpack.watcher.start.json
+++ b/x-pack/plugins/console_extensions/spec/generated/xpack.watcher.start.json
@@ -4,7 +4,7 @@
"POST"
],
"patterns": [
- "_xpack/watcher/_start"
+ "_watcher/_start"
],
"documentation": "http://www.elastic.co/guide/en/elasticsearch/reference/current/watcher-api-start.html"
}
diff --git a/x-pack/plugins/console_extensions/spec/generated/xpack.watcher.stats.json b/x-pack/plugins/console_extensions/spec/generated/xpack.watcher.stats.json
index 1a1df49a44c74..429523ea5d2ec 100644
--- a/x-pack/plugins/console_extensions/spec/generated/xpack.watcher.stats.json
+++ b/x-pack/plugins/console_extensions/spec/generated/xpack.watcher.stats.json
@@ -4,6 +4,7 @@
"metric": [
"_all",
"queued_watches",
+ "current_watches",
"pending_watches"
],
"emit_stacktraces": "__flag__"
@@ -12,12 +13,13 @@
"GET"
],
"patterns": [
- "_xpack/watcher/stats",
- "_xpack/watcher/stats/{metrics}"
+ "_watcher/stats",
+ "_watcher/stats/{metrics}"
],
"url_components": {
"metrics": [
"_all",
+ "current_watches",
"pending_watches",
"queued_watches"
]
diff --git a/x-pack/plugins/console_extensions/spec/generated/xpack.watcher.stop.json b/x-pack/plugins/console_extensions/spec/generated/xpack.watcher.stop.json
index 85e9c63158109..4e5b3f4c52dcf 100644
--- a/x-pack/plugins/console_extensions/spec/generated/xpack.watcher.stop.json
+++ b/x-pack/plugins/console_extensions/spec/generated/xpack.watcher.stop.json
@@ -4,7 +4,7 @@
"POST"
],
"patterns": [
- "_xpack/watcher/_stop"
+ "_watcher/_stop"
],
"documentation": "http://www.elastic.co/guide/en/elasticsearch/reference/current/watcher-api-stop.html"
}
diff --git a/x-pack/plugins/console_extensions/spec/overrides/xpack.ml.get_buckets.json b/x-pack/plugins/console_extensions/spec/overrides/ml.get_buckets.json
similarity index 92%
rename from x-pack/plugins/console_extensions/spec/overrides/xpack.ml.get_buckets.json
rename to x-pack/plugins/console_extensions/spec/overrides/ml.get_buckets.json
index cfcb0270b9649..d920ea4db4e95 100644
--- a/x-pack/plugins/console_extensions/spec/overrides/xpack.ml.get_buckets.json
+++ b/x-pack/plugins/console_extensions/spec/overrides/ml.get_buckets.json
@@ -1,5 +1,5 @@
{
- "xpack.ml.get_buckets": {
+ "ml.get_buckets": {
"data_autocomplete_rules": {
"desc": { "__one_of": ["true", "false"] },
"exclude_interim": { "__one_of": ["true", "false"] },
diff --git a/x-pack/plugins/console_extensions/spec/overrides/xpack.ml.get_calendar_events.json b/x-pack/plugins/console_extensions/spec/overrides/ml.get_calendar_events.json
similarity index 69%
rename from x-pack/plugins/console_extensions/spec/overrides/xpack.ml.get_calendar_events.json
rename to x-pack/plugins/console_extensions/spec/overrides/ml.get_calendar_events.json
index 9af9354cccde3..e2ebea39a6bcf 100644
--- a/x-pack/plugins/console_extensions/spec/overrides/xpack.ml.get_calendar_events.json
+++ b/x-pack/plugins/console_extensions/spec/overrides/ml.get_calendar_events.json
@@ -1,5 +1,5 @@
{
- "xpack.ml.get_calendar_events": {
+ "ml.get_calendar_events": {
"data_autocomplete_rules": {
"from": 0,
"size": 100
diff --git a/x-pack/plugins/console_extensions/spec/overrides/xpack.ml.get_calendars.json b/x-pack/plugins/console_extensions/spec/overrides/ml.get_calendars.json
similarity index 72%
rename from x-pack/plugins/console_extensions/spec/overrides/xpack.ml.get_calendars.json
rename to x-pack/plugins/console_extensions/spec/overrides/ml.get_calendars.json
index 146965574723e..fd961624b8afc 100644
--- a/x-pack/plugins/console_extensions/spec/overrides/xpack.ml.get_calendars.json
+++ b/x-pack/plugins/console_extensions/spec/overrides/ml.get_calendars.json
@@ -1,5 +1,5 @@
{
- "xpack.ml.get_calendars": {
+ "ml.get_calendars": {
"data_autocomplete_rules": {
"from": 0,
"size": 100
diff --git a/x-pack/plugins/console_extensions/spec/overrides/ml.get_categories.json b/x-pack/plugins/console_extensions/spec/overrides/ml.get_categories.json
new file mode 100644
index 0000000000000..c32fb482ee4e4
--- /dev/null
+++ b/x-pack/plugins/console_extensions/spec/overrides/ml.get_categories.json
@@ -0,0 +1,14 @@
+{
+ "ml.get_categories": {
+ "data_autocomplete_rules": {
+ "page": {
+ "__template": {
+ "from": 0,
+ "size": 100
+ },
+ "from": 0,
+ "size": 100
+ }
+ }
+ }
+}
diff --git a/x-pack/plugins/console_extensions/spec/overrides/xpack.ml.get_influencers.json b/x-pack/plugins/console_extensions/spec/overrides/ml.get_influencers.json
similarity index 90%
rename from x-pack/plugins/console_extensions/spec/overrides/xpack.ml.get_influencers.json
rename to x-pack/plugins/console_extensions/spec/overrides/ml.get_influencers.json
index df1bc1487dd6b..4f31b3db1007c 100644
--- a/x-pack/plugins/console_extensions/spec/overrides/xpack.ml.get_influencers.json
+++ b/x-pack/plugins/console_extensions/spec/overrides/ml.get_influencers.json
@@ -1,5 +1,5 @@
{
- "xpack.ml.get_influencers": {
+ "ml.get_influencers": {
"data_autocomplete_rules": {
"desc": { "__one_of": ["true", "false"] },
"exclude_interim": { "__one_of": ["true", "false"] },
diff --git a/x-pack/plugins/console_extensions/spec/overrides/xpack.ml.get_model_snapshots.json b/x-pack/plugins/console_extensions/spec/overrides/ml.get_model_snapshots.json
similarity index 82%
rename from x-pack/plugins/console_extensions/spec/overrides/xpack.ml.get_model_snapshots.json
rename to x-pack/plugins/console_extensions/spec/overrides/ml.get_model_snapshots.json
index 1496851f0c7d9..02a86d39509f8 100644
--- a/x-pack/plugins/console_extensions/spec/overrides/xpack.ml.get_model_snapshots.json
+++ b/x-pack/plugins/console_extensions/spec/overrides/ml.get_model_snapshots.json
@@ -1,5 +1,5 @@
{
- "xpack.ml.get_model_snapshots": {
+ "ml.get_model_snapshots": {
"data_autocomplete_rules": {
"desc": [true, false],
"end": "",
diff --git a/x-pack/plugins/console_extensions/spec/overrides/xpack.ml.get_overall_buckets.json b/x-pack/plugins/console_extensions/spec/overrides/ml.get_overall_buckets.json
similarity index 88%
rename from x-pack/plugins/console_extensions/spec/overrides/xpack.ml.get_overall_buckets.json
rename to x-pack/plugins/console_extensions/spec/overrides/ml.get_overall_buckets.json
index cb41f5ef78aaa..312c44419ba90 100644
--- a/x-pack/plugins/console_extensions/spec/overrides/xpack.ml.get_overall_buckets.json
+++ b/x-pack/plugins/console_extensions/spec/overrides/ml.get_overall_buckets.json
@@ -1,5 +1,5 @@
{
- "xpack.ml.get_overall_buckets": {
+ "ml.get_overall_buckets": {
"data_autocomplete_rules": {
"allow_no_jobs": { "__one_of": ["true", "false"] },
"bucket_span": "",
diff --git a/x-pack/plugins/console_extensions/spec/overrides/xpack.ml.get_records.json b/x-pack/plugins/console_extensions/spec/overrides/ml.get_records.json
similarity index 91%
rename from x-pack/plugins/console_extensions/spec/overrides/xpack.ml.get_records.json
rename to x-pack/plugins/console_extensions/spec/overrides/ml.get_records.json
index 16691960696b5..d68dabaeac367 100644
--- a/x-pack/plugins/console_extensions/spec/overrides/xpack.ml.get_records.json
+++ b/x-pack/plugins/console_extensions/spec/overrides/ml.get_records.json
@@ -1,5 +1,5 @@
{
- "xpack.ml.get_records": {
+ "ml.get_records": {
"data_autocomplete_rules": {
"desc": { "__one_of": ["true", "false"] },
"exclude_interim": { "__one_of": ["true", "false"] },
diff --git a/x-pack/plugins/console_extensions/spec/overrides/xpack.ml.post_calendar_events.json b/x-pack/plugins/console_extensions/spec/overrides/ml.post_calendar_events.json
similarity index 64%
rename from x-pack/plugins/console_extensions/spec/overrides/xpack.ml.post_calendar_events.json
rename to x-pack/plugins/console_extensions/spec/overrides/ml.post_calendar_events.json
index 05e3e3697df3c..543a2758ff03a 100644
--- a/x-pack/plugins/console_extensions/spec/overrides/xpack.ml.post_calendar_events.json
+++ b/x-pack/plugins/console_extensions/spec/overrides/ml.post_calendar_events.json
@@ -1,5 +1,5 @@
{
- "xpack.ml.post_calendar_events": {
+ "ml.post_calendar_events": {
"data_autocomplete_rules": {
"events": [{}]
}
diff --git a/x-pack/plugins/console_extensions/spec/overrides/xpack.ml.put_calendar.json b/x-pack/plugins/console_extensions/spec/overrides/ml.put_calendar.json
similarity index 71%
rename from x-pack/plugins/console_extensions/spec/overrides/xpack.ml.put_calendar.json
rename to x-pack/plugins/console_extensions/spec/overrides/ml.put_calendar.json
index d0ca83a2fd2af..9bfddb49f84c6 100644
--- a/x-pack/plugins/console_extensions/spec/overrides/xpack.ml.put_calendar.json
+++ b/x-pack/plugins/console_extensions/spec/overrides/ml.put_calendar.json
@@ -1,5 +1,5 @@
{
- "xpack.ml.put_calendar": {
+ "ml.put_calendar": {
"data_autocomplete_rules": {
"description": ""
}
diff --git a/x-pack/plugins/console_extensions/spec/overrides/xpack.ml.put_datafeed.json b/x-pack/plugins/console_extensions/spec/overrides/ml.put_datafeed.json
similarity index 90%
rename from x-pack/plugins/console_extensions/spec/overrides/xpack.ml.put_datafeed.json
rename to x-pack/plugins/console_extensions/spec/overrides/ml.put_datafeed.json
index a3b50af4db036..bb42e485a621e 100644
--- a/x-pack/plugins/console_extensions/spec/overrides/xpack.ml.put_datafeed.json
+++ b/x-pack/plugins/console_extensions/spec/overrides/ml.put_datafeed.json
@@ -1,5 +1,5 @@
{
- "xpack.ml.put_datafeed": {
+ "ml.put_datafeed": {
"data_autocomplete_rules": {
"aggregations": {},
"chunking_config": {},
diff --git a/x-pack/plugins/console_extensions/spec/overrides/xpack.ml.put_job.json b/x-pack/plugins/console_extensions/spec/overrides/ml.put_job.json
similarity index 94%
rename from x-pack/plugins/console_extensions/spec/overrides/xpack.ml.put_job.json
rename to x-pack/plugins/console_extensions/spec/overrides/ml.put_job.json
index aee010691b964..ec62d7646aefc 100644
--- a/x-pack/plugins/console_extensions/spec/overrides/xpack.ml.put_job.json
+++ b/x-pack/plugins/console_extensions/spec/overrides/ml.put_job.json
@@ -1,5 +1,5 @@
{
- "xpack.ml.put_job": {
+ "ml.put_job": {
"data_autocomplete_rules": {
"analysis_config": {},
"background_persist_interval": "",
diff --git a/x-pack/plugins/console_extensions/spec/overrides/xpack.ml.revert_model_snapshot.json b/x-pack/plugins/console_extensions/spec/overrides/ml.revert_model_snapshot.json
similarity index 75%
rename from x-pack/plugins/console_extensions/spec/overrides/xpack.ml.revert_model_snapshot.json
rename to x-pack/plugins/console_extensions/spec/overrides/ml.revert_model_snapshot.json
index 806b326271bad..00f69cd0893f2 100644
--- a/x-pack/plugins/console_extensions/spec/overrides/xpack.ml.revert_model_snapshot.json
+++ b/x-pack/plugins/console_extensions/spec/overrides/ml.revert_model_snapshot.json
@@ -1,5 +1,5 @@
{
- "xpack.ml.revert_model_snapshot": {
+ "ml.revert_model_snapshot": {
"data_autocomplete_rules": {
"delete_intervening_results": { "__one_of": ["true", "false"] }
}
diff --git a/x-pack/plugins/console_extensions/spec/overrides/xpack.ml.update_datafeed.json b/x-pack/plugins/console_extensions/spec/overrides/ml.update_datafeed.json
similarity index 89%
rename from x-pack/plugins/console_extensions/spec/overrides/xpack.ml.update_datafeed.json
rename to x-pack/plugins/console_extensions/spec/overrides/ml.update_datafeed.json
index f096707690eea..13616b23dbbbf 100644
--- a/x-pack/plugins/console_extensions/spec/overrides/xpack.ml.update_datafeed.json
+++ b/x-pack/plugins/console_extensions/spec/overrides/ml.update_datafeed.json
@@ -1,5 +1,5 @@
{
- "xpack.ml.update_datafeed": {
+ "ml.update_datafeed": {
"data_autocomplete_rules": {
"aggregations": {},
"chunking_config": {},
diff --git a/x-pack/plugins/console_extensions/spec/overrides/xpack.ml.update_job.json b/x-pack/plugins/console_extensions/spec/overrides/ml.update_job.json
similarity index 93%
rename from x-pack/plugins/console_extensions/spec/overrides/xpack.ml.update_job.json
rename to x-pack/plugins/console_extensions/spec/overrides/ml.update_job.json
index 562fdef07c790..b95259c017a67 100644
--- a/x-pack/plugins/console_extensions/spec/overrides/xpack.ml.update_job.json
+++ b/x-pack/plugins/console_extensions/spec/overrides/ml.update_job.json
@@ -1,5 +1,5 @@
{
- "xpack.ml.update_job": {
+ "ml.update_job": {
"data_autocomplete_rules": {
"analysis_limits": {},
"background_persist_interval": "",
diff --git a/x-pack/plugins/console_extensions/spec/overrides/xpack.ml.update_model_snapshot.json b/x-pack/plugins/console_extensions/spec/overrides/ml.update_model_snapshot.json
similarity index 72%
rename from x-pack/plugins/console_extensions/spec/overrides/xpack.ml.update_model_snapshot.json
rename to x-pack/plugins/console_extensions/spec/overrides/ml.update_model_snapshot.json
index bbf98c6ac05e7..c5cb3e0e90a63 100644
--- a/x-pack/plugins/console_extensions/spec/overrides/xpack.ml.update_model_snapshot.json
+++ b/x-pack/plugins/console_extensions/spec/overrides/ml.update_model_snapshot.json
@@ -1,5 +1,5 @@
{
- "xpack.ml.update_model_snapshot": {
+ "ml.update_model_snapshot": {
"data_autocomplete_rules": {
"description": "",
"retain": [true, false]
diff --git a/x-pack/plugins/console_extensions/spec/overrides/xpack.ml.get_categories.json b/x-pack/plugins/console_extensions/spec/overrides/xpack.ml.get_categories.json
deleted file mode 100644
index b3a46b02edefc..0000000000000
--- a/x-pack/plugins/console_extensions/spec/overrides/xpack.ml.get_categories.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "xpack.ml.get_categories": {
- "data_autocomplete_rules": {
- "page": {
- "__template": {
- "from": 0,
- "size": 100
- },
- "from": 0,
- "size": 100
- }
- },
- "patterns": [
- "_xpack/ml/anomaly_detectors/{job_id}/results/categories/{category_id}",
- "_xpack/ml/anomaly_detectors/{job_id}/results/categories"
- ]
- }
-}
diff --git a/x-pack/plugins/console_extensions/spec/overrides/xpack.rollup.get_jobs.json b/x-pack/plugins/console_extensions/spec/overrides/xpack.rollup.get_jobs.json
deleted file mode 100644
index 06a89d35819f8..0000000000000
--- a/x-pack/plugins/console_extensions/spec/overrides/xpack.rollup.get_jobs.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
- "xpack.rollup.get_jobs": {
- "patterns": [
- "_xpack/rollup/job/{id}"
- ]
- }
-}
diff --git a/x-pack/plugins/cross_cluster_replication/public/extend_index_management/index.js b/x-pack/plugins/cross_cluster_replication/public/extend_index_management/index.js
index 4ee2e8908b708..3c7aa90b4073d 100644
--- a/x-pack/plugins/cross_cluster_replication/public/extend_index_management/index.js
+++ b/x-pack/plugins/cross_cluster_replication/public/extend_index_management/index.js
@@ -17,7 +17,8 @@ export const followerBadgeExtension = {
label: i18n.translate('xpack.crossClusterReplication.indexMgmtBadge.followerLabel', {
defaultMessage: 'Follower',
}),
- color: 'default'
+ color: 'default',
+ filterExpression: 'isFollowerIndex:true'
};
addBadgeExtension(followerBadgeExtension);
diff --git a/x-pack/plugins/gis/common/constants.js b/x-pack/plugins/gis/common/constants.js
index e76ce51bb37df..2e8fb14c2e875 100644
--- a/x-pack/plugins/gis/common/constants.js
+++ b/x-pack/plugins/gis/common/constants.js
@@ -9,3 +9,5 @@ export const GIS_API_PATH = 'api/gis';
export const DECIMAL_DEGREES_PRECISION = 5; // meters precision
export const ZOOM_PRECISION = 2;
+
+export const DEFAULT_EMS_TILE_LAYER = 'road_map';
diff --git a/x-pack/plugins/gis/public/_main.scss b/x-pack/plugins/gis/public/_main.scss
index 5e8b75daad1c6..f7794072b8e74 100644
--- a/x-pack/plugins/gis/public/_main.scss
+++ b/x-pack/plugins/gis/public/_main.scss
@@ -8,12 +8,6 @@
overflow: hidden;
}
-@include euiBreakpoint('xs') {
- #gis-plugin {
- height: calc(100vh - #{$euiHeaderChildSizeMobile});
- }
-}
-
#react-gis-root {
flex-grow: 1;
display: flex;
diff --git a/x-pack/plugins/gis/public/actions/store_actions.js b/x-pack/plugins/gis/public/actions/store_actions.js
index c7a2571695393..8c8d8c71f06ff 100644
--- a/x-pack/plugins/gis/public/actions/store_actions.js
+++ b/x-pack/plugins/gis/public/actions/store_actions.js
@@ -16,7 +16,6 @@ import {
getMapReady,
getWaitingForMapReadyLayerListRaw,
} from '../selectors/map_selectors';
-import { timeService } from '../kibana_services';
export const SET_SELECTED_LAYER = 'SET_SELECTED_LAYER';
export const UPDATE_LAYER_ORDER = 'UPDATE_LAYER_ORDER';
@@ -35,7 +34,6 @@ export const LAYER_DATA_LOAD_STARTED = 'LAYER_DATA_LOAD_STARTED';
export const LAYER_DATA_LOAD_ENDED = 'LAYER_DATA_LOAD_ENDED';
export const LAYER_DATA_LOAD_ERROR = 'LAYER_DATA_LOAD_ERROR';
export const SET_JOINS = 'SET_JOINS';
-export const SET_TIME_FILTERS = 'SET_TIME_FILTERS';
export const SET_QUERY = 'SET_QUERY';
export const TRIGGER_REFRESH_TIMER = 'TRIGGER_REFRESH_TIMER';
export const UPDATE_LAYER_PROP = 'UPDATE_LAYER_PROP';
@@ -418,43 +416,17 @@ export function removeLayer(id) {
}
export function setMeta(metaJson) {
- return async dispatch => {
- dispatch({
- type: SET_META,
- meta: metaJson
- });
- };
-}
-
-export function setTimeFiltersToKbnGlobalTime() {
- return (dispatch) => {
- dispatch(setTimeFilters(timeService.getTime()));
- };
-}
-
-export function setTimeFilters({ from, to }) {
- return async (dispatch, getState) => {
- dispatch({
- type: SET_TIME_FILTERS,
- from,
- to,
- });
-
- // Update Kibana global time
- const kbnTime = timeService.getTime();
- if ((to && to !== kbnTime.to) || (from && from !== kbnTime.from)) {
- timeService.setTime({ from, to });
- }
-
- const dataFilters = getDataFilters(getState());
- await syncDataForAllLayers(getState, dispatch, dataFilters);
+ return {
+ type: SET_META,
+ meta: metaJson
};
}
-export function setQuery({ query }) {
+export function setQuery({ query, timeFilters }) {
return async (dispatch, getState) => {
dispatch({
type: SET_QUERY,
+ timeFilters,
query: {
...query,
// ensure query changes to trigger re-fetch even when query is the same because "Refresh" clicked
@@ -468,21 +440,10 @@ export function setQuery({ query }) {
}
export function setRefreshConfig({ isPaused, interval }) {
- return async (dispatch) => {
- dispatch({
- type: SET_REFRESH_CONFIG,
- isPaused,
- interval,
- });
-
- // Update Kibana global refresh
- const kbnRefresh = timeService.getRefreshInterval();
- if (isPaused !== kbnRefresh.pause || interval !== kbnRefresh.value) {
- timeService.setRefreshInterval({
- pause: isPaused,
- value: interval,
- });
- }
+ return {
+ type: SET_REFRESH_CONFIG,
+ isPaused,
+ interval,
};
}
diff --git a/x-pack/plugins/gis/public/angular/get_initial_layers.js b/x-pack/plugins/gis/public/angular/get_initial_layers.js
index 385114d29eef6..a7cc6e77fa317 100644
--- a/x-pack/plugins/gis/public/angular/get_initial_layers.js
+++ b/x-pack/plugins/gis/public/angular/get_initial_layers.js
@@ -6,12 +6,25 @@
import _ from 'lodash';
import { KibanaTilemapSource } from '../shared/layers/sources/kibana_tilemap_source';
import { EMSTMSSource } from '../shared/layers/sources/ems_tms_source';
+import { isMetaDataLoaded, getDataSourcesSync } from '../meta';
+import { DEFAULT_EMS_TILE_LAYER } from '../../common/constants';
+
+export function getInitialLayers(savedMapLayerListJSON) {
-export function getInitialLayers(savedMapLayerListJSON, dataSources) {
if (savedMapLayerListJSON) {
return JSON.parse(savedMapLayerListJSON);
}
+ if (!isMetaDataLoaded()) {
+ const descriptor = EMSTMSSource.createDescriptor(DEFAULT_EMS_TILE_LAYER);
+ const source = new EMSTMSSource(descriptor);
+ const layer = source.createDefaultLayer();
+ return [
+ layer.toLayerDescriptor()
+ ];
+ }
+
+ const dataSources = getDataSourcesSync();
const kibanaTilemapUrl = _.get(dataSources, 'kibana.tilemap.url');
if (kibanaTilemapUrl) {
const sourceDescriptor = KibanaTilemapSource.createDescriptor(kibanaTilemapUrl);
@@ -32,7 +45,5 @@ export function getInitialLayers(savedMapLayerListJSON, dataSources) {
];
}
- // TODO display (or throw) warning that no tile layers are available and map.tilemap needs to be configured
- // because EMS is unreachable or has been turned off on purpose.
return [];
}
diff --git a/x-pack/plugins/gis/public/angular/get_initial_layers.test.js b/x-pack/plugins/gis/public/angular/get_initial_layers.test.js
index 47f610d8cf8db..9554dc54bda00 100644
--- a/x-pack/plugins/gis/public/angular/get_initial_layers.test.js
+++ b/x-pack/plugins/gis/public/angular/get_initial_layers.test.js
@@ -4,6 +4,10 @@
* you may not use this file except in compliance with the Elastic License.
*/
+jest.mock('../meta', () => {
+ return {};
+});
+
import { getInitialLayers } from './get_initial_layers';
const mockKibanaDataSource = {
@@ -28,22 +32,65 @@ describe('Saved object has layer list', () => {
}
];
const layerListJSON = JSON.stringify(layerListFromSavedObject);
- const dataSources = {
- kibana: mockKibanaDataSource,
- ems: mockEmsDataSource
- };
- expect(getInitialLayers(layerListJSON, dataSources)).toEqual(layerListFromSavedObject);
+ expect((getInitialLayers(layerListJSON))).toEqual(layerListFromSavedObject);
});
});
+
+
describe('Saved object does not have layer list', () => {
+
+ beforeEach(() => {
+ require('../meta').isMetaDataLoaded = () => {
+ return true;
+ };
+ });
+
+ function mockDataSourceResponse(dataSources) {
+ require('../meta').getDataSourcesSync = () => {
+ return dataSources;
+ };
+ require('../meta').isMetaDataLoaded = () => {
+ return true;
+ };
+ }
+
+ it('should get the default EMS layer when metadata has not loaded yet', () => {
+ mockDataSourceResponse();
+ require('../meta').isMetaDataLoaded = () => {
+ return false;
+ };
+ const layers = getInitialLayers(null);
+ expect(layers).toEqual([{
+ "alpha": 1,
+ "dataRequests": [],
+ "id": layers[0].id,
+ "label": null,
+ "maxZoom": 24,
+ "minZoom": 0,
+ "sourceDescriptor": {
+ "type": "EMS_TMS",
+ "id": "road_map",
+ },
+ "style": {
+ "properties": {},
+ "type": "TILE",
+ },
+ "temporary": false,
+ "type": "TILE",
+ "visible": true,
+ }]);
+ });
+
+
it('Should get initial layer from Kibana tilemap data source when Kibana tilemap is configured ', () => {
- const dataSources = {
+
+ mockDataSourceResponse({
kibana: mockKibanaDataSource,
ems: mockEmsDataSource
- };
+ });
- const layers = getInitialLayers(null, dataSources);
+ const layers = getInitialLayers(null);
expect(layers).toEqual([{
"alpha": 1,
dataRequests: [],
@@ -70,8 +117,9 @@ describe('Saved object does not have layer list', () => {
const dataSources = {
ems: mockEmsDataSource
};
+ mockDataSourceResponse(dataSources);
- const layers = getInitialLayers(null, dataSources);
+ const layers = getInitialLayers(null);
expect(layers).toEqual([{
"alpha": 1,
dataRequests: [],
@@ -100,10 +148,12 @@ describe('Saved object does not have layer list', () => {
tms: []
}
};
- expect(getInitialLayers(null, dataSources)).toEqual([]);
+ mockDataSourceResponse(dataSources);
+ expect((getInitialLayers(null))).toEqual([]);
});
it('Should return empty list when no dataSoures are provided', () => {
- expect(getInitialLayers(null, null)).toEqual([]);
+ mockDataSourceResponse(null);
+ expect((getInitialLayers(null))).toEqual([]);
});
});
diff --git a/x-pack/plugins/gis/public/angular/get_initial_query.js b/x-pack/plugins/gis/public/angular/get_initial_query.js
new file mode 100644
index 0000000000000..e30e7e4ad9f58
--- /dev/null
+++ b/x-pack/plugins/gis/public/angular/get_initial_query.js
@@ -0,0 +1,32 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import chrome from 'ui/chrome';
+
+const settings = chrome.getUiSettingsClient();
+
+export function getInitialQuery({
+ mapStateJSON,
+ appState = {},
+ userQueryLanguage,
+}) {
+
+ if (appState.query) {
+ return appState.query;
+ }
+
+ if (mapStateJSON) {
+ const mapState = JSON.parse(mapStateJSON);
+ if (mapState.query) {
+ return mapState.query;
+ }
+ }
+
+ return {
+ query: '',
+ language: userQueryLanguage || settings.get('search:queryLanguage')
+ };
+}
diff --git a/x-pack/plugins/gis/public/angular/get_initial_refresh_config.js b/x-pack/plugins/gis/public/angular/get_initial_refresh_config.js
new file mode 100644
index 0000000000000..5d042028c1ef8
--- /dev/null
+++ b/x-pack/plugins/gis/public/angular/get_initial_refresh_config.js
@@ -0,0 +1,28 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+import chrome from 'ui/chrome';
+
+const uiSettings = chrome.getUiSettingsClient();
+
+export function getInitialRefreshConfig({
+ mapStateJSON,
+ globalState = {},
+}) {
+
+ if (mapStateJSON) {
+ const mapState = JSON.parse(mapStateJSON);
+ if (mapState.refreshConfig) {
+ return mapState.refreshConfig;
+ }
+ }
+
+ const defaultRefreshConfig = uiSettings.get('timepicker:refreshIntervalDefaults');
+ const refreshInterval = { ...defaultRefreshConfig, ...globalState.refreshInterval };
+ return {
+ isPaused: refreshInterval.pause,
+ interval: refreshInterval.value,
+ };
+}
diff --git a/x-pack/plugins/gis/public/angular/get_initial_time_filters.js b/x-pack/plugins/gis/public/angular/get_initial_time_filters.js
new file mode 100644
index 0000000000000..8ce57e0d0991b
--- /dev/null
+++ b/x-pack/plugins/gis/public/angular/get_initial_time_filters.js
@@ -0,0 +1,24 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+import chrome from 'ui/chrome';
+
+const uiSettings = chrome.getUiSettingsClient();
+
+export function getInitialTimeFilters({
+ mapStateJSON,
+ globalState = {},
+}) {
+
+ if (mapStateJSON) {
+ const mapState = JSON.parse(mapStateJSON);
+ if (mapState.timeFilters) {
+ return mapState.timeFilters;
+ }
+ }
+
+ const defaultTime = uiSettings.get('timepicker:timeDefaults');
+ return { ...defaultTime, ...globalState.time };
+}
diff --git a/x-pack/plugins/gis/public/angular/map.html b/x-pack/plugins/gis/public/angular/map.html
index 34f953f0525ea..8bffe59548dcd 100644
--- a/x-pack/plugins/gis/public/angular/map.html
+++ b/x-pack/plugins/gis/public/angular/map.html
@@ -27,6 +27,12 @@
app-name="'maps'"
on-submit="updateQueryAndDispatch"
index-patterns="indexPatterns"
+ show-date-picker="showDatePicker"
+ date-range-from="time.from"
+ date-range-to="time.to"
+ is-refresh-paused="refreshConfig.isPaused"
+ refresh-interval="refreshConfig.interval"
+ on-refresh-change="onRefreshChange"
>
diff --git a/x-pack/plugins/gis/public/angular/map_controller.js b/x-pack/plugins/gis/public/angular/map_controller.js
index 6faae6a414e21..d9d6d12e8933e 100644
--- a/x-pack/plugins/gis/public/angular/map_controller.js
+++ b/x-pack/plugins/gis/public/angular/map_controller.js
@@ -14,54 +14,108 @@ import { getStore } from '../store/store';
import { GisMap } from '../components/gis_map';
import {
setSelectedLayer,
- setTimeFilters,
setRefreshConfig,
setGotoWithCenter,
replaceLayerList,
setQuery,
} from '../actions/store_actions';
import { updateFlyout, FLYOUT_STATE } from '../store/ui';
-import { getDataSources, getUniqueIndexPatternIds } from '../selectors/map_selectors';
+import { getUniqueIndexPatternIds } from '../selectors/map_selectors';
import { Inspector } from 'ui/inspector';
import { inspectorAdapters, indexPatternService } from '../kibana_services';
import { SavedObjectSaveModal } from 'ui/saved_objects/components/saved_object_save_modal';
import { showSaveModal } from 'ui/saved_objects/show_saved_object_save_modal';
import { toastNotifications } from 'ui/notify';
import { getInitialLayers } from './get_initial_layers';
+import { getInitialQuery } from './get_initial_query';
+import { getInitialTimeFilters } from './get_initial_time_filters';
+import { getInitialRefreshConfig } from './get_initial_refresh_config';
const REACT_ANCHOR_DOM_ELEMENT_ID = 'react-gis-root';
-const DEFAULT_QUERY_LANGUAGE = 'kuery';
+
const app = uiModules.get('app/gis', []);
-app.controller('GisMapController', ($scope, $route, config, kbnUrl, localStorage, AppState) => {
+app.controller('GisMapController', ($scope, $route, config, kbnUrl, localStorage, AppState, globalState) => {
const savedMap = $scope.map = $route.current.locals.map;
let unsubscribe;
inspectorAdapters.requests.reset();
+ $scope.$listen(globalState, 'fetch_with_changes', (diff) => {
+ if (diff.includes('time')) {
+ $scope.updateQueryAndDispatch({ query: $scope.query, dateRange: globalState.time });
+ }
+ if (diff.includes('refreshInterval')) {
+ $scope.onRefreshChange({ isPaused: globalState.pause, refreshInterval: globalState.value });
+ }
+ });
+
const $state = new AppState();
$scope.$listen($state, 'fetch_with_changes', function (diff) {
if (diff.includes('query')) {
- $scope.updateQueryAndDispatch($state.query);
+ $scope.updateQueryAndDispatch({ query: $state.query, dateRange: $scope.time });
}
});
- $scope.query = {};
+
+ function syncAppAndGlobalState() {
+ $scope.$evalAsync(() => {
+ $state.query = $scope.query;
+ $state.save();
+ globalState.time = $scope.time;
+ globalState.refreshInterval = {
+ pause: $scope.refreshConfig.isPaused,
+ value: $scope.refreshConfig.interval,
+ };
+ globalState.save();
+ });
+ }
+
+ $scope.query = getInitialQuery({
+ mapStateJSON: savedMap.mapStateJSON,
+ appState: $state,
+ userQueryLanguage: localStorage.get('kibana.userQueryLanguage')
+ });
+ $scope.time = getInitialTimeFilters({
+ mapStateJSON: savedMap.mapStateJSON,
+ globalState: globalState,
+ });
+ $scope.refreshConfig = getInitialRefreshConfig({
+ mapStateJSON: savedMap.mapStateJSON,
+ globalState: globalState,
+ });
+ syncAppAndGlobalState();
+
$scope.indexPatterns = [];
- $scope.updateQueryAndDispatch = function (newQuery) {
- $scope.query = newQuery;
+ $scope.updateQueryAndDispatch = function ({ dateRange, query }) {
+ $scope.query = query;
+ $scope.time = dateRange;
getStore().then(store => {
// ignore outdated query
- if ($scope.query !== newQuery) {
+ if ($scope.query !== query && $scope.time !== dateRange) {
return;
}
- store.dispatch(setQuery({ query: $scope.query }));
+ store.dispatch(setQuery({ query: $scope.query, timeFilters: $scope.time }));
- // update appState
- $state.query = $scope.query;
- $state.save();
+ syncAppAndGlobalState();
+ });
+ };
+ $scope.onRefreshChange = function ({ isPaused, refreshInterval }) {
+ $scope.refreshConfig = {
+ isPaused,
+ interval: refreshInterval ? refreshInterval : $scope.refreshConfig.interval
+ };
+ getStore().then(store => {
+ // ignore outdated
+ if ($scope.refreshConfig.isPaused !== isPaused && $scope.refreshConfig.interval !== refreshInterval) {
+ return;
+ }
+
+ store.dispatch(setRefreshConfig($scope.refreshConfig));
+
+ syncAppAndGlobalState();
});
};
@@ -76,36 +130,20 @@ app.controller('GisMapController', ($scope, $route, config, kbnUrl, localStorage
});
// sync store with savedMap mapState
- let queryFromSavedObject;
if (savedMap.mapStateJSON) {
const mapState = JSON.parse(savedMap.mapStateJSON);
- queryFromSavedObject = mapState.query;
- const timeFilters = mapState.timeFilters ? mapState.timeFilters : timefilter.getTime();
- store.dispatch(setTimeFilters(timeFilters));
store.dispatch(setGotoWithCenter({
lat: mapState.center.lat,
lon: mapState.center.lon,
zoom: mapState.zoom,
}));
- if (mapState.refreshConfig) {
- store.dispatch(setRefreshConfig(mapState.refreshConfig));
- }
}
- const layerList = getInitialLayers(savedMap.layerListJSON, getDataSources(store.getState()));
+ const layerList = getInitialLayers(savedMap.layerListJSON);
store.dispatch(replaceLayerList(layerList));
- // Initialize query, syncing appState and store
- if ($state.query) {
- $scope.updateQueryAndDispatch($state.query);
- } else if (queryFromSavedObject) {
- $scope.updateQueryAndDispatch(queryFromSavedObject);
- } else {
- $scope.updateQueryAndDispatch({
- query: '',
- language: localStorage.get('kibana.userQueryLanguage') || DEFAULT_QUERY_LANGUAGE
- });
- }
+ store.dispatch(setRefreshConfig($scope.refreshConfig));
+ store.dispatch(setQuery({ query: $scope.query, timeFilters: $scope.time }));
const root = document.getElementById(REACT_ANCHOR_DOM_ELEMENT_ID);
render(
@@ -136,9 +174,7 @@ app.controller('GisMapController', ($scope, $route, config, kbnUrl, localStorage
}
function handleStoreChanges(store) {
- const state = store.getState();
-
- const nextIndexPatternIds = getUniqueIndexPatternIds(state);
+ const nextIndexPatternIds = getUniqueIndexPatternIds(store.getState());
if (nextIndexPatternIds !== prevIndexPatternIds) {
prevIndexPatternIds = nextIndexPatternIds;
updateIndexPatterns(nextIndexPatternIds);
@@ -197,6 +233,10 @@ app.controller('GisMapController', ($scope, $route, config, kbnUrl, localStorage
return { id };
}
+ // Hide angular timepicer/refresh UI from top nav
+ timefilter.disableTimeRangeSelector();
+ timefilter.disableAutoRefreshSelector();
+ $scope.showDatePicker = true; // used by query-bar directive to enable timepikcer in query bar
$scope.topNavMenu = [{
key: 'inspect',
description: 'Open Inspector',
@@ -238,6 +278,4 @@ app.controller('GisMapController', ($scope, $route, config, kbnUrl, localStorage
showSaveModal(saveModal);
}
}];
- timefilter.enableTimeRangeSelector();
- timefilter.enableAutoRefreshSelector();
});
diff --git a/x-pack/plugins/gis/public/components/gis_map/index.js b/x-pack/plugins/gis/public/components/gis_map/index.js
index b0e31b7e2f470..cff886a1ff123 100644
--- a/x-pack/plugins/gis/public/components/gis_map/index.js
+++ b/x-pack/plugins/gis/public/components/gis_map/index.js
@@ -7,26 +7,22 @@
import { connect } from 'react-redux';
import { GisMap } from './view';
import { getFlyoutDisplay, FLYOUT_STATE } from '../../store/ui';
-import {
- setTimeFiltersToKbnGlobalTime,
- triggerRefreshTimer,
- setRefreshConfig
-} from '../../actions/store_actions';
+import { triggerRefreshTimer } from '../../actions/store_actions';
+import { getRefreshConfig } from '../../selectors/map_selectors';
function mapStateToProps(state = {}) {
const flyoutDisplay = getFlyoutDisplay(state);
return {
layerDetailsVisible: flyoutDisplay === FLYOUT_STATE.LAYER_PANEL,
addLayerVisible: flyoutDisplay === FLYOUT_STATE.ADD_LAYER_WIZARD,
- noFlyoutVisible: flyoutDisplay === FLYOUT_STATE.NONE
+ noFlyoutVisible: flyoutDisplay === FLYOUT_STATE.NONE,
+ refreshConfig: getRefreshConfig(state),
};
}
function mapDispatchToProps(dispatch) {
return {
- setTimeFiltersToKbnGlobalTime: () => dispatch(setTimeFiltersToKbnGlobalTime()),
triggerRefreshTimer: () => dispatch(triggerRefreshTimer()),
- setRefreshConfig: (({ isPaused, interval }) => dispatch(setRefreshConfig({ isPaused, interval }))),
};
}
diff --git a/x-pack/plugins/gis/public/components/gis_map/view.js b/x-pack/plugins/gis/public/components/gis_map/view.js
index d3a08630e970c..2abad91c4b974 100644
--- a/x-pack/plugins/gis/public/components/gis_map/view.js
+++ b/x-pack/plugins/gis/public/components/gis_map/view.js
@@ -12,39 +12,41 @@ import { AddLayerPanel } from '../layer_addpanel/index';
import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
import { Toasts } from '../toasts';
-import { timeService } from '../../kibana_services';
-
export class GisMap extends Component {
componentDidMount() {
- timeService.on('timeUpdate', this.props.setTimeFiltersToKbnGlobalTime);
- timeService.on('refreshIntervalUpdate', this.setRefreshTimer);
+ this.setRefreshTimer();
+ }
+
+ componentDidUpdate() {
this.setRefreshTimer();
}
componentWillUnmount() {
- timeService.off('timeUpdate', this.props.setTimeFiltersToKbnGlobalTime);
- timeService.off('refreshIntervalUpdate', this.setRefreshTimer);
this.clearRefreshTimer();
}
setRefreshTimer = () => {
+ const { isPaused, interval } = this.props.refreshConfig;
+
+ if (this.isPaused === isPaused && this.interval === interval) {
+ // refreshConfig is the same, nothing to do
+ return;
+ }
+
+ this.isPaused = isPaused;
+ this.interval = interval;
+
this.clearRefreshTimer();
- const { value, pause } = timeService.getRefreshInterval();
- if (!pause && value > 0) {
+ if (!isPaused && interval > 0) {
this.refreshTimerId = setInterval(
() => {
this.props.triggerRefreshTimer();
},
- value
+ interval
);
}
-
- this.props.setRefreshConfig({
- isPaused: pause,
- interval: value,
- });
}
clearRefreshTimer = () => {
diff --git a/x-pack/plugins/gis/public/components/layer_addpanel/index.js b/x-pack/plugins/gis/public/components/layer_addpanel/index.js
index 525843f3481f9..aa45eacf5b43f 100644
--- a/x-pack/plugins/gis/public/components/layer_addpanel/index.js
+++ b/x-pack/plugins/gis/public/components/layer_addpanel/index.js
@@ -8,7 +8,7 @@ import { connect } from 'react-redux';
import { AddLayerPanel } from './view';
import { getFlyoutDisplay, updateFlyout, FLYOUT_STATE }
from '../../store/ui';
-import { getTemporaryLayers, getDataSources } from "../../selectors/map_selectors";
+import { getTemporaryLayers } from "../../selectors/map_selectors";
import {
addLayer,
removeLayer,
@@ -19,14 +19,12 @@ import _ from 'lodash';
function mapStateToProps(state = {}) {
- const dataSourceMeta = getDataSources(state);
function isLoading() {
const tmp = getTemporaryLayers(state);
return tmp.some((layer) => layer.isLayerLoading());
}
return {
flyoutVisible: getFlyoutDisplay(state) !== FLYOUT_STATE.NONE,
- dataSourcesMeta: dataSourceMeta,
layerLoading: isLoading(),
temporaryLayers: !_.isEmpty(getTemporaryLayers(state))
};
diff --git a/x-pack/plugins/gis/public/components/layer_addpanel/view.js b/x-pack/plugins/gis/public/components/layer_addpanel/view.js
index 2149610054034..f92194c9ce593 100644
--- a/x-pack/plugins/gis/public/components/layer_addpanel/view.js
+++ b/x-pack/plugins/gis/public/components/layer_addpanel/view.js
@@ -108,8 +108,7 @@ export class AddLayerPanel extends Component {
_renderSourceEditor() {
const editorProperties = {
- onPreviewSource: this._previewLayer,
- dataSourcesMeta: this.props.dataSourcesMeta
+ onPreviewSource: this._previewLayer
};
const Source = ALL_SOURCES.find((Source) => {
diff --git a/x-pack/plugins/gis/public/meta.js b/x-pack/plugins/gis/public/meta.js
new file mode 100644
index 0000000000000..40c0f03c2a79a
--- /dev/null
+++ b/x-pack/plugins/gis/public/meta.js
@@ -0,0 +1,60 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+
+import { GIS_API_PATH } from '../common/constants';
+import _ from 'lodash';
+
+const GIS_API_RELATIVE = `../${GIS_API_PATH}`;
+
+let meta = null;
+let isLoaded = false;
+export async function getDataSources() {
+ if (!meta) {
+ meta = new Promise(async (resolve, reject) => {
+ try {
+ const meta = await fetch(`${GIS_API_RELATIVE}/meta`);
+ const metaJson = await meta.json();
+ isLoaded = true;
+ resolve(metaJson.data_sources);
+ } catch(e) {
+ reject(e);
+ }
+ });
+ }
+ return meta;
+}
+
+export function getDataSourcesSync() {
+ if (!isLoaded) {
+ throw new Error('Metadata is not loaded yet. Use isMetadataLoaded first before calling this function.');
+ }
+ return meta;
+}
+
+export function isMetaDataLoaded() {
+ return isLoaded;
+}
+
+export async function getEmsVectorFilesMeta() {
+ const dataSource = await getDataSources();
+ return _.get(dataSource, 'ems.file', []);
+}
+
+export async function getEmsTMSServices() {
+ const dataSource = await getDataSources();
+ return _.get(dataSource, 'ems.tms', []);
+}
+
+export async function getKibanaRegionList() {
+ const dataSource = await getDataSources();
+ return _.get(dataSource, 'kibana.regionmap', []);
+}
+
+export async function getKibanaTileMap() {
+ const dataSource = await getDataSources();
+ return _.get(dataSource, 'kibana.tilemap', []);
+}
diff --git a/x-pack/plugins/gis/public/selectors/map_selectors.js b/x-pack/plugins/gis/public/selectors/map_selectors.js
index 6935d7b66fb83..f3274d0e8826f 100644
--- a/x-pack/plugins/gis/public/selectors/map_selectors.js
+++ b/x-pack/plugins/gis/public/selectors/map_selectors.js
@@ -15,8 +15,8 @@ import { HeatmapStyle } from '../shared/layers/styles/heatmap_style';
import { TileStyle } from '../shared/layers/styles/tile_style';
import { timefilter } from 'ui/timefilter';
-function createLayerInstance(layerDescriptor, dataSources) {
- const source = createSourceInstance(layerDescriptor.sourceDescriptor, dataSources);
+function createLayerInstance(layerDescriptor) {
+ const source = createSourceInstance(layerDescriptor.sourceDescriptor);
const style = createStyleInstance(layerDescriptor.style);
switch (layerDescriptor.type) {
case TileLayer.type:
@@ -30,21 +30,14 @@ function createLayerInstance(layerDescriptor, dataSources) {
}
}
-function createSourceInstance(sourceDescriptor, dataSources) {
-
- const dataMeta = {
- emsTmsServices: _.get(dataSources, 'ems.tms', []),
- emsFileLayers: _.get(dataSources, 'ems.file', []),
- ymlFileLayers: _.get(dataSources, 'kibana.regionmap', [])
- };
-
+function createSourceInstance(sourceDescriptor) {
const Source = ALL_SOURCES.find(Source => {
return Source.type === sourceDescriptor.type;
});
if (!Source) {
throw new Error(`Unrecognized sourceType ${sourceDescriptor.type}`);
}
- return new Source(sourceDescriptor, dataMeta);
+ return new Source(sourceDescriptor);
}
@@ -66,8 +59,6 @@ function createStyleInstance(styleDescriptor) {
}
}
-export const getMapState = ({ map }) => map && map.mapState;
-
export const getMapReady = ({ map }) => map && map.ready;
export const getGoto = ({ map }) => map && map.goto;
@@ -137,14 +128,12 @@ export const getDataFilters = createSelector(
}
);
-export const getDataSources = createSelector(getMetadata, metadata => metadata ? metadata.data_sources : null);
export const getLayerList = createSelector(
getLayerListRaw,
- getDataSources,
- (layerDescriptorList, dataSources) => {
+ (layerDescriptorList) => {
return layerDescriptorList.map(layerDescriptor =>
- createLayerInstance(layerDescriptor, dataSources));
+ createLayerInstance(layerDescriptor));
});
export const getSelectedLayer = createSelector(
diff --git a/x-pack/plugins/gis/public/shared/layers/sources/ems_file_source/create_source_editor.js b/x-pack/plugins/gis/public/shared/layers/sources/ems_file_source/create_source_editor.js
new file mode 100644
index 0000000000000..53f253017536e
--- /dev/null
+++ b/x-pack/plugins/gis/public/shared/layers/sources/ems_file_source/create_source_editor.js
@@ -0,0 +1,64 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+
+import React from 'react';
+import {
+ EuiSelect,
+ EuiFormRow,
+} from '@elastic/eui';
+
+import { getEmsVectorFilesMeta } from '../../../../meta';
+
+
+export class EMSFileCreateSourceEditor extends React.Component {
+
+
+ state = {
+ emsFileOptionsRaw: null
+ };
+
+ _loadFileOptions = async () => {
+ const options = await getEmsVectorFilesMeta();
+ if (this._isMounted) {
+ this.setState({
+ emsFileOptionsRaw: options
+ });
+ }
+ }
+
+ componentWillUnmount() {
+ this._isMounted = false;
+ }
+
+ componentDidMount() {
+ this._isMounted = true;
+ this._loadFileOptions();
+ }
+
+ render() {
+
+ if (!this.state.emsFileOptionsRaw) {
+ return null;
+ }
+
+ const emsVectorOptions = this.state.emsFileOptionsRaw ? this.state.emsFileOptionsRaw.map((file) => ({
+ value: file.id,
+ text: file.name
+ })) : [];
+
+
+ return (
+
+
+
+ );
+ }
+}
diff --git a/x-pack/plugins/gis/public/shared/layers/sources/ems_file_source.js b/x-pack/plugins/gis/public/shared/layers/sources/ems_file_source/ems_file_source.js
similarity index 59%
rename from x-pack/plugins/gis/public/shared/layers/sources/ems_file_source.js
rename to x-pack/plugins/gis/public/shared/layers/sources/ems_file_source/ems_file_source.js
index 85dd5e6dc156b..b4f16817bf630 100644
--- a/x-pack/plugins/gis/public/shared/layers/sources/ems_file_source.js
+++ b/x-pack/plugins/gis/public/shared/layers/sources/ems_file_source/ems_file_source.js
@@ -4,15 +4,12 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import { AbstractVectorSource } from './vector_source';
+import { AbstractVectorSource } from '../vector_source';
import React from 'react';
-import {
- EuiSelect,
- EuiFormRow,
-} from '@elastic/eui';
-
-import { GIS_API_PATH } from '../../../../common/constants';
-import { emsServiceSettings } from '../../../kibana_services';
+import { GIS_API_PATH } from '../../../../../common/constants';
+import { emsServiceSettings } from '../../../../kibana_services';
+import { getEmsVectorFilesMeta } from '../../../../meta';
+import { EMSFileCreateSourceEditor } from './create_source_editor';
export class EMSFileSource extends AbstractVectorSource {
@@ -28,38 +25,23 @@ export class EMSFileSource extends AbstractVectorSource {
};
}
- static renderEditor({ dataSourcesMeta, onPreviewSource }) {
-
- const emsVectorOptionsRaw = (dataSourcesMeta) ? dataSourcesMeta.ems.file : [];
- const emsVectorOptions = emsVectorOptionsRaw ? emsVectorOptionsRaw.map((file) => ({
- value: file.id,
- text: file.name
- })) : [];
-
+ static renderEditor({ onPreviewSource }) {
const onChange = ({ target }) => {
const selectedId = target.options[target.selectedIndex].value;
const emsFileSourceDescriptor = EMSFileSource.createDescriptor(selectedId);
- const emsFileSource = new EMSFileSource(emsFileSourceDescriptor, emsVectorOptionsRaw);
+ const emsFileSource = new EMSFileSource(emsFileSourceDescriptor);
onPreviewSource(emsFileSource);
};
- return (
-
-
-
- );
+ return ;
}
- constructor(descriptor, { emsFileLayers }) {
+ constructor(descriptor) {
super(descriptor);
- this._emsFiles = emsFileLayers;
}
async getGeoJsonWithMeta() {
- const fileSource = this._emsFiles.find((source => source.id === this._descriptor.id));
+ const emsFiles = await getEmsVectorFilesMeta();
+ const fileSource = emsFiles.find((source => source.id === this._descriptor.id));
const fetchUrl = `../${GIS_API_PATH}/data/ems?id=${encodeURIComponent(this._descriptor.id)}`;
const featureCollection = await AbstractVectorSource.getGeoJson(fileSource, fetchUrl);
return {
@@ -77,24 +59,24 @@ export class EMSFileSource extends AbstractVectorSource {
}
async getDisplayName() {
- const fileSource = this._emsFiles.find((source => source.id === this._descriptor.id));
+ const emsFiles = await getEmsVectorFilesMeta();
+ const fileSource = emsFiles.find((source => source.id === this._descriptor.id));
return fileSource.name;
}
async getAttributions() {
- const fileSource = this._emsFiles.find((source => source.id === this._descriptor.id));
+ const emsFiles = await getEmsVectorFilesMeta();
+ const fileSource = emsFiles.find((source => source.id === this._descriptor.id));
return fileSource.attributions;
}
async getStringFields() {
- //todo: use map/service-settings instead.
- const fileSource = this._emsFiles.find((source => source.id === this._descriptor.id));
-
+ const emsFiles = await getEmsVectorFilesMeta();
+ const fileSource = emsFiles.find((source => source.id === this._descriptor.id));
return fileSource.fields.map(f => {
return { name: f.name, label: f.description };
});
-
}
canFormatFeatureProperties() {
diff --git a/x-pack/plugins/canvas/public/components/file_upload/index.js b/x-pack/plugins/gis/public/shared/layers/sources/ems_file_source/index.js
similarity index 82%
rename from x-pack/plugins/canvas/public/components/file_upload/index.js
rename to x-pack/plugins/gis/public/shared/layers/sources/ems_file_source/index.js
index 68c0f6150521b..9d0e503eb08ba 100644
--- a/x-pack/plugins/canvas/public/components/file_upload/index.js
+++ b/x-pack/plugins/gis/public/shared/layers/sources/ems_file_source/index.js
@@ -4,4 +4,4 @@
* you may not use this file except in compliance with the Elastic License.
*/
-export { FileUpload } from './file_upload';
+export { EMSFileSource } from './ems_file_source';
diff --git a/x-pack/plugins/gis/public/shared/layers/sources/ems_tms_source/create_source_editor.js b/x-pack/plugins/gis/public/shared/layers/sources/ems_tms_source/create_source_editor.js
new file mode 100644
index 0000000000000..443a8d5170835
--- /dev/null
+++ b/x-pack/plugins/gis/public/shared/layers/sources/ems_tms_source/create_source_editor.js
@@ -0,0 +1,64 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+
+import React from 'react';
+import {
+ EuiSelect,
+ EuiFormRow,
+} from '@elastic/eui';
+
+import { getEmsTMSServices } from '../../../../meta';
+
+
+export class EMSTMSCreateSourceEditor extends React.Component {
+
+
+ state = {
+ emsTmsOptionsRaw: null
+ };
+
+ _loadTmsOptions = async () => {
+ const options = await getEmsTMSServices();
+ if (this._isMounted) {
+ this.setState({
+ emsTmsOptionsRaw: options
+ });
+ }
+ }
+
+ componentWillUnmount() {
+ this._isMounted = false;
+ }
+
+ componentDidMount() {
+ this._isMounted = true;
+ this._loadTmsOptions();
+ }
+
+ render() {
+
+ if (!this.state.emsTmsOptionsRaw) {
+ return null;
+ }
+
+ const emsTileOptions = this.state.emsTmsOptionsRaw.map((service) => ({
+ value: service.id,
+ text: service.id //due to not having human readable names
+ }));
+
+
+ return (
+
+
+
+ );
+ }
+}
diff --git a/x-pack/plugins/gis/public/shared/layers/sources/ems_tms_source/ems_tms_source.js b/x-pack/plugins/gis/public/shared/layers/sources/ems_tms_source/ems_tms_source.js
index 129f00ee6a541..b4b0e529f214a 100644
--- a/x-pack/plugins/gis/public/shared/layers/sources/ems_tms_source/ems_tms_source.js
+++ b/x-pack/plugins/gis/public/shared/layers/sources/ems_tms_source/ems_tms_source.js
@@ -6,11 +6,9 @@
import React from 'react';
import { AbstractTMSSource } from '../tms_source';
import { TileLayer } from '../../tile_layer';
-import {
- EuiSelect,
- EuiFormRow,
-} from '@elastic/eui';
-import _ from 'lodash';
+
+import { getEmsTMSServices } from '../../../../meta';
+import { EMSTMSCreateSourceEditor } from './create_source_editor';
export class EMSTMSSource extends AbstractTMSSource {
@@ -27,34 +25,20 @@ export class EMSTMSSource extends AbstractTMSSource {
};
}
- static renderEditor({ dataSourcesMeta, onPreviewSource }) {
-
- const emsTmsOptionsRaw = _.get(dataSourcesMeta, "ems.tms", []);
- const emsTileOptions = emsTmsOptionsRaw.map((service) => ({
- value: service.id,
- text: service.id //due to not having human readable names
- }));
+ static renderEditor({ onPreviewSource }) {
const onChange = ({ target }) => {
const selectedId = target.options[target.selectedIndex].value;
const emsTMSSourceDescriptor = EMSTMSSource.createDescriptor(selectedId);
- const emsTMSSource = new EMSTMSSource(emsTMSSourceDescriptor, emsTmsOptionsRaw);
+ const emsTMSSource = new EMSTMSSource(emsTMSSourceDescriptor);
onPreviewSource(emsTMSSource);
};
- return (
-
-
-
- );
+
+ return ;
}
- constructor(descriptor, { emsTmsServices }) {
+ constructor(descriptor) {
super(descriptor);
- this._emsTileServices = emsTmsServices;
}
async getImmutableProperties() {
@@ -64,12 +48,13 @@ export class EMSTMSSource extends AbstractTMSSource {
];
}
- _getTMSOptions() {
- if(!this._emsTileServices) {
+ async _getTMSOptions() {
+ const emsTileServices = await getEmsTMSServices();
+ if(!emsTileServices) {
return;
}
- return this._emsTileServices.find(service => {
+ return emsTileServices.find(service => {
return service.id === this._descriptor.id;
});
}
@@ -93,7 +78,7 @@ export class EMSTMSSource extends AbstractTMSSource {
}
async getAttributions() {
- const service = this._getTMSOptions();
+ const service = await this._getTMSOptions();
if (!service || !service.attributionMarkdown) {
return [];
}
@@ -110,10 +95,10 @@ export class EMSTMSSource extends AbstractTMSSource {
});
}
- getUrlTemplate() {
- const service = this._getTMSOptions();
+ async getUrlTemplate() {
+ const service = await this._getTMSOptions();
if (!service || !service.url) {
- throw new Error('Can not generate EMS TMS url template');
+ throw new Error('Cannot generate EMS TMS url template');
}
return service.url;
}
diff --git a/x-pack/plugins/gis/public/shared/layers/sources/ems_tms_source/ems_tms_source.test.js b/x-pack/plugins/gis/public/shared/layers/sources/ems_tms_source/ems_tms_source.test.js
index 1d5d54be06a98..1f29dbb7d1e6f 100644
--- a/x-pack/plugins/gis/public/shared/layers/sources/ems_tms_source/ems_tms_source.test.js
+++ b/x-pack/plugins/gis/public/shared/layers/sources/ems_tms_source/ems_tms_source.test.js
@@ -4,6 +4,21 @@
* you may not use this file except in compliance with the Elastic License.
*/
+jest.mock('../../../../meta', () => {
+ return {
+ getEmsTMSServices: async () => {
+ return [
+ {
+ id: 'road_map',
+ attributionMarkdown: '[foobar](http://foobar.org) | [foobaz](http://foobaz.org)'
+ }, {
+ id: 'satellite',
+ attributionMarkdown: '[satellite](http://satellite.org)'
+ }
+ ];
+ }
+ };
+});
import {
EMSTMSSource,
@@ -15,21 +30,10 @@ describe('EMSTMSSource', () => {
const emsTmsSource = new EMSTMSSource({
id: 'road_map'
- }, {
- emsTmsServices: [
- {
- id: 'road_map',
- attributionMarkdown: '[foobar](http://foobar.org) | [foobaz](http://foobaz.org)'
- }, {
- id: 'satellite',
- attributionMarkdown: '[satellite](http://satellite.org)'
- }
- ]
});
const attributions = await emsTmsSource.getAttributions();
-
expect(attributions).toEqual([
{
label: 'foobar',
diff --git a/x-pack/plugins/gis/public/shared/layers/sources/kibana_regionmap_source/create_source_editor.js b/x-pack/plugins/gis/public/shared/layers/sources/kibana_regionmap_source/create_source_editor.js
index 3c8aceb8e8f3b..c740df0129ad6 100644
--- a/x-pack/plugins/gis/public/shared/layers/sources/kibana_regionmap_source/create_source_editor.js
+++ b/x-pack/plugins/gis/public/shared/layers/sources/kibana_regionmap_source/create_source_editor.js
@@ -10,48 +10,70 @@ import {
EuiSelect,
EuiFormRow,
} from '@elastic/eui';
+import { getKibanaRegionList } from '../../../../meta';
const NO_REGIONMAP_LAYERS_MSG =
'No vector layers are available.' +
' Ask your system administrator to set "map.regionmap" in kibana.yml.';
-export function CreateSourceEditor({ onSelect, regionmapLayers }) {
+export class CreateSourceEditor extends React.Component {
- const regionmapOptions = regionmapLayers.map(({ name, url }) => {
- return {
- value: url,
- text: name
- };
- });
+ state = {
+ regionmapLayers: []
+ }
- const onChange = ({ target }) => {
- const selectedName = target.options[target.selectedIndex].text;
- onSelect({ name: selectedName });
+ _loadList = async () => {
+ const list = await getKibanaRegionList();
+ if (this._isMounted) {
+ this.setState({
+ regionmapLayers: list
+ });
+ }
};
- return (
-
-
-
- );
+ componentWillUnmount() {
+ this._isMounted = false;
+ }
+
+ componentDidMount() {
+ this._isMounted = true;
+ this._loadList();
+ }
+
+ render() {
+
+
+
+ const onChange = ({ target }) => {
+ const selectedName = target.options[target.selectedIndex].text;
+ this.props.onSelect({ name: selectedName });
+ };
+
+ const regionmapOptions = this.state.regionmapLayers.map(({ name, url }) => {
+ return {
+ value: url,
+ text: name
+ };
+ });
+
+ return (
+
+
+
+ );
+ }
}
CreateSourceEditor.propTypes = {
- onSelect: PropTypes.func.isRequired,
- regionmapLayers: PropTypes.arrayOf(PropTypes.shape({
- url: PropTypes.string.isRequired,
- name: PropTypes.string.isRequired,
- })),
+ onSelect: PropTypes.func.isRequired
};
-CreateSourceEditor.defaultProps = {
- regionmapLayers: [],
-};
+
diff --git a/x-pack/plugins/gis/public/shared/layers/sources/kibana_regionmap_source/kibana_regionmap_source.js b/x-pack/plugins/gis/public/shared/layers/sources/kibana_regionmap_source/kibana_regionmap_source.js
index cbdc31c516a37..9e02ec3bfb190 100644
--- a/x-pack/plugins/gis/public/shared/layers/sources/kibana_regionmap_source/kibana_regionmap_source.js
+++ b/x-pack/plugins/gis/public/shared/layers/sources/kibana_regionmap_source/kibana_regionmap_source.js
@@ -4,11 +4,12 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import _ from 'lodash';
import { AbstractVectorSource } from '../vector_source';
import React from 'react';
import { CreateSourceEditor } from './create_source_editor';
+import { getKibanaRegionList } from '../../../../meta';
+
export class KibanaRegionmapSource extends AbstractVectorSource {
static type = 'REGIONMAP_FILE';
@@ -16,9 +17,8 @@ export class KibanaRegionmapSource extends AbstractVectorSource {
static description = 'Vector shapes from static files configured in kibana.yml';
static icon = 'logoKibana';
- constructor(descriptor, { ymlFileLayers }) {
+ constructor(descriptor) {
super(descriptor);
- this._regionList = ymlFileLayers;
}
static createDescriptor(options) {
@@ -28,19 +28,16 @@ export class KibanaRegionmapSource extends AbstractVectorSource {
};
}
- static renderEditor = ({ dataSourcesMeta, onPreviewSource }) => {
- const regionmapLayers = _.get(dataSourcesMeta, 'kibana.regionmap', []);
-
+ static renderEditor = ({ onPreviewSource }) => {
const onSelect = (layerConfig) => {
const sourceDescriptor = KibanaRegionmapSource.createDescriptor(layerConfig);
- const source = new KibanaRegionmapSource(sourceDescriptor, { ymlFileLayers: regionmapLayers });
+ const source = new KibanaRegionmapSource(sourceDescriptor);
onPreviewSource(source);
};
return (
);
};
@@ -53,7 +50,8 @@ export class KibanaRegionmapSource extends AbstractVectorSource {
}
async getGeoJsonWithMeta() {
- const fileSource = this._regionList.find(source => source.name === this._descriptor.name);
+ const regionList = await getKibanaRegionList();
+ const fileSource = regionList.find(source => source.name === this._descriptor.name);
const featureCollection = await AbstractVectorSource.getGeoJson(fileSource, fileSource.url);
return {
data: featureCollection
@@ -61,8 +59,8 @@ export class KibanaRegionmapSource extends AbstractVectorSource {
}
async getStringFields() {
- //todo: use map/service-settings instead.
- const fileSource = this._regionList.find((source => source.name === this._descriptor.name));
+ const regionList = await getKibanaRegionList();
+ const fileSource = regionList.find((source => source.name === this._descriptor.name));
return fileSource.fields.map(f => {
return { name: f.name, label: f.description };
diff --git a/x-pack/plugins/gis/public/shared/layers/sources/kibana_tilemap_source/create_source_editor.js b/x-pack/plugins/gis/public/shared/layers/sources/kibana_tilemap_source/create_source_editor.js
index 777767858fa0a..b20ccc1314f24 100644
--- a/x-pack/plugins/gis/public/shared/layers/sources/kibana_tilemap_source/create_source_editor.js
+++ b/x-pack/plugins/gis/public/shared/layers/sources/kibana_tilemap_source/create_source_editor.js
@@ -11,27 +11,54 @@ import {
EuiFormRow,
} from '@elastic/eui';
+import { getKibanaTileMap } from '../../../../meta';
+
const NO_TILEMAP_LAYER_MSG =
'No tilemap layer is available.' +
' Ask your system administrator to set "map.tilemap.url" in kibana.yml.';
+
+
export class CreateSourceEditor extends Component {
- componentDidMount() {
- if (this.props.url) {
+
+ state = {
+ url: null
+ }
+
+ _loadUrl = async () => {
+ const tilemap = await getKibanaTileMap();
+ if (this._isMounted) {
+ this.setState({
+ url: tilemap.url
+ });
this.props.previewTilemap(this.props.url);
}
}
+ componentWillUnmount() {
+ this._isMounted = false;
+ }
+
+ componentDidMount() {
+ this._isMounted = true;
+ this._loadUrl();
+ }
+
render() {
+
+ if (this.state.url === null) {
+ return null;
+ }
+
return (
);
@@ -39,6 +66,5 @@ export class CreateSourceEditor extends Component {
}
CreateSourceEditor.propTypes = {
- previewTilemap: PropTypes.func.isRequired,
- url: PropTypes.string,
+ previewTilemap: PropTypes.func.isRequired
};
diff --git a/x-pack/plugins/gis/public/shared/layers/sources/kibana_tilemap_source/kibana_tilemap_source.js b/x-pack/plugins/gis/public/shared/layers/sources/kibana_tilemap_source/kibana_tilemap_source.js
index a14b8d90fc976..a847aa32535c2 100644
--- a/x-pack/plugins/gis/public/shared/layers/sources/kibana_tilemap_source/kibana_tilemap_source.js
+++ b/x-pack/plugins/gis/public/shared/layers/sources/kibana_tilemap_source/kibana_tilemap_source.js
@@ -7,7 +7,6 @@ import React from 'react';
import { AbstractTMSSource } from '../tms_source';
import { TileLayer } from '../../tile_layer';
import { CreateSourceEditor } from './create_source_editor';
-
export class KibanaTilemapSource extends AbstractTMSSource {
static type = 'KIBANA_TILEMAP';
@@ -22,20 +21,19 @@ export class KibanaTilemapSource extends AbstractTMSSource {
};
}
- static renderEditor = ({ dataSourcesMeta, onPreviewSource }) => {
- const { url } = dataSourcesMeta ? dataSourcesMeta.kibana.tilemap : {};
+ static renderEditor = ({ onPreviewSource }) => {
const previewTilemap = (urlTemplate) => {
const sourceDescriptor = KibanaTilemapSource.createDescriptor(urlTemplate);
const source = new KibanaTilemapSource(sourceDescriptor);
onPreviewSource(source);
};
- return ();
+ return ();
};
async getImmutableProperties() {
return [
{ label: 'Data source', value: KibanaTilemapSource.title },
- { label: 'Tilemap url', value: this.getUrlTemplate() },
+ { label: 'Tilemap url', value: (await this.getUrlTemplate()) },
];
}
@@ -54,11 +52,11 @@ export class KibanaTilemapSource extends AbstractTMSSource {
}
- getUrlTemplate() {
+ async getUrlTemplate() {
return this._descriptor.url;
}
async getDisplayName() {
- return this.getUrlTemplate();
+ return await this.getUrlTemplate();
}
}
diff --git a/x-pack/plugins/gis/public/shared/layers/sources/tms_source.js b/x-pack/plugins/gis/public/shared/layers/sources/tms_source.js
index 852dffd1ef5f2..53a920a1393c1 100644
--- a/x-pack/plugins/gis/public/shared/layers/sources/tms_source.js
+++ b/x-pack/plugins/gis/public/shared/layers/sources/tms_source.js
@@ -8,7 +8,7 @@
import { AbstractSource } from './source';
export class AbstractTMSSource extends AbstractSource {
- getUrlTemplate() {
+ async getUrlTemplate() {
throw new Error('Should implement TMSSource#getUrlTemplate');
}
}
diff --git a/x-pack/plugins/gis/public/shared/layers/tile_layer.js b/x-pack/plugins/gis/public/shared/layers/tile_layer.js
index 75e42d8123025..99fd312c6fd86 100644
--- a/x-pack/plugins/gis/public/shared/layers/tile_layer.js
+++ b/x-pack/plugins/gis/public/shared/layers/tile_layer.js
@@ -64,15 +64,38 @@ export class TileLayer extends AbstractLayer {
});
}
+ async syncData({ startLoading, stopLoading, onLoadError, dataFilters }) {
+ if (!this.isVisible() || !this.showAtZoomLevel(dataFilters.zoom)) {
+ return;
+ }
+ const sourceDataId = 'source';
+ const requestToken = Symbol(`layer-source-refresh:${ this.getId()} - source`);
+ startLoading(sourceDataId, requestToken, dataFilters);
+ try {
+ const url = await this._source.getUrlTemplate();
+ stopLoading(sourceDataId, requestToken, url, {});
+ } catch(error) {
+ onLoadError(sourceDataId, requestToken, error.message);
+ }
+ }
+
async syncLayerWithMB(mbMap) {
+
const source = mbMap.getSource(this.getId());
- const layerId = this.getId() + '_raster';
+ const mbLayerId = this.getId() + '_raster';
if (source) {
+ // If source exists, just sync style
+ this._setTileLayerProperties(mbMap, mbLayerId);
+ return;
+ }
+
+ const sourceDataRquest = this.getSourceDataRequest();
+ const url = sourceDataRquest.getData();
+ if (!url) {
return;
}
- const url = this._source.getUrlTemplate();
const sourceId = this.getId();
mbMap.addSource(sourceId, {
type: 'raster',
@@ -82,7 +105,7 @@ export class TileLayer extends AbstractLayer {
});
mbMap.addLayer({
- id: layerId,
+ id: mbLayerId,
type: 'raster',
source: sourceId,
minzoom: 0,
@@ -90,13 +113,16 @@ export class TileLayer extends AbstractLayer {
});
await this._tileLoadErrorTracker(mbMap, url);
+ this._setTileLayerProperties(mbMap, mbLayerId);
+ }
- mbMap.setLayoutProperty(layerId, 'visibility', this.isVisible() ? 'visible' : 'none');
- mbMap.setLayerZoomRange(layerId, this._descriptor.minZoom, this._descriptor.maxZoom);
+ _setTileLayerProperties(mbMap, mbLayerId) {
+ mbMap.setLayoutProperty(mbLayerId, 'visibility', this.isVisible() ? 'visible' : 'none');
+ mbMap.setLayerZoomRange(mbLayerId, this._descriptor.minZoom, this._descriptor.maxZoom);
this._style && this._style.setMBPaintProperties({
alpha: this.getAlpha(),
mbMap,
- layerId,
+ mbLayerId,
});
}
diff --git a/x-pack/plugins/gis/public/store/config.js b/x-pack/plugins/gis/public/store/config.js
deleted file mode 100644
index 09eb91cdcac8e..0000000000000
--- a/x-pack/plugins/gis/public/store/config.js
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License;
- * you may not use this file except in compliance with the Elastic License.
- */
-import { SET_META } from '../actions/store_actions';
-
-const INITIAL_STATE = {
- meta: null
-};
-
-// Reducer
-function config(state = INITIAL_STATE, action) {
- switch (action.type) {
- case SET_META:
- return { ...state, meta: action.meta };
- default:
- return state;
- }
-}
-
-export default config;
diff --git a/x-pack/plugins/gis/public/store/map.js b/x-pack/plugins/gis/public/store/map.js
index 3aa6146486b39..9b5c48a20fe9b 100644
--- a/x-pack/plugins/gis/public/store/map.js
+++ b/x-pack/plugins/gis/public/store/map.js
@@ -20,7 +20,6 @@ import {
MAP_EXTENT_CHANGED,
MAP_READY,
MAP_DESTROYED,
- SET_TIME_FILTERS,
SET_QUERY,
UPDATE_LAYER_PROP,
UPDATE_LAYER_STYLE_FOR_SELECTED_LAYER,
@@ -163,12 +162,16 @@ export function map(state = INITIAL_STATE, action) {
buffer: action.mapState.buffer,
};
return { ...state, mapState: { ...state.mapState, ...newMapState } };
- case SET_TIME_FILTERS:
- const { from, to } = action;
- return { ...state, mapState: { ...state.mapState, timeFilters: { from, to } } };
case SET_QUERY:
- const { query } = action;
- return { ...state, mapState: { ...state.mapState, query } };
+ const { query, timeFilters } = action;
+ return {
+ ...state,
+ mapState: {
+ ...state.mapState,
+ query,
+ timeFilters,
+ }
+ };
case SET_REFRESH_CONFIG:
const { isPaused, interval } = action;
return {
diff --git a/x-pack/plugins/gis/public/store/store.js b/x-pack/plugins/gis/public/store/store.js
index 2bad2f6cb7063..22b964ee301cf 100644
--- a/x-pack/plugins/gis/public/store/store.js
+++ b/x-pack/plugins/gis/public/store/store.js
@@ -8,16 +8,13 @@ import { combineReducers, applyMiddleware, createStore, compose } from 'redux';
import thunk from 'redux-thunk';
import ui from './ui';
import { map } from './map';
-import { loadMetaResources } from "../actions/store_actions";
-import config from './config';
// TODO this should not be exported and all access to the store be via getStore
export let store;
const rootReducer = combineReducers({
map,
- ui,
- config
+ ui
});
const enhancers = [ applyMiddleware(thunk) ];
@@ -36,6 +33,5 @@ export const getStore = async function () {
storeConfig,
composeEnhancers(...enhancers)
);
- await loadMetaResources(store.dispatch);
return store;
};
diff --git a/x-pack/plugins/graph/index.js b/x-pack/plugins/graph/index.js
index 83134f20d4f82..39dbc148772ec 100644
--- a/x-pack/plugins/graph/index.js
+++ b/x-pack/plugins/graph/index.js
@@ -7,6 +7,7 @@
import { resolve } from 'path';
import Boom from 'boom';
+import migrations from './migrations';
import { initServer } from './server';
import mappings from './mappings.json';
@@ -28,7 +29,8 @@ export function graph(kibana) {
styleSheetPaths: resolve(__dirname, 'public/index.scss'),
hacks: ['plugins/graph/hacks/toggle_app_link_in_nav'],
home: ['plugins/graph/register_feature'],
- mappings
+ mappings,
+ migrations,
},
config(Joi) {
diff --git a/x-pack/plugins/graph/migrations.js b/x-pack/plugins/graph/migrations.js
new file mode 100644
index 0000000000000..d454de49f2b00
--- /dev/null
+++ b/x-pack/plugins/graph/migrations.js
@@ -0,0 +1,41 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import { get } from 'lodash';
+
+export default {
+ 'graph-workspace': {
+ '7.0.0': (doc) => {
+ // Set new "references" attribute
+ doc.references = doc.references || [];
+ // Migrate index pattern
+ const wsState = get(doc, 'attributes.wsState');
+ if (typeof wsState !== 'string') {
+ return doc;
+ }
+ let state;
+ try {
+ state = JSON.parse(JSON.parse(wsState));
+ } catch (e) {
+ // Let it go, the data is invalid and we'll leave it as is
+ return doc;
+ }
+ const { indexPattern } = state;
+ if (!indexPattern) {
+ return doc;
+ }
+ state.indexPatternRefName = 'indexPattern_0';
+ delete state.indexPattern;
+ doc.attributes.wsState = JSON.stringify(JSON.stringify(state));
+ doc.references.push({
+ name: 'indexPattern_0',
+ type: 'index-pattern',
+ id: indexPattern,
+ });
+ return doc;
+ }
+ }
+};
diff --git a/x-pack/plugins/graph/migrations.test.js b/x-pack/plugins/graph/migrations.test.js
new file mode 100644
index 0000000000000..93162d94857ce
--- /dev/null
+++ b/x-pack/plugins/graph/migrations.test.js
@@ -0,0 +1,102 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import migrations from './migrations';
+
+describe('graph-workspace', () => {
+ describe('7.0.0', () => {
+ const migration = migrations['graph-workspace']['7.0.0'];
+
+ test('returns doc on empty object', () => {
+ expect(migration({})).toMatchInlineSnapshot(`
+Object {
+ "references": Array [],
+}
+`);
+ });
+
+ test('returns doc when wsState is not a string', () => {
+ const doc = {
+ id: '1',
+ attributes: {
+ wsState: true,
+ },
+ };
+ expect(migration(doc)).toMatchInlineSnapshot(`
+Object {
+ "attributes": Object {
+ "wsState": true,
+ },
+ "id": "1",
+ "references": Array [],
+}
+`);
+ });
+
+ test('returns doc when wsState is not valid JSON', () => {
+ const doc = {
+ id: '1',
+ attributes: {
+ wsState: '123abc',
+ },
+ };
+ expect(migration(doc)).toMatchInlineSnapshot(`
+Object {
+ "attributes": Object {
+ "wsState": "123abc",
+ },
+ "id": "1",
+ "references": Array [],
+}
+`);
+ });
+
+ test('returns doc when "indexPattern" is missing from wsState', () => {
+ const doc = {
+ id: '1',
+ attributes: {
+ wsState: JSON.stringify(JSON.stringify({ foo: true })),
+ },
+ };
+ expect(migration(doc)).toMatchInlineSnapshot(`
+Object {
+ "attributes": Object {
+ "wsState": "\\"{\\\\\\"foo\\\\\\":true}\\"",
+ },
+ "id": "1",
+ "references": Array [],
+}
+`);
+ });
+
+ test('extract "indexPattern" attribute from doc', () => {
+ const doc = {
+ id: '1',
+ attributes: {
+ wsState: JSON.stringify(JSON.stringify({ foo: true, indexPattern: 'pattern*' })),
+ bar: true,
+ },
+ };
+ const migratedDoc = migration(doc);
+ expect(migratedDoc).toMatchInlineSnapshot(`
+Object {
+ "attributes": Object {
+ "bar": true,
+ "wsState": "\\"{\\\\\\"foo\\\\\\":true,\\\\\\"indexPatternRefName\\\\\\":\\\\\\"indexPattern_0\\\\\\"}\\"",
+ },
+ "id": "1",
+ "references": Array [
+ Object {
+ "id": "pattern*",
+ "name": "indexPattern_0",
+ "type": "index-pattern",
+ },
+ ],
+}
+`);
+ });
+ });
+});
diff --git a/x-pack/plugins/graph/public/services/saved_workspace.js b/x-pack/plugins/graph/public/services/saved_workspace.js
index eb0c0e1dd936a..f25743900dab8 100644
--- a/x-pack/plugins/graph/public/services/saved_workspace.js
+++ b/x-pack/plugins/graph/public/services/saved_workspace.js
@@ -7,6 +7,10 @@
import { uiModules } from 'ui/modules';
import { SavedObjectProvider } from 'ui/courier';
import { i18n } from '@kbn/i18n';
+import {
+ extractReferences,
+ injectReferences,
+} from './saved_workspace_references';
const module = uiModules.get('app/dashboard');
@@ -21,6 +25,8 @@ export function SavedWorkspaceProvider(Private) {
type: SavedWorkspace.type,
mapping: SavedWorkspace.mapping,
searchSource: SavedWorkspace.searchsource,
+ extractReferences: extractReferences,
+ injectReferences: injectReferences,
// if this is null/undefined then the SavedObject will be assigned the defaults
id: id,
diff --git a/x-pack/plugins/graph/public/services/saved_workspace_references.js b/x-pack/plugins/graph/public/services/saved_workspace_references.js
new file mode 100644
index 0000000000000..a1b4254685c40
--- /dev/null
+++ b/x-pack/plugins/graph/public/services/saved_workspace_references.js
@@ -0,0 +1,53 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+export function extractReferences({ attributes, references = [] }) {
+ // For some reason, wsState comes in stringified 2x
+ const state = JSON.parse(JSON.parse(attributes.wsState));
+ const { indexPattern } = state;
+ if (!indexPattern) {
+ throw new Error('indexPattern attribute is missing in "wsState"');
+ }
+ state.indexPatternRefName = 'indexPattern_0';
+ delete state.indexPattern;
+ return {
+ references: [
+ ...references,
+ {
+ name: 'indexPattern_0',
+ type: 'index-pattern',
+ id: indexPattern,
+ }
+ ],
+ attributes: {
+ ...attributes,
+ wsState: JSON.stringify(JSON.stringify(state)),
+ },
+ };
+}
+
+export function injectReferences(savedObject, references) {
+ // Skip if wsState is missing, at the time of development of this, there is no guarantee each
+ // saved object has wsState.
+ if (typeof savedObject.wsState !== 'string') {
+ return;
+ }
+ // Only need to parse / stringify once here compared to extractReferences
+ const state = JSON.parse(savedObject.wsState);
+ // Like the migration, skip injectReferences if "indexPatternRefName" is missing
+ if (!state.indexPatternRefName) {
+ return;
+ }
+ const indexPatternReference = references.find(reference => reference.name === state.indexPatternRefName);
+ if (!indexPatternReference) {
+ // Throw an error as "indexPatternRefName" means the reference exists within
+ // "references" and in this scenario we have bad data.
+ throw new Error(`Could not find reference "${state.indexPatternRefName}"`);
+ }
+ state.indexPattern = indexPatternReference.id;
+ delete state.indexPatternRefName;
+ savedObject.wsState = JSON.stringify(state);
+}
diff --git a/x-pack/plugins/graph/public/services/saved_workspace_references.test.js b/x-pack/plugins/graph/public/services/saved_workspace_references.test.js
new file mode 100644
index 0000000000000..01eb7f9ead1f0
--- /dev/null
+++ b/x-pack/plugins/graph/public/services/saved_workspace_references.test.js
@@ -0,0 +1,124 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import { extractReferences, injectReferences } from './saved_workspace_references';
+
+describe('extractReferences', () => {
+ test('extracts references from wsState', () => {
+ const doc = {
+ id: '1',
+ attributes: {
+ foo: true,
+ wsState: JSON.stringify(
+ JSON.stringify({
+ indexPattern: 'pattern*',
+ bar: true,
+ })
+ ),
+ },
+ };
+ const updatedDoc = extractReferences(doc);
+ expect(updatedDoc).toMatchInlineSnapshot(`
+Object {
+ "attributes": Object {
+ "foo": true,
+ "wsState": "\\"{\\\\\\"bar\\\\\\":true,\\\\\\"indexPatternRefName\\\\\\":\\\\\\"indexPattern_0\\\\\\"}\\"",
+ },
+ "references": Array [
+ Object {
+ "id": "pattern*",
+ "name": "indexPattern_0",
+ "type": "index-pattern",
+ },
+ ],
+}
+`);
+ });
+
+ test('fails when indexPattern is missing from workspace', () => {
+ const doc = {
+ id: '1',
+ attributes: {
+ wsState: JSON.stringify(
+ JSON.stringify({
+ bar: true,
+ })
+ ),
+ },
+ };
+ expect(() => extractReferences(doc)).toThrowErrorMatchingInlineSnapshot(
+ `"indexPattern attribute is missing in \\"wsState\\""`
+ );
+ });
+});
+
+describe('injectReferences', () => {
+ test('injects references into context', () => {
+ const context = {
+ id: '1',
+ foo: true,
+ wsState: JSON.stringify({
+ indexPatternRefName: 'indexPattern_0',
+ bar: true,
+ }),
+ };
+ const references = [
+ {
+ name: 'indexPattern_0',
+ type: 'index-pattern',
+ id: 'pattern*',
+ },
+ ];
+ injectReferences(context, references);
+ expect(context).toMatchInlineSnapshot(`
+Object {
+ "foo": true,
+ "id": "1",
+ "wsState": "{\\"bar\\":true,\\"indexPattern\\":\\"pattern*\\"}",
+}
+`);
+ });
+
+ test('skips when wsState is not a string', () => {
+ const context = {
+ id: '1',
+ foo: true,
+ };
+ injectReferences(context, []);
+ expect(context).toMatchInlineSnapshot(`
+Object {
+ "foo": true,
+ "id": "1",
+}
+`);
+ });
+
+ test('skips when indexPatternRefName is missing wsState', () => {
+ const context = {
+ id: '1',
+ wsState: JSON.stringify({ bar: true }),
+ };
+ injectReferences(context, []);
+ expect(context).toMatchInlineSnapshot(`
+Object {
+ "id": "1",
+ "wsState": "{\\"bar\\":true}",
+}
+`);
+ });
+
+ test(`fails when it can't find the reference in the array`, () => {
+ const context = {
+ id: '1',
+ wsState: JSON.stringify({
+ indexPatternRefName: 'indexPattern_0',
+ }),
+ };
+ expect(() => injectReferences(context, [])).toThrowErrorMatchingInlineSnapshot(
+ `"Could not find reference \\"indexPattern_0\\""`
+ );
+ });
+});
diff --git a/x-pack/plugins/index_management/public/index_management_extensions.js b/x-pack/plugins/index_management/public/index_management_extensions.js
index 32d07e89c1fdf..28c5ad974b538 100644
--- a/x-pack/plugins/index_management/public/index_management_extensions.js
+++ b/x-pack/plugins/index_management/public/index_management_extensions.js
@@ -47,6 +47,7 @@ const badgeExtensions = [
label: i18n.translate('xpack.idxMgmt.frozenBadgeLabel', {
defaultMessage: 'Frozen',
}),
+ filterExpression: 'isFrozen:true',
color: 'primary'
}
];
diff --git a/x-pack/plugins/index_management/public/lib/render_badges.js b/x-pack/plugins/index_management/public/lib/render_badges.js
index 4f8c224c084c5..661dad876a7f0 100644
--- a/x-pack/plugins/index_management/public/lib/render_badges.js
+++ b/x-pack/plugins/index_management/public/lib/render_badges.js
@@ -6,15 +6,34 @@
import React, { Fragment } from 'react';
-import { EuiBadge } from '@elastic/eui';
+import { i18n } from '@kbn/i18n';
+import { EuiBadge, EuiSearchBar } from '@elastic/eui';
import { getBadgeExtensions } from '../index_management_extensions';
-export const renderBadges = (index) => {
+export const renderBadges = (index, filterChanged) => {
const badgeLabels = [];
- getBadgeExtensions().forEach(({ matchIndex, label, color }) => {
+ getBadgeExtensions().forEach(({ matchIndex, label, color, filterExpression }) => {
if (matchIndex(index)) {
+ const clickHandler = () => {
+ filterChanged
+ && filterExpression
+ && filterChanged(EuiSearchBar.Query.parse(filterExpression));
+ };
badgeLabels.push(
- {' '}{label}
+ {' '}
+
+ {label}
+
);
}
diff --git a/x-pack/plugins/index_management/public/sections/index_list/components/index_table/index_table.js b/x-pack/plugins/index_management/public/sections/index_list/components/index_table/index_table.js
index 6ff588a6a4fe0..944d8fcec87c0 100644
--- a/x-pack/plugins/index_management/public/sections/index_list/components/index_table/index_table.js
+++ b/x-pack/plugins/index_management/public/sections/index_list/components/index_table/index_table.js
@@ -213,20 +213,23 @@ export class IndexTableUi extends Component {
}
buildRowCell(fieldName, value, index) {
- const { openDetailPanel } = this.props;
+ const { openDetailPanel, filterChanged } = this.props;
if (fieldName === 'health') {
return {value};
} else if (fieldName === 'name') {
return (
- {
- openDetailPanel(value);
- }}
- >
- {value}{renderBadges(index)}
-
+
+ {
+ openDetailPanel(value);
+ }}
+ >
+ {value}
+
+ {renderBadges(index, filterChanged)}
+
);
}
return value;
diff --git a/x-pack/plugins/infra/public/components/logging/log_flyout.tsx b/x-pack/plugins/infra/public/components/logging/log_flyout.tsx
new file mode 100644
index 0000000000000..7c277dd78ba78
--- /dev/null
+++ b/x-pack/plugins/infra/public/components/logging/log_flyout.tsx
@@ -0,0 +1,114 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import {
+ EuiBasicTable,
+ EuiButtonIcon,
+ EuiFlyout,
+ EuiFlyoutBody,
+ EuiFlyoutHeader,
+ EuiTitle,
+ EuiToolTip,
+} from '@elastic/eui';
+import { FormattedMessage, InjectedIntl, injectI18n } from '@kbn/i18n/react';
+import React from 'react';
+import styled from 'styled-components';
+import { InfraLogItem, InfraLogItemField } from '../../graphql/types';
+import { InfraLoadingPanel } from '../loading';
+interface Props {
+ flyoutItem: InfraLogItem | null;
+ hideFlyout: () => void;
+ setFilter: (filter: string) => void;
+ intl: InjectedIntl;
+ loading: boolean;
+}
+
+export const LogFlyout = injectI18n(
+ ({ flyoutItem, loading, hideFlyout, setFilter, intl }: Props) => {
+ const handleFilter = (field: InfraLogItemField) => () => {
+ const filter = `${field.field}:"${field.value}"`;
+ setFilter(filter);
+ };
+
+ const columns = [
+ {
+ field: 'field',
+ name: intl.formatMessage({
+ defaultMessage: 'Field',
+ id: 'xpack.infra.logFlyout.fieldColumnLabel',
+ }),
+ sortable: true,
+ },
+ {
+ field: 'value',
+ name: intl.formatMessage({
+ defaultMessage: 'Value',
+ id: 'xpack.infra.logFlyout.valueColumnLabel',
+ }),
+ sortable: true,
+ render: (name: string, item: InfraLogItemField) => (
+
+
+
+
+ {item.value}
+
+ ),
+ },
+ ];
+ return (
+ hideFlyout()} size="m">
+
+
+
+
+
+
+
+
+ {loading || flyoutItem === null ? (
+
+
+
+ ) : (
+
+ )}
+
+
+ );
+ }
+);
+
+export const InfraFlyoutLoadingPanel = styled.div`
+ position: absolute;
+ top: 0;
+ right: 0;
+ bottom: 0;
+ left: 0;
+`;
diff --git a/x-pack/plugins/infra/public/components/logging/log_text_stream/item_date_field.tsx b/x-pack/plugins/infra/public/components/logging/log_text_stream/item_date_field.tsx
index f75056e23aef0..8550033e471c6 100644
--- a/x-pack/plugins/infra/public/components/logging/log_text_stream/item_date_field.tsx
+++ b/x-pack/plugins/infra/public/components/logging/log_text_stream/item_date_field.tsx
@@ -64,6 +64,7 @@ const LogTextStreamItemDateFieldWrapper = LogTextStreamItemField.extend.attrs<{
border-right: solid 2px ${props => props.theme.eui.euiColorLightShade};
color: ${props => props.theme.eui.euiColorDarkShade};
white-space: pre;
+ padding: 0 ${props => props.theme.eui.paddingSizes.l};
${props => (props.hasHighlights ? highlightedFieldStyle : '')};
${props => (props.isHovered ? hoveredFieldStyle : '')};
diff --git a/x-pack/plugins/infra/public/components/logging/log_text_stream/item_field.tsx b/x-pack/plugins/infra/public/components/logging/log_text_stream/item_field.tsx
index c9d360fc116a7..4b6dcdb635ad9 100644
--- a/x-pack/plugins/infra/public/components/logging/log_text_stream/item_field.tsx
+++ b/x-pack/plugins/infra/public/components/logging/log_text_stream/item_field.tsx
@@ -19,5 +19,5 @@ export const LogTextStreamItemField = styled.div.attrs<{
[switchProp.default]: props.theme.eui.euiFontSize,
})};
line-height: ${props => props.theme.eui.euiLineHeight};
- padding: 2px ${props => props.theme.eui.euiSize};
+ padding: 2px ${props => props.theme.eui.euiSize} 2px 0;
`;
diff --git a/x-pack/plugins/infra/public/components/logging/log_text_stream/item_message_field.tsx b/x-pack/plugins/infra/public/components/logging/log_text_stream/item_message_field.tsx
index 77ef813261818..39f75d5b7ab64 100644
--- a/x-pack/plugins/infra/public/components/logging/log_text_stream/item_message_field.tsx
+++ b/x-pack/plugins/infra/public/components/logging/log_text_stream/item_message_field.tsx
@@ -105,7 +105,6 @@ const LogTextStreamItemMessageFieldWrapper = LogTextStreamItemField.extend.attrs
const HighlightSpan = styled.span`
display: inline-block;
- padding: 0 ${props => props.theme.eui.euiSizeXs};
background-color: ${props => props.theme.eui.euiColorSecondary};
color: ${props => props.theme.eui.euiColorGhost};
font-weight: ${props => props.theme.eui.euiFontWeightMedium};
diff --git a/x-pack/plugins/infra/public/components/logging/log_text_stream/item_view.tsx b/x-pack/plugins/infra/public/components/logging/log_text_stream/item_view.tsx
index c4a75771fa5a0..055b92250b0f8 100644
--- a/x-pack/plugins/infra/public/components/logging/log_text_stream/item_view.tsx
+++ b/x-pack/plugins/infra/public/components/logging/log_text_stream/item_view.tsx
@@ -14,10 +14,11 @@ interface StreamItemProps {
item: StreamItem;
scale: TextScale;
wrap: boolean;
+ openFlyoutWithItem: (id: string) => void;
}
export const LogTextStreamItemView = React.forwardRef(
- ({ item, scale, wrap }, ref) => {
+ ({ item, scale, wrap, openFlyoutWithItem }, ref) => {
switch (item.kind) {
case 'logEntry':
return (
@@ -27,6 +28,7 @@ export const LogTextStreamItemView = React.forwardRef(
searchResult={item.searchResult}
scale={scale}
wrap={wrap}
+ openFlyoutWithItem={openFlyoutWithItem}
/>
);
}
diff --git a/x-pack/plugins/infra/public/components/logging/log_text_stream/log_entry_item_view.tsx b/x-pack/plugins/infra/public/components/logging/log_text_stream/log_entry_item_view.tsx
index 2e910cad56785..fb8642c3bd680 100644
--- a/x-pack/plugins/infra/public/components/logging/log_text_stream/log_entry_item_view.tsx
+++ b/x-pack/plugins/infra/public/components/logging/log_text_stream/log_entry_item_view.tsx
@@ -4,9 +4,12 @@
* you may not use this file except in compliance with the Elastic License.
*/
+import { darken, transparentize } from 'polished';
import * as React from 'react';
import styled from 'styled-components';
+import { EuiButtonIcon, EuiToolTip } from '@elastic/eui';
+import { InjectedIntl, injectI18n } from '@kbn/i18n/react';
import { LogEntry } from '../../../../common/log_entry';
import { SearchResult } from '../../../../common/log_search_result';
import { TextScale } from '../../../../common/log_text_scale';
@@ -20,65 +23,110 @@ interface LogTextStreamLogEntryItemViewProps {
searchResult?: SearchResult;
scale: TextScale;
wrap: boolean;
+ openFlyoutWithItem: (id: string) => void;
+ intl: InjectedIntl;
}
interface LogTextStreamLogEntryItemViewState {
isHovered: boolean;
}
-export class LogTextStreamLogEntryItemView extends React.PureComponent<
- LogTextStreamLogEntryItemViewProps,
- LogTextStreamLogEntryItemViewState
-> {
- public readonly state = {
- isHovered: false,
- };
+export const LogTextStreamLogEntryItemView = injectI18n(
+ class extends React.PureComponent<
+ LogTextStreamLogEntryItemViewProps,
+ LogTextStreamLogEntryItemViewState
+ > {
+ public readonly state = {
+ isHovered: false,
+ };
- public handleMouseEnter: React.MouseEventHandler = () => {
- this.setState({
- isHovered: true,
- });
- };
+ public handleMouseEnter: React.MouseEventHandler = () => {
+ this.setState({
+ isHovered: true,
+ });
+ };
- public handleMouseLeave: React.MouseEventHandler = () => {
- this.setState({
- isHovered: false,
- });
- };
+ public handleMouseLeave: React.MouseEventHandler = () => {
+ this.setState({
+ isHovered: false,
+ });
+ };
- public render() {
- const { boundingBoxRef, logEntry, scale, searchResult, wrap } = this.props;
- const { isHovered } = this.state;
+ public handleClick: React.MouseEventHandler = () => {
+ this.props.openFlyoutWithItem(this.props.logEntry.gid);
+ };
- return (
-
-
- {formatTime(logEntry.fields.time)}
-
-
- {logEntry.fields.message}
-
-
- );
+
+ {formatTime(logEntry.fields.time)}
+
+
+ {isHovered ? (
+
+
+
+ ) : (
+
+ )}
+
+
+ {logEntry.fields.message}
+
+
+ );
+ }
}
+);
+
+interface IconProps {
+ isHovered: boolean;
}
+const EmptyIcon = styled.div`
+ width: 24px;
+`;
+
+const LogTextStreamIconDiv = styled('div')`
+ flex-grow: 0;
+ background-color: ${props =>
+ props.isHovered
+ ? props.theme.darkMode
+ ? transparentize(0.9, darken(0.05, props.theme.eui.euiColorHighlight))
+ : darken(0.05, props.theme.eui.euiColorHighlight)
+ : 'transparent'};
+ text-align: center;
+ user-select: none;
+`;
+
const LogTextStreamLogEntryItemDiv = styled.div`
font-family: ${props => props.theme.eui.euiCodeFontFamily};
font-size: ${props => props.theme.eui.euiFontSize};
diff --git a/x-pack/plugins/infra/public/components/logging/log_text_stream/scrollable_log_text_stream_view.tsx b/x-pack/plugins/infra/public/components/logging/log_text_stream/scrollable_log_text_stream_view.tsx
index eb74ffcc29394..47db7a6716de8 100644
--- a/x-pack/plugins/infra/public/components/logging/log_text_stream/scrollable_log_text_stream_view.tsx
+++ b/x-pack/plugins/infra/public/components/logging/log_text_stream/scrollable_log_text_stream_view.tsx
@@ -42,6 +42,8 @@ interface ScrollableLogTextStreamViewProps {
}
) => any;
loadNewerItems: () => void;
+ setFlyoutItem: (id: string) => void;
+ showFlyout: () => void;
}
interface ScrollableLogTextStreamViewState {
@@ -141,7 +143,13 @@ export class ScrollableLogTextStreamView extends React.PureComponent<
key={getStreamItemId(item)}
>
{measureRef => (
-
+
)}
))}
@@ -160,6 +168,11 @@ export class ScrollableLogTextStreamView extends React.PureComponent<
}
}
+ private handleOpenFlyout = (id: string) => {
+ this.props.setFlyoutItem(id);
+ this.props.showFlyout();
+ };
+
private handleReload = () => {
const { jumpToTarget, target } = this.props;
diff --git a/x-pack/plugins/infra/public/components/waffle/index.tsx b/x-pack/plugins/infra/public/components/nodes_overview/index.tsx
similarity index 56%
rename from x-pack/plugins/infra/public/components/waffle/index.tsx
rename to x-pack/plugins/infra/public/components/nodes_overview/index.tsx
index d38301f6eb1f8..6663b2354a40a 100644
--- a/x-pack/plugins/infra/public/components/waffle/index.tsx
+++ b/x-pack/plugins/infra/public/components/nodes_overview/index.tsx
@@ -10,34 +10,29 @@ import React from 'react';
import styled from 'styled-components';
import {
- isWaffleMapGroupWithGroups,
- isWaffleMapGroupWithNodes,
-} from '../../containers/waffle/type_guards';
-import { InfraMetricType, InfraNodeType, InfraTimerangeInput } from '../../graphql/types';
-import {
- InfraFormatterType,
- InfraWaffleData,
- InfraWaffleMapBounds,
- InfraWaffleMapGroup,
- InfraWaffleMapOptions,
-} from '../../lib/lib';
+ InfraMetricType,
+ InfraNode,
+ InfraNodeType,
+ InfraTimerangeInput,
+} from '../../graphql/types';
+import { InfraFormatterType, InfraWaffleMapBounds, InfraWaffleMapOptions } from '../../lib/lib';
import { KueryFilterQuery } from '../../store/local/waffle_filter';
import { createFormatter } from '../../utils/formatters';
-import { AutoSizer } from '../auto_sizer';
import { InfraLoadingPanel } from '../loading';
-import { GroupOfGroups } from './group_of_groups';
-import { GroupOfNodes } from './group_of_nodes';
-import { Legend } from './legend';
-import { applyWaffleMapLayout } from './lib/apply_wafflemap_layout';
+import { Map } from '../waffle/map';
+import { ViewSwitcher } from '../waffle/view_switcher';
+import { TableView } from './table';
interface Props {
options: InfraWaffleMapOptions;
nodeType: InfraNodeType;
- map: InfraWaffleData;
+ nodes: InfraNode[];
loading: boolean;
reload: () => void;
onDrilldown: (filter: KueryFilterQuery) => void;
timeRange: InfraTimerangeInput;
+ onViewChange: (view: string) => void;
+ view: string;
intl: InjectedIntl;
}
@@ -71,24 +66,8 @@ const METRIC_FORMATTERS: MetricFormatters = {
},
};
-const extractValuesFromMap = (groups: InfraWaffleMapGroup[], values: number[] = []): number[] => {
- return groups.reduce((acc: number[], group: InfraWaffleMapGroup) => {
- if (isWaffleMapGroupWithGroups(group)) {
- return acc.concat(extractValuesFromMap(group.groups, values));
- }
- if (isWaffleMapGroupWithNodes(group)) {
- return acc.concat(
- group.nodes.map(node => {
- return node.metric.value || 0;
- })
- );
- }
- return acc;
- }, values);
-};
-
-const calculateBoundsFromMap = (map: InfraWaffleData): InfraWaffleMapBounds => {
- const values = extractValuesFromMap(map);
+const calculateBoundsFromNodes = (nodes: InfraNode[]): InfraWaffleMapBounds => {
+ const values = nodes.map(node => node.metric.value);
// if there is only one value then we need to set the bottom range to zero
if (values.length === 1) {
values.unshift(0);
@@ -96,11 +75,11 @@ const calculateBoundsFromMap = (map: InfraWaffleData): InfraWaffleMapBounds => {
return { min: min(values) || 0, max: max(values) || 0 };
};
-export const Waffle = injectI18n(
+export const NodesOverview = injectI18n(
class extends React.Component {
public static displayName = 'Waffle';
public render() {
- const { loading, map, reload, timeRange, intl } = this.props;
+ const { loading, nodes, nodeType, reload, intl, view, options, timeRange } = this.props;
if (loading) {
return (
);
- } else if (!loading && map && map.length === 0) {
+ } else if (!loading && nodes && nodes.length === 0) {
return (
- {({ measureRef, content: { width = 0, height = 0 } }) => {
- const groupsWithLayout = applyWaffleMapLayout(map, width, height);
- return (
- measureRef(el)}
- data-test-subj="waffleMap"
- >
-
- {groupsWithLayout.map(this.renderGroup(bounds, timeRange))}
-
-
-
- );
- }}
-
+
+
+
+
+ {view === 'table' ? (
+
+
+
+ ) : (
+
+
+
+ )}
+
);
}
+ private handleViewChange = (view: string) => this.props.onViewChange(view);
+
// TODO: Change this to a real implimentation using the tickFormatter from the prototype as an example.
private formatter = (val: string | number) => {
const { metric } = this.props.options;
@@ -204,61 +194,31 @@ export const Waffle = injectI18n(
});
return;
};
-
- private renderGroup = (bounds: InfraWaffleMapBounds, timeRange: InfraTimerangeInput) => (
- group: InfraWaffleMapGroup
- ) => {
- if (isWaffleMapGroupWithGroups(group)) {
- return (
-
- );
- }
- if (isWaffleMapGroupWithNodes(group)) {
- return (
-
- );
- }
- };
}
);
-const WaffleMapOuterContiner = styled.div`
- flex: 1 0 0%;
- display: flex;
- justify-content: center;
- flex-direction: column;
- overflow-x: hidden;
- overflow-y: auto;
+const CenteredEmptyPrompt = styled(EuiEmptyPrompt)`
+ align-self: center;
`;
-const WaffleMapInnerContainer = styled.div`
- display: flex;
- flex-direction: row;
- flex-wrap: wrap;
- justify-content: center;
- align-content: flex-start;
- padding: 10px;
+const MainContainer = styled.div`
+ position: relative;
+ flex: 1 1 auto;
`;
-const CenteredEmptyPrompt = styled(EuiEmptyPrompt)`
- align-self: center;
+const TableContainer = styled.div`
+ padding: ${props => props.theme.eui.paddingSizes.l};
+`;
+
+const ViewSwitcherContainer = styled.div`
+ padding: ${props => props.theme.eui.paddingSizes.l};
+`;
+
+const MapContainer = styled.div`
+ position: absolute;
+ display: flex;
+ top: 0;
+ right: 0;
+ bottom: 0;
+ left: 0;
`;
diff --git a/x-pack/plugins/infra/public/components/nodes_overview/table.tsx b/x-pack/plugins/infra/public/components/nodes_overview/table.tsx
new file mode 100644
index 0000000000000..ac188d5e0d169
--- /dev/null
+++ b/x-pack/plugins/infra/public/components/nodes_overview/table.tsx
@@ -0,0 +1,167 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import { EuiButtonEmpty, EuiInMemoryTable, EuiToolTip } from '@elastic/eui';
+import { InjectedIntl, injectI18n } from '@kbn/i18n/react';
+import { last } from 'lodash';
+import React from 'react';
+import { InfraNodeType } from '../../../server/lib/adapters/nodes';
+import { createWaffleMapNode } from '../../containers/waffle/nodes_to_wafflemap';
+import { InfraNode, InfraNodePath, InfraTimerangeInput } from '../../graphql/types';
+import { InfraWaffleMapNode, InfraWaffleMapOptions } from '../../lib/lib';
+import { fieldToName } from '../waffle/lib/field_to_display_name';
+import { NodeContextMenu } from '../waffle/node_context_menu';
+
+interface Props {
+ nodes: InfraNode[];
+ nodeType: InfraNodeType;
+ options: InfraWaffleMapOptions;
+ formatter: (subject: string | number) => string;
+ timeRange: InfraTimerangeInput;
+ intl: InjectedIntl;
+ onFilter: (filter: string) => void;
+}
+
+const initialState = {
+ isPopoverOpen: [] as string[],
+};
+
+type State = Readonly;
+
+const getGroupPaths = (path: InfraNodePath[]) => {
+ switch (path.length) {
+ case 3:
+ return path.slice(0, 2);
+ case 2:
+ return path.slice(0, 1);
+ default:
+ return [];
+ }
+};
+
+export const TableView = injectI18n(
+ class extends React.PureComponent {
+ public readonly state: State = initialState;
+ public render() {
+ const { nodes, options, formatter, intl, timeRange, nodeType } = this.props;
+ const columns = [
+ {
+ field: 'name',
+ name: intl.formatMessage({
+ id: 'xpack.infra.tableView.columnName.name',
+ defaultMessage: 'Name',
+ }),
+ sortable: true,
+ truncateText: true,
+ textOnly: true,
+ render: (value: string, item: { node: InfraWaffleMapNode }) => (
+
+
+ {value}
+
+
+ ),
+ },
+ ...options.groupBy.map((grouping, index) => ({
+ field: `group_${index}`,
+ name: fieldToName((grouping && grouping.field) || '', intl),
+ sortable: true,
+ truncateText: true,
+ textOnly: true,
+ render: (value: string) => {
+ const handleClick = () => this.props.onFilter(`${grouping.field}:"${value}"`);
+ return (
+
+ {value}
+
+ );
+ },
+ })),
+ {
+ field: 'value',
+ name: intl.formatMessage({
+ id: 'xpack.infra.tableView.columnName.last1m',
+ defaultMessage: 'Last 1m',
+ }),
+ sortable: true,
+ truncateText: true,
+ dataType: 'number',
+ render: (value: number) => {formatter(value)},
+ },
+ {
+ field: 'avg',
+ name: intl.formatMessage({
+ id: 'xpack.infra.tableView.columnName.avg',
+ defaultMessage: 'Avg',
+ }),
+ sortable: true,
+ truncateText: true,
+ dataType: 'number',
+ render: (value: number) => {formatter(value)},
+ },
+ {
+ field: 'max',
+ name: intl.formatMessage({
+ id: 'xpack.infra.tableView.columnName.max',
+ defaultMessage: 'Max',
+ }),
+ sortable: true,
+ truncateText: true,
+ dataType: 'number',
+ render: (value: number) => {formatter(value)},
+ },
+ ];
+ const items = nodes.map(node => {
+ const name = last(node.path);
+ return {
+ name: (name && name.value) || 'unknown',
+ ...getGroupPaths(node.path).reduce(
+ (acc, path, index) => ({
+ ...acc,
+ [`group_${index}`]: path.label,
+ }),
+ {}
+ ),
+ value: node.metric.value,
+ avg: node.metric.avg,
+ max: node.metric.max,
+ node: createWaffleMapNode(node),
+ };
+ });
+ const initialSorting = {
+ sort: {
+ field: 'value',
+ direction: 'desc',
+ },
+ };
+ return (
+
+ );
+ }
+
+ private openPopoverFor = (id: string) => () => {
+ this.setState(prevState => ({ isPopoverOpen: [...prevState.isPopoverOpen, id] }));
+ };
+
+ private closePopoverFor = (id: string) => () => {
+ this.setState(prevState => ({
+ isPopoverOpen: prevState.isPopoverOpen.filter(subject => subject !== id),
+ }));
+ };
+ }
+);
diff --git a/x-pack/plugins/infra/public/components/waffle/custom_field_panel.tsx b/x-pack/plugins/infra/public/components/waffle/custom_field_panel.tsx
new file mode 100644
index 0000000000000..0c676e587a774
--- /dev/null
+++ b/x-pack/plugins/infra/public/components/waffle/custom_field_panel.tsx
@@ -0,0 +1,78 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import { EuiButton, EuiComboBox, EuiForm, EuiFormRow } from '@elastic/eui';
+import { InjectedIntl, injectI18n } from '@kbn/i18n/react';
+import React from 'react';
+import { InfraIndexField } from 'x-pack/plugins/infra/server/graphql/types';
+interface Props {
+ onSubmit: (field: string) => void;
+ fields: InfraIndexField[];
+ intl: InjectedIntl;
+}
+
+interface SelectedOption {
+ label: string;
+}
+
+const initialState = {
+ selectedOptions: [] as SelectedOption[],
+};
+
+type State = Readonly;
+
+export const CustomFieldPanel = injectI18n(
+ class extends React.PureComponent {
+ public static displayName = 'CustomFieldPanel';
+ public readonly state: State = initialState;
+ public render() {
+ const { fields, intl } = this.props;
+ const options = fields
+ .filter(f => f.aggregatable && f.type === 'string')
+ .map(f => ({ label: f.name }));
+ return (
+
+
+
+
+
+
+ Add
+
+
+
+ );
+ }
+
+ private handleSubmit = () => {
+ this.props.onSubmit(this.state.selectedOptions[0].label);
+ };
+
+ private handleFieldSelection = (selectedOptions: SelectedOption[]) => {
+ this.setState({ selectedOptions });
+ };
+ }
+);
diff --git a/x-pack/plugins/infra/public/components/waffle/lib/field_to_display_name.ts b/x-pack/plugins/infra/public/components/waffle/lib/field_to_display_name.ts
new file mode 100644
index 0000000000000..58f47b4ff46cf
--- /dev/null
+++ b/x-pack/plugins/infra/public/components/waffle/lib/field_to_display_name.ts
@@ -0,0 +1,45 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import { InjectedIntl } from '@kbn/i18n/react';
+
+interface Lookup {
+ [id: string]: string;
+}
+
+export const fieldToName = (field: string, intl: InjectedIntl) => {
+ const LOOKUP: Lookup = {
+ 'kubernetes.namespace': intl.formatMessage({
+ id: 'xpack.infra.groupByDisplayNames.kubernetesNamespace',
+ defaultMessage: 'Namespace',
+ }),
+ 'kubernetes.node.name': intl.formatMessage({
+ id: 'xpack.infra.groupByDisplayNames.kubernetesNodeName',
+ defaultMessage: 'Node',
+ }),
+ 'host.name': intl.formatMessage({
+ id: 'xpack.infra.groupByDisplayNames.hostName',
+ defaultMessage: 'Host',
+ }),
+ 'meta.cloud.availability_zone': intl.formatMessage({
+ id: 'xpack.infra.groupByDisplayNames.availabilityZone',
+ defaultMessage: 'Availability Zone',
+ }),
+ 'meta.cloud.machine_type': intl.formatMessage({
+ id: 'xpack.infra.groupByDisplayNames.machineType',
+ defaultMessage: 'Machine Type',
+ }),
+ 'meta.cloud.project_id': intl.formatMessage({
+ id: 'xpack.infra.groupByDisplayNames.projectID',
+ defaultMessage: 'Project ID',
+ }),
+ 'meta.cloud.provider': intl.formatMessage({
+ id: 'xpack.infra.groupByDisplayNames.provider',
+ defaultMessage: 'Cloud Provider',
+ }),
+ };
+ return LOOKUP[field] || field;
+};
diff --git a/x-pack/plugins/infra/public/components/waffle/map.tsx b/x-pack/plugins/infra/public/components/waffle/map.tsx
new file mode 100644
index 0000000000000..0bd4c5a8e388b
--- /dev/null
+++ b/x-pack/plugins/infra/public/components/waffle/map.tsx
@@ -0,0 +1,107 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+import React from 'react';
+import styled from 'styled-components';
+import { nodesToWaffleMap } from '../../containers/waffle/nodes_to_wafflemap';
+import {
+ isWaffleMapGroupWithGroups,
+ isWaffleMapGroupWithNodes,
+} from '../../containers/waffle/type_guards';
+import { InfraNode, InfraNodeType, InfraTimerangeInput } from '../../graphql/types';
+import { InfraWaffleMapBounds, InfraWaffleMapOptions } from '../../lib/lib';
+import { AutoSizer } from '../auto_sizer';
+import { GroupOfGroups } from './group_of_groups';
+import { GroupOfNodes } from './group_of_nodes';
+import { Legend } from './legend';
+import { applyWaffleMapLayout } from './lib/apply_wafflemap_layout';
+
+interface Props {
+ nodes: InfraNode[];
+ nodeType: InfraNodeType;
+ options: InfraWaffleMapOptions;
+ formatter: (subject: string | number) => string;
+ timeRange: InfraTimerangeInput;
+ onFilter: (filter: string) => void;
+ bounds: InfraWaffleMapBounds;
+}
+
+export const Map: React.SFC = ({
+ nodes,
+ options,
+ timeRange,
+ onFilter,
+ formatter,
+ bounds,
+ nodeType,
+}) => {
+ const map = nodesToWaffleMap(nodes);
+ return (
+
+ {({ measureRef, content: { width = 0, height = 0 } }) => {
+ const groupsWithLayout = applyWaffleMapLayout(map, width, height);
+ return (
+ measureRef(el)}
+ data-test-subj="waffleMap"
+ >
+
+ {groupsWithLayout.map(group => {
+ if (isWaffleMapGroupWithGroups(group)) {
+ return (
+
+ );
+ }
+ if (isWaffleMapGroupWithNodes(group)) {
+ return (
+
+ );
+ }
+ })}
+
+
+
+ );
+ }}
+
+ );
+};
+
+const WaffleMapOuterContainer = styled.div`
+ flex: 1 0 0%;
+ display: flex;
+ justify-content: center;
+ flex-direction: column;
+ overflow-x: hidden;
+ overflow-y: auto;
+`;
+
+const WaffleMapInnerContainer = styled.div`
+ display: flex;
+ flex-direction: row;
+ flex-wrap: wrap;
+ justify-content: center;
+ align-content: flex-start;
+ padding: 10px;
+`;
diff --git a/x-pack/plugins/infra/public/components/waffle/view_switcher.tsx b/x-pack/plugins/infra/public/components/waffle/view_switcher.tsx
new file mode 100644
index 0000000000000..83952ff8f5c1f
--- /dev/null
+++ b/x-pack/plugins/infra/public/components/waffle/view_switcher.tsx
@@ -0,0 +1,48 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import { EuiButtonGroup } from '@elastic/eui';
+import { InjectedIntl, injectI18n } from '@kbn/i18n/react';
+import React from 'react';
+
+interface Props {
+ view: string;
+ onChange: (view: string) => void;
+ intl: InjectedIntl;
+}
+
+export const ViewSwitcher = injectI18n(({ view, onChange, intl }: Props) => {
+ const buttons = [
+ {
+ id: 'map',
+ label: intl.formatMessage({
+ id: 'xpack.infra.viewSwitcher.mapViewLabel',
+ defaultMessage: 'Map View',
+ }),
+ iconType: 'apps',
+ },
+ {
+ id: 'table',
+ label: intl.formatMessage({
+ id: 'xpack.infra.viewSwitcher.tableViewLabel',
+ defaultMessage: 'Table View',
+ }),
+ iconType: 'editorUnorderedList',
+ },
+ ];
+ return (
+
+ );
+});
diff --git a/x-pack/plugins/infra/public/components/waffle/waffle_group_by_controls.tsx b/x-pack/plugins/infra/public/components/waffle/waffle_group_by_controls.tsx
index e492e153c67a0..7b58bed4d69b2 100644
--- a/x-pack/plugins/infra/public/components/waffle/waffle_group_by_controls.tsx
+++ b/x-pack/plugins/infra/public/components/waffle/waffle_group_by_controls.tsx
@@ -8,122 +8,56 @@ import {
EuiBadge,
EuiContextMenu,
EuiContextMenuPanelDescriptor,
+ EuiContextMenuPanelItemDescriptor,
EuiFilterButton,
EuiFilterGroup,
EuiPopover,
} from '@elastic/eui';
import { FormattedMessage, InjectedIntl, injectI18n } from '@kbn/i18n/react';
import React from 'react';
-import { InfraNodeType, InfraPathInput, InfraPathType } from '../../graphql/types';
+import { InfraIndexField, InfraNodeType, InfraPathInput, InfraPathType } from '../../graphql/types';
+import { InfraGroupByOptions } from '../../lib/lib';
+import { CustomFieldPanel } from './custom_field_panel';
+import { fieldToName } from './lib/field_to_display_name';
interface Props {
nodeType: InfraNodeType;
groupBy: InfraPathInput[];
onChange: (groupBy: InfraPathInput[]) => void;
+ onChangeCustomOptions: (options: InfraGroupByOptions[]) => void;
+ fields: InfraIndexField[];
intl: InjectedIntl;
+ customOptions: InfraGroupByOptions[];
}
-let OPTIONS: { [P in InfraNodeType]: Array<{ text: string; type: InfraPathType; field: string }> };
+const createFieldToOptionMapper = (intl: InjectedIntl) => (field: string) => ({
+ text: fieldToName(field, intl),
+ type: InfraPathType.terms,
+ field,
+});
+
+let OPTIONS: { [P in InfraNodeType]: InfraGroupByOptions[] };
const getOptions = (
nodeType: InfraNodeType,
intl: InjectedIntl
): Array<{ text: string; type: InfraPathType; field: string }> => {
if (!OPTIONS) {
+ const mapFieldToOption = createFieldToOptionMapper(intl);
OPTIONS = {
- [InfraNodeType.pod]: [
- {
- text: intl.formatMessage({
- id: 'xpack.infra.waffle.podGroupByOptions.namespaceLabel',
- defaultMessage: 'Namespace',
- }),
- type: InfraPathType.terms,
- field: 'kubernetes.namespace',
- },
- {
- text: intl.formatMessage({
- id: 'xpack.infra.waffle.podGroupByOptions.nodeLabel',
- defaultMessage: 'Node',
- }),
- type: InfraPathType.terms,
- field: 'kubernetes.node.name',
- },
- ],
+ [InfraNodeType.pod]: ['kubernetes.namespace', 'kubernetes.node.name'].map(mapFieldToOption),
[InfraNodeType.container]: [
- {
- text: intl.formatMessage({
- id: 'xpack.infra.waffle.containerGroupByOptions.hostLabel',
- defaultMessage: 'Host',
- }),
- type: InfraPathType.terms,
- field: 'host.name',
- },
- {
- text: intl.formatMessage({
- id: 'xpack.infra.waffle.containerGroupByOptions.availabilityZoneLabel',
- defaultMessage: 'Availability Zone',
- }),
- type: InfraPathType.terms,
- field: 'meta.cloud.availability_zone',
- },
- {
- text: intl.formatMessage({
- id: 'xpack.infra.waffle.containerGroupByOptions.machineTypeLabel',
- defaultMessage: 'Machine Type',
- }),
- type: InfraPathType.terms,
- field: 'meta.cloud.machine_type',
- },
- {
- text: intl.formatMessage({
- id: 'xpack.infra.waffle.containerGroupByOptions.projectIDLabel',
- defaultMessage: 'Project ID',
- }),
- type: InfraPathType.terms,
- field: 'meta.cloud.project_id',
- },
- {
- text: intl.formatMessage({
- id: 'xpack.infra.waffle.containerGroupByOptions.providerLabel',
- defaultMessage: 'Provider',
- }),
- type: InfraPathType.terms,
- field: 'meta.cloud.provider',
- },
- ],
+ 'host.name',
+ 'meta.cloud.availability_zone',
+ 'meta.cloud.machine_type',
+ 'meta.cloud.project_id',
+ 'meta.cloud.provider',
+ ].map(mapFieldToOption),
[InfraNodeType.host]: [
- {
- text: intl.formatMessage({
- id: 'xpack.infra.waffle.hostGroupByOptions.availabilityZoneLabel',
- defaultMessage: 'Availability Zone',
- }),
- type: InfraPathType.terms,
- field: 'meta.cloud.availability_zone',
- },
- {
- text: intl.formatMessage({
- id: 'xpack.infra.waffle.hostGroupByOptions.machineTypeLabel',
- defaultMessage: 'Machine Type',
- }),
- type: InfraPathType.terms,
- field: 'meta.cloud.machine_type',
- },
- {
- text: intl.formatMessage({
- id: 'xpack.infra.waffle.hostGroupByOptions.projectIDLabel',
- defaultMessage: 'Project ID',
- }),
- type: InfraPathType.terms,
- field: 'meta.cloud.project_id',
- },
- {
- text: intl.formatMessage({
- id: 'xpack.infra.waffle.hostGroupByOptions.cloudProviderLabel',
- defaultMessage: 'Cloud Provider',
- }),
- type: InfraPathType.terms,
- field: 'meta.cloud.provider',
- },
- ],
+ 'meta.cloud.availability_zone',
+ 'meta.cloud.machine_type',
+ 'meta.cloud.project_id',
+ 'meta.cloud.provider',
+ ].map(mapFieldToOption),
};
}
@@ -143,7 +77,7 @@ export const WaffleGroupByControls = injectI18n(
public render() {
const { nodeType, groupBy, intl } = this.props;
- const options = getOptions(nodeType, intl);
+ const options = getOptions(nodeType, intl).concat(this.props.customOptions);
if (!options.length) {
throw Error(
@@ -165,11 +99,35 @@ export const WaffleGroupByControls = injectI18n(
id: 'xpack.infra.waffle.selectTwoGroupingsTitle',
defaultMessage: 'Select up to two groupings',
}),
- items: options.map(o => {
- const icon = groupBy.some(g => g.field === o.field) ? 'check' : 'empty';
- const panel = { name: o.text, onClick: this.handleClick(o.field), icon };
- return panel;
+ items: [
+ {
+ name: intl.formatMessage({
+ id: 'xpack.infra.waffle.customGroupByOptionName',
+ defaultMessage: 'Custom Field',
+ }),
+ icon: 'empty',
+ panel: 'customPanel',
+ },
+ ...options.map(o => {
+ const icon = groupBy.some(g => g.field === o.field) ? 'check' : 'empty';
+ const panel = {
+ name: o.text,
+ onClick: this.handleClick(o.field),
+ icon,
+ } as EuiContextMenuPanelItemDescriptor;
+ return panel;
+ }),
+ ],
+ },
+ {
+ id: 'customPanel',
+ title: intl.formatMessage({
+ id: 'xpack.infra.waffle.customGroupByPanelTitle',
+ defaultMessage: 'Group By Custom Field',
}),
+ content: (
+
+ ),
},
];
const buttonBody =
@@ -228,6 +186,8 @@ export const WaffleGroupByControls = injectI18n(
private handleRemove = (field: string) => () => {
const { groupBy } = this.props;
this.props.onChange(groupBy.filter(g => g.field !== field));
+ const options = this.props.customOptions.filter(g => g.field !== field);
+ this.props.onChangeCustomOptions(options);
// We need to close the panel after we rmeove the pill icon otherwise
// it will remain open because the click is still captured by the EuiFilterButton
setTimeout(() => this.handleClose());
@@ -241,6 +201,20 @@ export const WaffleGroupByControls = injectI18n(
this.setState(state => ({ isPopoverOpen: !state.isPopoverOpen }));
};
+ private handleCustomField = (field: string) => {
+ const options = [
+ ...this.props.customOptions,
+ {
+ text: field,
+ field,
+ type: InfraPathType.custom,
+ },
+ ];
+ this.props.onChangeCustomOptions(options);
+ const fn = this.handleClick(field);
+ fn();
+ };
+
private handleClick = (field: string) => () => {
const { groupBy } = this.props;
if (groupBy.some(g => g.field === field)) {
diff --git a/x-pack/plugins/infra/public/containers/logs/flyout_item.gql_query.ts b/x-pack/plugins/infra/public/containers/logs/flyout_item.gql_query.ts
new file mode 100644
index 0000000000000..56b63a54b1126
--- /dev/null
+++ b/x-pack/plugins/infra/public/containers/logs/flyout_item.gql_query.ts
@@ -0,0 +1,23 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import gql from 'graphql-tag';
+
+export const flyoutItemQuery = gql`
+ query FlyoutItemQuery($sourceId: ID!, $itemId: ID!) {
+ source(id: $sourceId) {
+ id
+ logItem(id: $itemId) {
+ id
+ index
+ fields {
+ field
+ value
+ }
+ }
+ }
+ }
+`;
diff --git a/x-pack/plugins/infra/public/containers/logs/with_log_flyout.tsx b/x-pack/plugins/infra/public/containers/logs/with_log_flyout.tsx
new file mode 100644
index 0000000000000..71c0a330fcb97
--- /dev/null
+++ b/x-pack/plugins/infra/public/containers/logs/with_log_flyout.tsx
@@ -0,0 +1,60 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import React from 'react';
+import { Query } from 'react-apollo';
+import { FlyoutItemQuery, InfraLogItem } from '../../graphql/types';
+import { FlyoutVisibility } from '../../store/local/log_flyout';
+import { WithOptions } from '../with_options';
+import { flyoutItemQuery } from './flyout_item.gql_query';
+import { WithFlyoutOptions } from './with_log_flyout_options';
+
+interface WithFlyoutArgs {
+ flyoutItem: InfraLogItem | null;
+ setFlyoutItem: (id: string) => void;
+ showFlyout: () => void;
+ hideFlyout: () => void;
+ error?: string | undefined;
+ loading: boolean;
+}
+
+interface WithFlyoutProps {
+ children: (args: WithFlyoutArgs) => React.ReactNode;
+}
+
+export const WithLogFlyout = ({ children }: WithFlyoutProps) => {
+ return (
+
+ {({ sourceId }) => (
+
+ {({ showFlyout, hideFlyout, setFlyoutItem, flyoutId, flyoutVisibility }) =>
+ flyoutVisibility === FlyoutVisibility.visible ? (
+
+ query={flyoutItemQuery}
+ fetchPolicy="no-cache"
+ variables={{
+ itemId: (flyoutId != null && flyoutId) || '',
+ sourceId,
+ }}
+ >
+ {({ data, error, loading }) => {
+ return children({
+ showFlyout,
+ hideFlyout,
+ setFlyoutItem,
+ flyoutItem: (data && data.source && data.source.logItem) || null,
+ error: error && error.message,
+ loading,
+ });
+ }}
+
+ ) : null
+ }
+
+ )}
+
+ );
+};
diff --git a/x-pack/plugins/infra/public/containers/logs/with_log_flyout_options.tsx b/x-pack/plugins/infra/public/containers/logs/with_log_flyout_options.tsx
new file mode 100644
index 0000000000000..13e011cda876b
--- /dev/null
+++ b/x-pack/plugins/infra/public/containers/logs/with_log_flyout_options.tsx
@@ -0,0 +1,105 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import React from 'react';
+import { connect } from 'react-redux';
+import { createSelector } from 'reselect';
+
+import { isString } from 'lodash';
+import { flyoutOptionsActions, flyoutOptionsSelectors, State } from '../../store';
+import { FlyoutVisibility } from '../../store/local/log_flyout';
+import { asChildFunctionRenderer } from '../../utils/typed_react';
+import { bindPlainActionCreators } from '../../utils/typed_redux';
+import { UrlStateContainer } from '../../utils/url_state';
+
+const selectOptionsUrlState = createSelector(
+ flyoutOptionsSelectors.selectFlyoutId,
+ flyoutOptionsSelectors.selectFlyoutVisibility,
+ (flyoutId, flyoutVisibility) => ({
+ flyoutVisibility,
+ flyoutId,
+ })
+);
+
+export const withFlyoutOptions = connect(
+ (state: State) => ({
+ flyoutVisibility: flyoutOptionsSelectors.selectFlyoutVisibility(state),
+ flyoutId: flyoutOptionsSelectors.selectFlyoutId(state),
+ urlState: selectOptionsUrlState(state),
+ }),
+ bindPlainActionCreators({
+ setFlyoutItem: flyoutOptionsActions.setFlyoutItem,
+ showFlyout: flyoutOptionsActions.showFlyout,
+ hideFlyout: flyoutOptionsActions.hideFlyout,
+ })
+);
+
+export const WithFlyoutOptions = asChildFunctionRenderer(withFlyoutOptions);
+
+/**
+ * Url State
+ */
+
+interface FlyoutOptionsUrlState {
+ flyoutId?: ReturnType;
+ flyoutVisibility?: ReturnType;
+}
+
+export const WithFlyoutOptionsUrlState = () => (
+
+ {({ setFlyoutItem, showFlyout, hideFlyout, urlState }) => (
+ {
+ if (newUrlState && newUrlState.flyoutId) {
+ setFlyoutItem(newUrlState.flyoutId);
+ }
+ if (newUrlState && newUrlState.flyoutVisibility === FlyoutVisibility.visible) {
+ showFlyout();
+ }
+ if (newUrlState && newUrlState.flyoutVisibility === FlyoutVisibility.hidden) {
+ hideFlyout();
+ }
+ }}
+ onInitialize={initialUrlState => {
+ if (initialUrlState && initialUrlState.flyoutId) {
+ setFlyoutItem(initialUrlState.flyoutId);
+ }
+ if (initialUrlState && initialUrlState.flyoutVisibility === FlyoutVisibility.visible) {
+ showFlyout();
+ }
+ if (initialUrlState && initialUrlState.flyoutVisibility === FlyoutVisibility.hidden) {
+ hideFlyout();
+ }
+ }}
+ />
+ )}
+
+);
+
+const mapToUrlState = (value: any): FlyoutOptionsUrlState | undefined =>
+ value
+ ? {
+ flyoutId: mapToFlyoutIdState(value.flyoutId),
+ flyoutVisibility: mapToFlyoutVisibilityState(value.flyoutVisibility),
+ }
+ : undefined;
+
+const mapToFlyoutIdState = (subject: any) => {
+ return subject && isString(subject) ? subject : undefined;
+};
+const mapToFlyoutVisibilityState = (subject: any) => {
+ if (subject) {
+ if (subject === 'visible') {
+ return FlyoutVisibility.visible;
+ }
+ if (subject === 'hidden') {
+ return FlyoutVisibility.hidden;
+ }
+ }
+};
diff --git a/x-pack/plugins/infra/public/containers/waffle/nodes_to_wafflemap.ts b/x-pack/plugins/infra/public/containers/waffle/nodes_to_wafflemap.ts
index 56f2ffa0bc5d9..4e1f0152b7f4f 100644
--- a/x-pack/plugins/infra/public/containers/waffle/nodes_to_wafflemap.ts
+++ b/x-pack/plugins/infra/public/containers/waffle/nodes_to_wafflemap.ts
@@ -16,7 +16,7 @@ import {
} from '../../lib/lib';
import { isWaffleMapGroupWithGroups, isWaffleMapGroupWithNodes } from './type_guards';
-function createId(path: InfraNodePath[]) {
+export function createId(path: InfraNodePath[]) {
return path.map(p => p.value).join('/');
}
@@ -40,6 +40,7 @@ function findOrCreateGroupWithNodes(
}
}
}
+ const lastPath = last(path);
const existingGroup = groups.find(g => g.id === id);
if (isWaffleMapGroupWithNodes(existingGroup)) {
return existingGroup;
@@ -51,7 +52,7 @@ function findOrCreateGroupWithNodes(
? i18n.translate('xpack.infra.nodesToWaffleMap.groupsWithNodes.allName', {
defaultMessage: 'All',
})
- : last(path).label,
+ : (lastPath && lastPath.label) || 'Unknown Group',
count: 0,
width: 0,
squareSize: 0,
@@ -64,6 +65,7 @@ function findOrCreateGroupWithGroups(
path: InfraNodePath[]
): InfraWaffleMapGroupOfGroups {
const id = path.length === 0 ? '__all__' : createId(path);
+ const lastPath = last(path);
const existingGroup = groups.find(g => g.id === id);
if (isWaffleMapGroupWithGroups(existingGroup)) {
return existingGroup;
@@ -75,7 +77,7 @@ function findOrCreateGroupWithGroups(
? i18n.translate('xpack.infra.nodesToWaffleMap.groupsWithGroups.allName', {
defaultMessage: 'All',
})
- : last(path).label,
+ : (lastPath && lastPath.label) || 'Unknown Group',
count: 0,
width: 0,
squareSize: 0,
@@ -83,13 +85,16 @@ function findOrCreateGroupWithGroups(
};
}
-function createWaffleMapNode(node: InfraNode): InfraWaffleMapNode {
+export function createWaffleMapNode(node: InfraNode): InfraWaffleMapNode {
const nodePathItem = last(node.path);
+ if (!nodePathItem) {
+ throw new Error('There must be at least one node path item');
+ }
return {
pathId: node.path.map(p => p.value).join('/'),
path: node.path,
id: nodePathItem.value,
- name: nodePathItem.label,
+ name: nodePathItem.label || nodePathItem.value,
metric: node.metric,
};
}
diff --git a/x-pack/plugins/infra/public/containers/waffle/waffle_nodes.gql_query.ts b/x-pack/plugins/infra/public/containers/waffle/waffle_nodes.gql_query.ts
index 51b67086a4bfa..8226cf9ad9b32 100644
--- a/x-pack/plugins/infra/public/containers/waffle/waffle_nodes.gql_query.ts
+++ b/x-pack/plugins/infra/public/containers/waffle/waffle_nodes.gql_query.ts
@@ -25,6 +25,8 @@ export const waffleNodesQuery = gql`
metric {
name
value
+ avg
+ max
}
}
}
diff --git a/x-pack/plugins/infra/public/containers/waffle/with_waffle_nodes.tsx b/x-pack/plugins/infra/public/containers/waffle/with_waffle_nodes.tsx
index 2f8a18ca45ab7..b1fdd3a457a54 100644
--- a/x-pack/plugins/infra/public/containers/waffle/with_waffle_nodes.tsx
+++ b/x-pack/plugins/infra/public/containers/waffle/with_waffle_nodes.tsx
@@ -9,18 +9,17 @@ import { Query } from 'react-apollo';
import {
InfraMetricInput,
+ InfraNode,
InfraNodeType,
InfraPathInput,
InfraPathType,
InfraTimerangeInput,
WaffleNodesQuery,
} from '../../graphql/types';
-import { InfraWaffleMapGroup } from '../../lib/lib';
-import { nodesToWaffleMap } from './nodes_to_wafflemap';
import { waffleNodesQuery } from './waffle_nodes.gql_query';
interface WithWaffleNodesArgs {
- nodes: InfraWaffleMapGroup[];
+ nodes: InfraNode[];
loading: boolean;
refetch: () => void;
}
@@ -67,7 +66,7 @@ export const WithWaffleNodes = ({
loading,
nodes:
data && data.source && data.source.map && data.source.map.nodes
- ? nodesToWaffleMap(data.source.map.nodes)
+ ? data.source.map.nodes
: [],
refetch,
})
diff --git a/x-pack/plugins/infra/public/containers/waffle/with_waffle_options.tsx b/x-pack/plugins/infra/public/containers/waffle/with_waffle_options.tsx
index b03f1e003fc4b..b71cb00ed2dd4 100644
--- a/x-pack/plugins/infra/public/containers/waffle/with_waffle_options.tsx
+++ b/x-pack/plugins/infra/public/containers/waffle/with_waffle_options.tsx
@@ -14,6 +14,7 @@ import {
InfraNodeType,
InfraPathType,
} from '../../graphql/types';
+import { InfraGroupByOptions } from '../../lib/lib';
import { State, waffleOptionsActions, waffleOptionsSelectors } from '../../store';
import { asChildFunctionRenderer } from '../../utils/typed_react';
import { bindPlainActionCreators } from '../../utils/typed_redux';
@@ -21,12 +22,16 @@ import { UrlStateContainer } from '../../utils/url_state';
const selectOptionsUrlState = createSelector(
waffleOptionsSelectors.selectMetric,
+ waffleOptionsSelectors.selectView,
waffleOptionsSelectors.selectGroupBy,
waffleOptionsSelectors.selectNodeType,
- (metric, groupBy, nodeType) => ({
+ waffleOptionsSelectors.selectCustomOptions,
+ (metric, view, groupBy, nodeType, customOptions) => ({
metric,
groupBy,
nodeType,
+ view,
+ customOptions,
})
);
@@ -35,12 +40,16 @@ export const withWaffleOptions = connect(
metric: waffleOptionsSelectors.selectMetric(state),
groupBy: waffleOptionsSelectors.selectGroupBy(state),
nodeType: waffleOptionsSelectors.selectNodeType(state),
+ view: waffleOptionsSelectors.selectView(state),
+ customOptions: waffleOptionsSelectors.selectCustomOptions(state),
urlState: selectOptionsUrlState(state),
}),
bindPlainActionCreators({
changeMetric: waffleOptionsActions.changeMetric,
changeGroupBy: waffleOptionsActions.changeGroupBy,
changeNodeType: waffleOptionsActions.changeNodeType,
+ changeView: waffleOptionsActions.changeView,
+ changeCustomOptions: waffleOptionsActions.changeCustomOptions,
})
);
@@ -54,11 +63,20 @@ interface WaffleOptionsUrlState {
metric?: ReturnType;
groupBy?: ReturnType;
nodeType?: ReturnType;
+ view?: ReturnType;
+ customOptions?: ReturnType;
}
export const WithWaffleOptionsUrlState = () => (
- {({ changeMetric, urlState, changeGroupBy, changeNodeType }) => (
+ {({
+ changeMetric,
+ urlState,
+ changeGroupBy,
+ changeNodeType,
+ changeView,
+ changeCustomOptions,
+ }) => (
(
if (newUrlState && newUrlState.nodeType) {
changeNodeType(newUrlState.nodeType);
}
+ if (newUrlState && newUrlState.view) {
+ changeView(newUrlState.view);
+ }
+ if (newUrlState && newUrlState.customOptions) {
+ changeCustomOptions(newUrlState.customOptions);
+ }
}}
onInitialize={initialUrlState => {
if (initialUrlState && initialUrlState.metric) {
@@ -84,6 +108,12 @@ export const WithWaffleOptionsUrlState = () => (
if (initialUrlState && initialUrlState.nodeType) {
changeNodeType(initialUrlState.nodeType);
}
+ if (initialUrlState && initialUrlState.view) {
+ changeView(initialUrlState.view);
+ }
+ if (initialUrlState && initialUrlState.customOptions) {
+ changeCustomOptions(initialUrlState.customOptions);
+ }
}}
/>
)}
@@ -96,6 +126,8 @@ const mapToUrlState = (value: any): WaffleOptionsUrlState | undefined =>
metric: mapToMetricUrlState(value.metric),
groupBy: mapToGroupByUrlState(value.groupBy),
nodeType: mapToNodeTypeUrlState(value.nodeType),
+ view: mapToViewUrlState(value.view),
+ customOptions: mapToCustomOptionsUrlState(value.customOptions),
}
: undefined;
@@ -107,6 +139,15 @@ const isInfraPathInput = (subject: any): subject is InfraPathType => {
return subject != null && subject.type != null && InfraPathType[subject.type] != null;
};
+const isInfraGroupByOption = (subject: any): subject is InfraGroupByOptions => {
+ return (
+ subject != null &&
+ subject.text != null &&
+ subject.field != null &&
+ InfraPathType[subject.type] != null
+ );
+};
+
const mapToMetricUrlState = (subject: any) => {
return subject && isInfraMetricInput(subject) ? subject : undefined;
};
@@ -118,3 +159,13 @@ const mapToGroupByUrlState = (subject: any) => {
const mapToNodeTypeUrlState = (subject: any) => {
return subject && InfraNodeType[subject] ? subject : undefined;
};
+
+const mapToViewUrlState = (subject: any) => {
+ return subject && ['map', 'table'].includes(subject) ? subject : undefined;
+};
+
+const mapToCustomOptionsUrlState = (subject: any) => {
+ return subject && Array.isArray(subject) && subject.every(isInfraGroupByOption)
+ ? subject
+ : undefined;
+};
diff --git a/x-pack/plugins/infra/public/graphql/introspection.json b/x-pack/plugins/infra/public/graphql/introspection.json
index eb04a6d14e227..e64b567aa88ef 100644
--- a/x-pack/plugins/infra/public/graphql/introspection.json
+++ b/x-pack/plugins/infra/public/graphql/introspection.json
@@ -11,7 +11,7 @@
"fields": [
{
"name": "source",
- "description": "Get an infrastructure data source by id.\n\nThe resolution order for the source configuration attributes is as follows\nwith the first defined value winning:\n\n1. The attributes of the saved object with the given 'id'.\n2. The attributes defined in the static Kibana configuration key\n 'xpack.infra.sources.default'.\n3. The hard-coded default values.\n\nAs a consequence, querying a source without a corresponding saved object\ndoesn't error out, but returns the configured or hardcoded defaults.",
+ "description": "Get an infrastructure data source by id.\n\nThe resolution order for the source configuration attributes is as follows\nwith the first defined value winning:\n\n1. The attributes of the saved object with the given 'id'.\n2. The attributes defined in the static Kibana configuration key\n 'xpack.infra.sources.default'.\n3. The hard-coded default values.\n\nAs a consequence, querying a source that doesn't exist doesn't error out,\nbut returns the configured or hardcoded defaults.",
"args": [
{
"name": "id",
@@ -299,6 +299,29 @@
"isDeprecated": false,
"deprecationReason": null
},
+ {
+ "name": "logItem",
+ "description": "",
+ "args": [
+ {
+ "name": "id",
+ "description": "",
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null }
+ },
+ "defaultValue": null
+ }
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": { "kind": "OBJECT", "name": "InfraLogItem", "ofType": null }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
{
"name": "map",
"description": "A hierarchy of hosts, pods, containers, services or arbitrary groups",
@@ -1310,6 +1333,96 @@
"enumValues": null,
"possibleTypes": null
},
+ {
+ "kind": "OBJECT",
+ "name": "InfraLogItem",
+ "description": "",
+ "fields": [
+ {
+ "name": "id",
+ "description": "The ID of the document",
+ "args": [],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "index",
+ "description": "The index where the document was found",
+ "args": [],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": { "kind": "SCALAR", "name": "String", "ofType": null }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "fields",
+ "description": "An array of flattened fields and values",
+ "args": [],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": { "kind": "OBJECT", "name": "InfraLogItemField", "ofType": null }
+ }
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "InfraLogItemField",
+ "description": "",
+ "fields": [
+ {
+ "name": "field",
+ "description": "The flattened field name",
+ "args": [],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": { "kind": "SCALAR", "name": "String", "ofType": null }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "value",
+ "description": "The value for the Field as a string",
+ "args": [],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": { "kind": "SCALAR", "name": "String", "ofType": null }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [],
+ "enumValues": null,
+ "possibleTypes": null
+ },
{
"kind": "INPUT_OBJECT",
"name": "InfraTimerangeInput",
@@ -1480,7 +1593,8 @@
"description": "",
"isDeprecated": false,
"deprecationReason": null
- }
+ },
+ { "name": "custom", "description": "", "isDeprecated": false, "deprecationReason": null }
],
"possibleTypes": null
},
@@ -1660,6 +1774,30 @@
},
"isDeprecated": false,
"deprecationReason": null
+ },
+ {
+ "name": "avg",
+ "description": "",
+ "args": [],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": { "kind": "SCALAR", "name": "Float", "ofType": null }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "max",
+ "description": "",
+ "args": [],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": { "kind": "SCALAR", "name": "Float", "ofType": null }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
}
],
"inputFields": null,
diff --git a/x-pack/plugins/infra/public/graphql/types.ts b/x-pack/plugins/infra/public/graphql/types.ts
index eff2698106f43..d96719aef0059 100644
--- a/x-pack/plugins/infra/public/graphql/types.ts
+++ b/x-pack/plugins/infra/public/graphql/types.ts
@@ -9,7 +9,7 @@
// ====================================================
export interface Query {
- /** Get an infrastructure data source by id.The resolution order for the source configuration attributes is as followswith the first defined value winning:1. The attributes of the saved object with the given 'id'.2. The attributes defined in the static Kibana configuration key'xpack.infra.sources.default'.3. The hard-coded default values.As a consequence, querying a source without a corresponding saved objectdoesn't error out, but returns the configured or hardcoded defaults. */
+ /** Get an infrastructure data source by id.The resolution order for the source configuration attributes is as followswith the first defined value winning:1. The attributes of the saved object with the given 'id'.2. The attributes defined in the static Kibana configuration key'xpack.infra.sources.default'.3. The hard-coded default values.As a consequence, querying a source that doesn't exist doesn't error out,but returns the configured or hardcoded defaults. */
source: InfraSource;
/** Get a list of all infrastructure data sources */
allSources: InfraSource[];
@@ -34,6 +34,8 @@ export interface InfraSource {
logEntriesBetween: InfraLogEntryInterval;
/** A consecutive span of summary buckets within an interval */
logSummaryBetween: InfraLogSummaryInterval;
+
+ logItem: InfraLogItem;
/** A hierarchy of hosts, pods, containers, services or arbitrary groups */
map?: InfraResponse | null;
@@ -177,6 +179,22 @@ export interface InfraLogSummaryBucket {
entriesCount: number;
}
+export interface InfraLogItem {
+ /** The ID of the document */
+ id: string;
+ /** The index where the document was found */
+ index: string;
+ /** An array of flattened fields and values */
+ fields: InfraLogItemField[];
+}
+
+export interface InfraLogItemField {
+ /** The flattened field name */
+ field: string;
+ /** The value for the Field as a string */
+ value: string;
+}
+
export interface InfraResponse {
nodes: InfraNode[];
}
@@ -197,6 +215,10 @@ export interface InfraNodeMetric {
name: InfraMetricType;
value: number;
+
+ avg: number;
+
+ max: number;
}
export interface InfraMetricData {
@@ -395,6 +417,9 @@ export interface LogSummaryBetweenInfraSourceArgs {
/** The query to filter the log entries by */
filterQuery?: string | null;
}
+export interface LogItemInfraSourceArgs {
+ id: string;
+}
export interface MapInfraSourceArgs {
timerange: InfraTimerangeInput;
@@ -456,6 +481,7 @@ export enum InfraPathType {
hosts = 'hosts',
pods = 'pods',
containers = 'containers',
+ custom = 'custom',
}
export enum InfraMetricType {
@@ -521,6 +547,45 @@ export type InfraLogMessageSegment = InfraLogMessageFieldSegment | InfraLogMessa
// Documents
// ====================================================
+export namespace FlyoutItemQuery {
+ export type Variables = {
+ sourceId: string;
+ itemId: string;
+ };
+
+ export type Query = {
+ __typename?: 'Query';
+
+ source: Source;
+ };
+
+ export type Source = {
+ __typename?: 'InfraSource';
+
+ id: string;
+
+ logItem: LogItem;
+ };
+
+ export type LogItem = {
+ __typename?: 'InfraLogItem';
+
+ id: string;
+
+ index: string;
+
+ fields: Fields[];
+ };
+
+ export type Fields = {
+ __typename?: 'InfraLogItemField';
+
+ field: string;
+
+ value: string;
+ };
+}
+
export namespace MetadataQuery {
export type Variables = {
sourceId: string;
@@ -658,6 +723,10 @@ export namespace WaffleNodesQuery {
name: InfraMetricType;
value: number;
+
+ avg: number;
+
+ max: number;
};
}
diff --git a/x-pack/plugins/infra/public/lib/lib.ts b/x-pack/plugins/infra/public/lib/lib.ts
index 35c58c7576158..9819c55a5a281 100644
--- a/x-pack/plugins/infra/public/lib/lib.ts
+++ b/x-pack/plugins/infra/public/lib/lib.ts
@@ -15,6 +15,7 @@ import {
InfraNodeMetric,
InfraNodePath,
InfraPathInput,
+ InfraPathType,
InfraTimerangeInput,
SourceQuery,
} from '../graphql/types';
@@ -204,3 +205,9 @@ export enum InfraWaffleMapDataFormat {
bitsBinaryJEDEC = 'bitsBinaryJEDEC',
abbreviatedNumber = 'abbreviatedNumber',
}
+
+export interface InfraGroupByOptions {
+ text: string;
+ type: InfraPathType;
+ field: string;
+}
diff --git a/x-pack/plugins/infra/public/pages/home/page_content.tsx b/x-pack/plugins/infra/public/pages/home/page_content.tsx
index 2b6990a6dbe54..c409be860c062 100644
--- a/x-pack/plugins/infra/public/pages/home/page_content.tsx
+++ b/x-pack/plugins/infra/public/pages/home/page_content.tsx
@@ -6,8 +6,8 @@
import React from 'react';
+import { NodesOverview } from '../../components/nodes_overview';
import { PageContent } from '../../components/page';
-import { Waffle } from '../../components/waffle';
import { WithWaffleFilter } from '../../containers/waffle/with_waffle_filters';
import { WithWaffleNodes } from '../../containers/waffle/with_waffle_nodes';
@@ -27,7 +27,7 @@ export const HomePageContent: React.SFC = () => (
{({ currentTimeRange, isAutoReloading }) => (
- {({ metric, groupBy, nodeType }) => (
+ {({ metric, groupBy, nodeType, view, changeView }) => (
(
timerange={currentTimeRange}
>
{({ nodes, loading, refetch }) => (
- 0 && isAutoReloading ? false : loading}
nodeType={nodeType}
options={{ ...wafflemap, metric, fields: configuredFields, groupBy }}
reload={refetch}
onDrilldown={applyFilterQuery}
timeRange={currentTimeRange}
+ view={view}
+ onViewChange={changeView}
/>
)}
diff --git a/x-pack/plugins/infra/public/pages/home/toolbar.tsx b/x-pack/plugins/infra/public/pages/home/toolbar.tsx
index aa519564509cf..16ac4c0a19638 100644
--- a/x-pack/plugins/infra/public/pages/home/toolbar.tsx
+++ b/x-pack/plugins/infra/public/pages/home/toolbar.tsx
@@ -109,22 +109,41 @@ export const HomeToolbar = injectI18n(({ intl }) => (
)}
-
- {({ changeMetric, changeGroupBy, groupBy, metric, nodeType }) => (
-
-
-
-
-
-
-
-
+
+ {({ derivedIndexPattern }) => (
+
+ {({
+ changeMetric,
+ changeGroupBy,
+ changeCustomOptions,
+ customOptions,
+ groupBy,
+ metric,
+ nodeType,
+ }) => (
+
+
+
+
+
+
+
+
+ )}
+
)}
-
+
{({ currentTime, isAutoReloading, jumpToTime, startAutoReload, stopAutoReload }) => (
diff --git a/x-pack/plugins/infra/public/pages/logs/logs.tsx b/x-pack/plugins/infra/public/pages/logs/logs.tsx
index 1b45d05de2842..11c0a7f038111 100644
--- a/x-pack/plugins/infra/public/pages/logs/logs.tsx
+++ b/x-pack/plugins/infra/public/pages/logs/logs.tsx
@@ -12,10 +12,14 @@ import { LogsToolbar } from './toolbar';
import { EmptyPage } from '../../components/empty_page';
import { Header } from '../../components/header';
+import { LogFlyout } from '../../components/logging/log_flyout';
import { ColumnarPage } from '../../components/page';
import { InfraHeaderFeedbackLink } from '../../components/header_feedback_link';
-import { WithLogFilterUrlState } from '../../containers/logs/with_log_filter';
+import { WithLogFilter, WithLogFilterUrlState } from '../../containers/logs/with_log_filter';
+import { WithLogFlyout } from '../../containers/logs/with_log_flyout';
+import { WithFlyoutOptions } from '../../containers/logs/with_log_flyout_options';
+import { WithFlyoutOptionsUrlState } from '../../containers/logs/with_log_flyout_options';
import { WithLogMinimapUrlState } from '../../containers/logs/with_log_minimap';
import { WithLogPositionUrlState } from '../../containers/logs/with_log_position';
import { WithLogTextviewUrlState } from '../../containers/logs/with_log_textview';
@@ -61,8 +65,32 @@ export const LogsPage = injectI18n(
+
-
+
+ {({ applyFilterQueryFromKueryExpression }) => (
+
+
+ {({ showFlyout, setFlyoutItem }) => (
+
+ )}
+
+
+ {({ flyoutItem, hideFlyout, loading }) => (
+
+ )}
+
+
+ )}
+
>
) : isLoading ? (
diff --git a/x-pack/plugins/infra/public/pages/logs/page_content.tsx b/x-pack/plugins/infra/public/pages/logs/page_content.tsx
index e2efd2f1a333a..2ca93a310323a 100644
--- a/x-pack/plugins/infra/public/pages/logs/page_content.tsx
+++ b/x-pack/plugins/infra/public/pages/logs/page_content.tsx
@@ -17,7 +17,12 @@ import { WithLogTextview } from '../../containers/logs/with_log_textview';
import { WithStreamItems } from '../../containers/logs/with_stream_items';
import { WithSummary } from '../../containers/logs/with_summary';
-export const LogsPageContent: React.SFC = () => (
+interface Props {
+ setFlyoutItem: (id: string) => void;
+ showFlyout: () => void;
+}
+
+export const LogsPageContent: React.SFC = ({ showFlyout, setFlyoutItem }) => (
{({ measureRef, content: { width = 0, height = 0 } }) => (
@@ -57,6 +62,8 @@ export const LogsPageContent: React.SFC = () => (
target={targetPosition}
width={width}
wrap={wrap}
+ setFlyoutItem={setFlyoutItem}
+ showFlyout={showFlyout}
/>
)}
diff --git a/x-pack/plugins/infra/public/store/actions.ts b/x-pack/plugins/infra/public/store/actions.ts
index ee9a2858f1c34..68a20f4dba98f 100644
--- a/x-pack/plugins/infra/public/store/actions.ts
+++ b/x-pack/plugins/infra/public/store/actions.ts
@@ -13,5 +13,6 @@ export {
waffleFilterActions,
waffleTimeActions,
waffleOptionsActions,
+ flyoutOptionsActions,
} from './local';
export { logEntriesActions, logSummaryActions } from './remote';
diff --git a/x-pack/plugins/infra/public/store/local/actions.ts b/x-pack/plugins/infra/public/store/local/actions.ts
index 8b9e0c9f5b58a..ef988c9b956a0 100644
--- a/x-pack/plugins/infra/public/store/local/actions.ts
+++ b/x-pack/plugins/infra/public/store/local/actions.ts
@@ -12,3 +12,4 @@ export { metricTimeActions } from './metric_time';
export { waffleFilterActions } from './waffle_filter';
export { waffleTimeActions } from './waffle_time';
export { waffleOptionsActions } from './waffle_options';
+export { flyoutOptionsActions } from './log_flyout';
diff --git a/x-pack/plugins/infra/public/store/local/log_flyout/actions.ts b/x-pack/plugins/infra/public/store/local/log_flyout/actions.ts
new file mode 100644
index 0000000000000..f0d75030dce1f
--- /dev/null
+++ b/x-pack/plugins/infra/public/store/local/log_flyout/actions.ts
@@ -0,0 +1,11 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import actionCreatorFactory from 'typescript-fsa';
+const actionCreator = actionCreatorFactory('x-pack/infra/local/log_flyout');
+export const setFlyoutItem = actionCreator('SET_FLYOUT_ITEM');
+export const showFlyout = actionCreator('SHOW_FLYOUT');
+export const hideFlyout = actionCreator('HIDE_FLYOUT');
diff --git a/x-pack/plugins/infra/public/store/local/log_flyout/index.ts b/x-pack/plugins/infra/public/store/local/log_flyout/index.ts
new file mode 100644
index 0000000000000..8dda5c3890ce6
--- /dev/null
+++ b/x-pack/plugins/infra/public/store/local/log_flyout/index.ts
@@ -0,0 +1,11 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import * as flyoutOptionsActions from './actions';
+import * as flyoutOptionsSelectors from './selector';
+
+export { flyoutOptionsActions, flyoutOptionsSelectors };
+export * from './reducer';
diff --git a/x-pack/plugins/infra/public/store/local/log_flyout/reducer.ts b/x-pack/plugins/infra/public/store/local/log_flyout/reducer.ts
new file mode 100644
index 0000000000000..695dc5e7d49b7
--- /dev/null
+++ b/x-pack/plugins/infra/public/store/local/log_flyout/reducer.ts
@@ -0,0 +1,39 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import { combineReducers } from 'redux';
+import { reducerWithInitialState } from 'typescript-fsa-reducers';
+
+import { hideFlyout, setFlyoutItem, showFlyout } from './actions';
+
+export enum FlyoutVisibility {
+ hidden = 'hidden',
+ visible = 'visible',
+}
+
+export interface FlyoutOptionsState {
+ visibility: FlyoutVisibility;
+ itemId: string;
+}
+
+export const initialFlyoutOptionsState: FlyoutOptionsState = {
+ visibility: FlyoutVisibility.hidden,
+ itemId: '',
+};
+
+const currentFlyoutReducer = reducerWithInitialState(initialFlyoutOptionsState.itemId).case(
+ setFlyoutItem,
+ (current, target) => target
+);
+
+const currentFlyoutVisibilityReducer = reducerWithInitialState(initialFlyoutOptionsState.visibility)
+ .case(hideFlyout, () => FlyoutVisibility.hidden)
+ .case(showFlyout, () => FlyoutVisibility.visible);
+
+export const flyoutOptionsReducer = combineReducers({
+ itemId: currentFlyoutReducer,
+ visibility: currentFlyoutVisibilityReducer,
+});
diff --git a/x-pack/plugins/infra/public/store/local/log_flyout/selector.ts b/x-pack/plugins/infra/public/store/local/log_flyout/selector.ts
new file mode 100644
index 0000000000000..5024290b7bdc7
--- /dev/null
+++ b/x-pack/plugins/infra/public/store/local/log_flyout/selector.ts
@@ -0,0 +1,10 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import { FlyoutOptionsState } from './reducer';
+
+export const selectFlyoutId = (state: FlyoutOptionsState) => state.itemId;
+export const selectFlyoutVisibility = (state: FlyoutOptionsState) => state.visibility;
diff --git a/x-pack/plugins/infra/public/store/local/reducer.ts b/x-pack/plugins/infra/public/store/local/reducer.ts
index 59e890b748d5e..d7cff2f004f3f 100644
--- a/x-pack/plugins/infra/public/store/local/reducer.ts
+++ b/x-pack/plugins/infra/public/store/local/reducer.ts
@@ -7,6 +7,7 @@
import { combineReducers } from 'redux';
import { initialLogFilterState, logFilterReducer, LogFilterState } from './log_filter';
+import { flyoutOptionsReducer, FlyoutOptionsState, initialFlyoutOptionsState } from './log_flyout';
import { initialLogMinimapState, logMinimapReducer, LogMinimapState } from './log_minimap';
import { initialLogPositionState, logPositionReducer, LogPositionState } from './log_position';
import { initialLogTextviewState, logTextviewReducer, LogTextviewState } from './log_textview';
@@ -28,6 +29,7 @@ export interface LocalState {
waffleFilter: WaffleFilterState;
waffleTime: WaffleTimeState;
waffleMetrics: WaffleOptionsState;
+ logFlyout: FlyoutOptionsState;
}
export const initialLocalState: LocalState = {
@@ -39,6 +41,7 @@ export const initialLocalState: LocalState = {
waffleFilter: initialWaffleFilterState,
waffleTime: initialWaffleTimeState,
waffleMetrics: initialWaffleOptionsState,
+ logFlyout: initialFlyoutOptionsState,
};
export const localReducer = combineReducers({
@@ -50,4 +53,5 @@ export const localReducer = combineReducers({
waffleFilter: waffleFilterReducer,
waffleTime: waffleTimeReducer,
waffleMetrics: waffleOptionsReducer,
+ logFlyout: flyoutOptionsReducer,
});
diff --git a/x-pack/plugins/infra/public/store/local/selectors.ts b/x-pack/plugins/infra/public/store/local/selectors.ts
index 85188e144ade1..46e6fbafb686e 100644
--- a/x-pack/plugins/infra/public/store/local/selectors.ts
+++ b/x-pack/plugins/infra/public/store/local/selectors.ts
@@ -6,6 +6,7 @@
import { globalizeSelectors } from '../../utils/typed_redux';
import { logFilterSelectors as innerLogFilterSelectors } from './log_filter';
+import { flyoutOptionsSelectors as innerFlyoutOptionsSelectors } from './log_flyout';
import { logMinimapSelectors as innerLogMinimapSelectors } from './log_minimap';
import { logPositionSelectors as innerLogPositionSelectors } from './log_position';
import { logTextviewSelectors as innerLogTextviewSelectors } from './log_textview';
@@ -54,3 +55,8 @@ export const waffleOptionsSelectors = globalizeSelectors(
(state: LocalState) => state.waffleMetrics,
innerWaffleOptionsSelectors
);
+
+export const flyoutOptionsSelectors = globalizeSelectors(
+ (state: LocalState) => state.logFlyout,
+ innerFlyoutOptionsSelectors
+);
diff --git a/x-pack/plugins/infra/public/store/local/waffle_options/actions.ts b/x-pack/plugins/infra/public/store/local/waffle_options/actions.ts
index 229b915db07db..5ef315e4b36d8 100644
--- a/x-pack/plugins/infra/public/store/local/waffle_options/actions.ts
+++ b/x-pack/plugins/infra/public/store/local/waffle_options/actions.ts
@@ -5,11 +5,13 @@
*/
import actionCreatorFactory from 'typescript-fsa';
-
import { InfraMetricInput, InfraNodeType, InfraPathInput } from '../../../graphql/types';
+import { InfraGroupByOptions } from '../../../lib/lib';
const actionCreator = actionCreatorFactory('x-pack/infra/local/waffle_options');
export const changeMetric = actionCreator('CHANGE_METRIC');
export const changeGroupBy = actionCreator('CHANGE_GROUP_BY');
+export const changeCustomOptions = actionCreator('CHANGE_CUSTOM_OPTIONS');
export const changeNodeType = actionCreator('CHANGE_NODE_TYPE');
+export const changeView = actionCreator('CHANGE_VIEW');
diff --git a/x-pack/plugins/infra/public/store/local/waffle_options/reducer.ts b/x-pack/plugins/infra/public/store/local/waffle_options/reducer.ts
index f474462245f4d..d778eee60afb7 100644
--- a/x-pack/plugins/infra/public/store/local/waffle_options/reducer.ts
+++ b/x-pack/plugins/infra/public/store/local/waffle_options/reducer.ts
@@ -13,18 +13,29 @@ import {
InfraNodeType,
InfraPathInput,
} from '../../../graphql/types';
-import { changeGroupBy, changeMetric, changeNodeType } from './actions';
+import { InfraGroupByOptions } from '../../../lib/lib';
+import {
+ changeCustomOptions,
+ changeGroupBy,
+ changeMetric,
+ changeNodeType,
+ changeView,
+} from './actions';
export interface WaffleOptionsState {
metric: InfraMetricInput;
groupBy: InfraPathInput[];
nodeType: InfraNodeType;
+ view: string;
+ customOptions: InfraGroupByOptions[];
}
export const initialWaffleOptionsState: WaffleOptionsState = {
metric: { type: InfraMetricType.cpu },
groupBy: [],
nodeType: InfraNodeType.host,
+ view: 'map',
+ customOptions: [],
};
const currentMetricReducer = reducerWithInitialState(initialWaffleOptionsState.metric).case(
@@ -32,6 +43,10 @@ const currentMetricReducer = reducerWithInitialState(initialWaffleOptionsState.m
(current, target) => target
);
+const currentCustomOptionsReducer = reducerWithInitialState(
+ initialWaffleOptionsState.customOptions
+).case(changeCustomOptions, (current, target) => target);
+
const currentGroupByReducer = reducerWithInitialState(initialWaffleOptionsState.groupBy).case(
changeGroupBy,
(current, target) => target
@@ -42,8 +57,15 @@ const currentNodeTypeReducer = reducerWithInitialState(initialWaffleOptionsState
(current, target) => target
);
+const currentViewReducer = reducerWithInitialState(initialWaffleOptionsState.view).case(
+ changeView,
+ (current, target) => target
+);
+
export const waffleOptionsReducer = combineReducers({
metric: currentMetricReducer,
groupBy: currentGroupByReducer,
nodeType: currentNodeTypeReducer,
+ view: currentViewReducer,
+ customOptions: currentCustomOptionsReducer,
});
diff --git a/x-pack/plugins/infra/public/store/local/waffle_options/selector.ts b/x-pack/plugins/infra/public/store/local/waffle_options/selector.ts
index 6889cd6150ab7..d5ee4c2071539 100644
--- a/x-pack/plugins/infra/public/store/local/waffle_options/selector.ts
+++ b/x-pack/plugins/infra/public/store/local/waffle_options/selector.ts
@@ -8,4 +8,6 @@ import { WaffleOptionsState } from './reducer';
export const selectMetric = (state: WaffleOptionsState) => state.metric;
export const selectGroupBy = (state: WaffleOptionsState) => state.groupBy;
+export const selectCustomOptions = (state: WaffleOptionsState) => state.customOptions;
export const selectNodeType = (state: WaffleOptionsState) => state.nodeType;
+export const selectView = (state: WaffleOptionsState) => state.view;
diff --git a/x-pack/plugins/infra/public/store/selectors.ts b/x-pack/plugins/infra/public/store/selectors.ts
index a604580376ce3..8a2c96cb01039 100644
--- a/x-pack/plugins/infra/public/store/selectors.ts
+++ b/x-pack/plugins/infra/public/store/selectors.ts
@@ -9,6 +9,7 @@ import { createSelector } from 'reselect';
import { getLogEntryAtTime } from '../utils/log_entry';
import { globalizeSelectors } from '../utils/typed_redux';
import {
+ flyoutOptionsSelectors as localFlyoutOptionsSelectors,
logFilterSelectors as localLogFilterSelectors,
logMinimapSelectors as localLogMinimapSelectors,
logPositionSelectors as localLogPositionSelectors,
@@ -38,6 +39,7 @@ export const metricTimeSelectors = globalizeSelectors(selectLocal, localMetricTi
export const waffleFilterSelectors = globalizeSelectors(selectLocal, localWaffleFilterSelectors);
export const waffleTimeSelectors = globalizeSelectors(selectLocal, localWaffleTimeSelectors);
export const waffleOptionsSelectors = globalizeSelectors(selectLocal, localWaffleOptionsSelectors);
+export const flyoutOptionsSelectors = globalizeSelectors(selectLocal, localFlyoutOptionsSelectors);
/**
* remote selectors
diff --git a/x-pack/plugins/infra/server/graphql/log_entries/resolvers.ts b/x-pack/plugins/infra/server/graphql/log_entries/resolvers.ts
index 8a0dd691f9978..0c7049c1895a4 100644
--- a/x-pack/plugins/infra/server/graphql/log_entries/resolvers.ts
+++ b/x-pack/plugins/infra/server/graphql/log_entries/resolvers.ts
@@ -31,6 +31,11 @@ export type InfraSourceLogSummaryBetweenResolver = ChildResolverOf<
QuerySourceResolver
>;
+export type InfraSourceLogItem = ChildResolverOf<
+ InfraResolverOf,
+ QuerySourceResolver
+>;
+
export const createLogEntriesResolvers = (libs: {
logEntries: InfraLogEntriesDomain;
}): {
@@ -38,6 +43,7 @@ export const createLogEntriesResolvers = (libs: {
logEntriesAround: InfraSourceLogEntriesAroundResolver;
logEntriesBetween: InfraSourceLogEntriesBetweenResolver;
logSummaryBetween: InfraSourceLogSummaryBetweenResolver;
+ logItem: InfraSourceLogItem;
};
InfraLogMessageSegment: {
__resolveType(
@@ -115,6 +121,9 @@ export const createLogEntriesResolvers = (libs: {
buckets,
};
},
+ async logItem(source, args, { req }) {
+ return await libs.logEntries.getLogItem(req, args.id, source.configuration);
+ },
},
InfraLogMessageSegment: {
__resolveType: (messageSegment: InfraLogMessageSegment) => {
diff --git a/x-pack/plugins/infra/server/graphql/log_entries/schema.gql.ts b/x-pack/plugins/infra/server/graphql/log_entries/schema.gql.ts
index e4947767ffbb1..302b5a374b524 100644
--- a/x-pack/plugins/infra/server/graphql/log_entries/schema.gql.ts
+++ b/x-pack/plugins/infra/server/graphql/log_entries/schema.gql.ts
@@ -78,6 +78,22 @@ export const logEntriesSchema = gql`
buckets: [InfraLogSummaryBucket!]!
}
+ type InfraLogItemField {
+ "The flattened field name"
+ field: String!
+ "The value for the Field as a string"
+ value: String!
+ }
+
+ type InfraLogItem {
+ "The ID of the document"
+ id: ID!
+ "The index where the document was found"
+ index: String!
+ "An array of flattened fields and values"
+ fields: [InfraLogItemField!]!
+ }
+
extend type InfraSource {
"A consecutive span of log entries surrounding a point in time"
logEntriesAround(
@@ -114,5 +130,6 @@ export const logEntriesSchema = gql`
"The query to filter the log entries by"
filterQuery: String
): InfraLogSummaryInterval!
+ logItem(id: ID!): InfraLogItem!
}
`;
diff --git a/x-pack/plugins/infra/server/graphql/nodes/schema.gql.ts b/x-pack/plugins/infra/server/graphql/nodes/schema.gql.ts
index b8002963925c3..b1b9b57392054 100644
--- a/x-pack/plugins/infra/server/graphql/nodes/schema.gql.ts
+++ b/x-pack/plugins/infra/server/graphql/nodes/schema.gql.ts
@@ -10,6 +10,8 @@ export const nodesSchema: any = gql`
type InfraNodeMetric {
name: InfraMetricType!
value: Float!
+ avg: Float!
+ max: Float!
}
type InfraNodePath {
@@ -60,6 +62,7 @@ export const nodesSchema: any = gql`
hosts
pods
containers
+ custom
}
input InfraPathInput {
diff --git a/x-pack/plugins/infra/server/graphql/types.ts b/x-pack/plugins/infra/server/graphql/types.ts
index 84c4eb3518fa0..6933202633856 100644
--- a/x-pack/plugins/infra/server/graphql/types.ts
+++ b/x-pack/plugins/infra/server/graphql/types.ts
@@ -37,7 +37,7 @@ export type SubscriptionResolver {
- /** Get an infrastructure data source by id.The resolution order for the source configuration attributes is as followswith the first defined value winning:1. The attributes of the saved object with the given 'id'.2. The attributes defined in the static Kibana configuration key'xpack.infra.sources.default'.3. The hard-coded default values.As a consequence, querying a source without a corresponding saved objectdoesn't error out, but returns the configured or hardcoded defaults. */
+ /** Get an infrastructure data source by id.The resolution order for the source configuration attributes is as followswith the first defined value winning:1. The attributes of the saved object with the given 'id'.2. The attributes defined in the static Kibana configuration key'xpack.infra.sources.default'.3. The hard-coded default values.As a consequence, querying a source that doesn't exist doesn't error out,but returns the configured or hardcoded defaults. */
source?: SourceResolver;
/** Get a list of all infrastructure data sources */
allSources?: AllSourcesResolver;
@@ -595,6 +621,8 @@ export namespace InfraSourceResolvers {
logEntriesBetween?: LogEntriesBetweenResolver;
/** A consecutive span of summary buckets within an interval */
logSummaryBetween?: LogSummaryBetweenResolver;
+
+ logItem?: LogItemResolver;
/** A hierarchy of hosts, pods, containers, services or arbitrary groups */
map?: MapResolver;
@@ -687,6 +715,15 @@ export namespace InfraSourceResolvers {
filterQuery?: string | null;
}
+ export type LogItemResolver<
+ R = InfraLogItem,
+ Parent = InfraSource,
+ Context = InfraContext
+ > = Resolver;
+ export interface LogItemArgs {
+ id: string;
+ }
+
export type MapResolver<
R = InfraResponse | null,
Parent = InfraSource,
@@ -1143,6 +1180,53 @@ export namespace InfraLogSummaryBucketResolvers {
> = Resolver;
}
+export namespace InfraLogItemResolvers {
+ export interface Resolvers {
+ /** The ID of the document */
+ id?: IdResolver;
+ /** The index where the document was found */
+ index?: IndexResolver;
+ /** An array of flattened fields and values */
+ fields?: FieldsResolver;
+ }
+
+ export type IdResolver = Resolver<
+ R,
+ Parent,
+ Context
+ >;
+ export type IndexResolver = Resolver<
+ R,
+ Parent,
+ Context
+ >;
+ export type FieldsResolver<
+ R = InfraLogItemField[],
+ Parent = InfraLogItem,
+ Context = InfraContext
+ > = Resolver;
+}
+
+export namespace InfraLogItemFieldResolvers {
+ export interface Resolvers {
+ /** The flattened field name */
+ field?: FieldResolver;
+ /** The value for the Field as a string */
+ value?: ValueResolver;
+ }
+
+ export type FieldResolver<
+ R = string,
+ Parent = InfraLogItemField,
+ Context = InfraContext
+ > = Resolver;
+ export type ValueResolver<
+ R = string,
+ Parent = InfraLogItemField,
+ Context = InfraContext
+ > = Resolver;
+}
+
export namespace InfraResponseResolvers {
export interface Resolvers {
nodes?: NodesResolver;
@@ -1203,6 +1287,10 @@ export namespace InfraNodeMetricResolvers {
name?: NameResolver;
value?: ValueResolver;
+
+ avg?: AvgResolver;
+
+ max?: MaxResolver;
}
export type NameResolver<
@@ -1215,6 +1303,16 @@ export namespace InfraNodeMetricResolvers {
Parent = InfraNodeMetric,
Context = InfraContext
> = Resolver;
+ export type AvgResolver = Resolver<
+ R,
+ Parent,
+ Context
+ >;
+ export type MaxResolver = Resolver<
+ R,
+ Parent,
+ Context
+ >;
}
export namespace InfraMetricDataResolvers {
diff --git a/x-pack/plugins/infra/server/lib/adapters/log_entries/kibana_log_entries_adapter.ts b/x-pack/plugins/infra/server/lib/adapters/log_entries/kibana_log_entries_adapter.ts
index f08cfe8f5ca0e..56126c0dd8064 100644
--- a/x-pack/plugins/infra/server/lib/adapters/log_entries/kibana_log_entries_adapter.ts
+++ b/x-pack/plugins/infra/server/lib/adapters/log_entries/kibana_log_entries_adapter.ts
@@ -5,10 +5,12 @@
*/
import { timeMilliseconds } from 'd3-time';
+import first from 'lodash/fp/first';
import get from 'lodash/fp/get';
import has from 'lodash/fp/has';
import zip from 'lodash/fp/zip';
+import { JsonObject } from 'x-pack/plugins/infra/common/typed_json';
import { compareTimeKeys, isTimeKey, TimeKey } from '../../../../common/time';
import {
LogEntriesAdapter,
@@ -28,6 +30,12 @@ const DAY_MILLIS = 24 * 60 * 60 * 1000;
const LOOKUP_OFFSETS = [0, 1, 7, 30, 365, 10000, Infinity].map(days => days * DAY_MILLIS);
const TIMESTAMP_FORMAT = 'epoch_millis';
+interface LogItemHit {
+ _index: string;
+ _id: string;
+ _source: JsonObject;
+}
+
export class InfraKibanaLogEntriesAdapter implements LogEntriesAdapter {
constructor(private readonly framework: InfraBackendFrameworkAdapter) {}
@@ -152,6 +160,35 @@ export class InfraKibanaLogEntriesAdapter implements LogEntriesAdapter {
: [];
}
+ public async getLogItem(
+ request: InfraFrameworkRequest,
+ id: string,
+ sourceConfiguration: InfraSourceConfiguration
+ ) {
+ const search = (searchOptions: object) =>
+ this.framework.callWithRequest(request, 'search', searchOptions);
+
+ const params = {
+ index: sourceConfiguration.logAlias,
+ terminate_after: 1,
+ body: {
+ size: 1,
+ query: {
+ ids: {
+ values: [id],
+ },
+ },
+ },
+ };
+
+ const response = await search(params);
+ const document = first(response.hits.hits);
+ if (!document) {
+ throw new Error('Document not found');
+ }
+ return document;
+ }
+
private async getLogEntryDocumentsBetween(
request: InfraFrameworkRequest,
sourceConfiguration: InfraSourceConfiguration,
diff --git a/x-pack/plugins/infra/server/lib/adapters/nodes/lib/create_node_item.ts b/x-pack/plugins/infra/server/lib/adapters/nodes/lib/create_node_item.ts
index 5a5bdabdfdedc..7c02b2d61b3ec 100644
--- a/x-pack/plugins/infra/server/lib/adapters/nodes/lib/create_node_item.ts
+++ b/x-pack/plugins/infra/server/lib/adapters/nodes/lib/create_node_item.ts
@@ -4,11 +4,10 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import { get, last } from 'lodash';
-import { isNumber } from 'lodash';
+import { get, isNumber, last, max, sum } from 'lodash';
import moment from 'moment';
-import { InfraNode, InfraNodeMetric } from '../../../../graphql/types';
+import { InfraMetricType, InfraNode, InfraNodeMetric } from '../../../../graphql/types';
import { InfraBucket, InfraNodeRequestOptions } from '../adapter_types';
import { NAME_FIELDS } from '../constants';
import { getBucketSizeInSeconds } from './get_bucket_size_in_seconds';
@@ -34,6 +33,21 @@ const findLastFullBucket = (
}, last(buckets));
};
+const getMetricValueFromBucket = (type: InfraMetricType) => (bucket: InfraBucket) => {
+ const metric = bucket[type];
+ return (metric && (metric.normalized_value || metric.value)) || 0;
+};
+
+function calculateMax(bucket: InfraBucket, type: InfraMetricType) {
+ const { buckets } = bucket.timeseries;
+ return max(buckets.map(getMetricValueFromBucket(type))) || 0;
+}
+
+function calculateAvg(bucket: InfraBucket, type: InfraMetricType) {
+ const { buckets } = bucket.timeseries;
+ return sum(buckets.map(getMetricValueFromBucket(type))) / buckets.length || 0;
+}
+
function createNodeMetrics(
options: InfraNodeRequestOptions,
node: InfraBucket,
@@ -45,11 +59,11 @@ function createNodeMetrics(
if (!lastBucket) {
throw new Error('Date histogram returned an empty set of buckets.');
}
- const metricObj = lastBucket[metric.type];
- const value = (metricObj && (metricObj.normalized_value || metricObj.value)) || 0;
return {
name: metric.type,
- value,
+ value: getMetricValueFromBucket(metric.type)(lastBucket),
+ max: calculateMax(bucket, metric.type),
+ avg: calculateAvg(bucket, metric.type),
};
}
diff --git a/x-pack/plugins/infra/server/lib/adapters/nodes/lib/extract_group_paths.ts b/x-pack/plugins/infra/server/lib/adapters/nodes/lib/extract_group_paths.ts
index 1ea42536b86a9..7e1a7857ced34 100644
--- a/x-pack/plugins/infra/server/lib/adapters/nodes/lib/extract_group_paths.ts
+++ b/x-pack/plugins/infra/server/lib/adapters/nodes/lib/extract_group_paths.ts
@@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import { InfraNode, InfraPathInput } from '../../../../graphql/types';
+import { InfraNode, InfraNodePath, InfraPathInput } from '../../../../graphql/types';
import { InfraBucket, InfraNodeRequestOptions } from '../adapter_types';
import { createNodeItem } from './create_node_item';
@@ -27,10 +27,11 @@ export function extractGroupPaths(
bucket.path_1.buckets.map(
(b: InfraBucket): InfraNode => {
const innerNode = createNodeItem(options, node, b);
- const nodePath = [
+ const groupPaths: InfraNodePath[] = [
{ value: bucket.key.toString(), label: bucket.key.toString() },
{ value: b.key.toString(), label: b.key.toString() },
- ].concat(innerNode.path);
+ ];
+ const nodePath = groupPaths.concat(innerNode.path);
return {
...innerNode,
path: nodePath,
@@ -40,7 +41,8 @@ export function extractGroupPaths(
);
}
const nodeItem = createNodeItem(options, node, bucket);
- const path = [{ value: key, label: key }].concat(nodeItem.path);
+ const currentPath: InfraNodePath[] = [{ value: key, label: key }];
+ const path = currentPath.concat(nodeItem.path);
return acc.concat({
...nodeItem,
path,
diff --git a/x-pack/plugins/infra/server/lib/adapters/nodes/processors/last/date_histogram_processor.ts b/x-pack/plugins/infra/server/lib/adapters/nodes/processors/last/date_histogram_processor.ts
index 31ef88ed3229c..df63cf4234645 100644
--- a/x-pack/plugins/infra/server/lib/adapters/nodes/processors/last/date_histogram_processor.ts
+++ b/x-pack/plugins/infra/server/lib/adapters/nodes/processors/last/date_histogram_processor.ts
@@ -5,7 +5,6 @@
*/
import { cloneDeep, set } from 'lodash';
-import moment from 'moment';
import { InfraESSearchBody, InfraProcesorRequestOptions } from '../../adapter_types';
import { createBasePath } from '../../lib/create_base_path';
import { getBucketSizeInSeconds } from '../../lib/get_bucket_size_in_seconds';
@@ -24,10 +23,6 @@ export const dateHistogramProcessor = (options: InfraProcesorRequestOptions) =>
const result = cloneDeep(doc);
const { timerange, sourceConfiguration, groupBy } = options.nodeOptions;
const bucketSizeInSeconds = getBucketSizeInSeconds(timerange.interval);
- const boundsMin = moment
- .utc(timerange.from)
- .subtract(5 * bucketSizeInSeconds, 's')
- .valueOf();
const path = createBasePath(groupBy).concat('timeseries');
const bucketOffset = calculateOffsetInSeconds(timerange.from, bucketSizeInSeconds);
const offset = `${Math.floor(bucketOffset)}s`;
@@ -38,7 +33,7 @@ export const dateHistogramProcessor = (options: InfraProcesorRequestOptions) =>
min_doc_count: 0,
offset,
extended_bounds: {
- min: boundsMin,
+ min: timerange.from,
max: timerange.to,
},
},
diff --git a/x-pack/plugins/infra/server/lib/domains/log_entries_domain/convert_document_source_to_log_item_fields.test.ts b/x-pack/plugins/infra/server/lib/domains/log_entries_domain/convert_document_source_to_log_item_fields.test.ts
new file mode 100644
index 0000000000000..d46ebbb26fbb8
--- /dev/null
+++ b/x-pack/plugins/infra/server/lib/domains/log_entries_domain/convert_document_source_to_log_item_fields.test.ts
@@ -0,0 +1,67 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import { convertDocumentSourceToLogItemFields } from './convert_document_source_to_log_item_fields';
+
+describe('convertDocumentSourceToLogItemFields', () => {
+ test('should convert document', () => {
+ const doc = {
+ agent: {
+ hostname: 'demo-stack-client-01',
+ id: '7adef8b6-2ab7-45cd-a0d5-b3baad735f1b',
+ type: 'filebeat',
+ ephemeral_id: 'a0c8164b-3564-4e32-b0bf-f4db5a7ae566',
+ version: '7.0.0',
+ },
+ tags: ['prod', 'web'],
+ metadata: [{ key: 'env', value: 'prod' }, { key: 'stack', value: 'web' }],
+ host: {
+ hostname: 'packer-virtualbox-iso-1546820004',
+ name: 'demo-stack-client-01',
+ },
+ };
+
+ const fields = convertDocumentSourceToLogItemFields(doc);
+ expect(fields).toEqual([
+ {
+ field: 'agent.hostname',
+ value: 'demo-stack-client-01',
+ },
+ {
+ field: 'agent.id',
+ value: '7adef8b6-2ab7-45cd-a0d5-b3baad735f1b',
+ },
+ {
+ field: 'agent.type',
+ value: 'filebeat',
+ },
+ {
+ field: 'agent.ephemeral_id',
+ value: 'a0c8164b-3564-4e32-b0bf-f4db5a7ae566',
+ },
+ {
+ field: 'agent.version',
+ value: '7.0.0',
+ },
+ {
+ field: 'tags',
+ value: '["prod","web"]',
+ },
+ {
+ field: 'metadata',
+ value: '[{"key":"env","value":"prod"},{"key":"stack","value":"web"}]',
+ },
+ {
+ field: 'host.hostname',
+ value: 'packer-virtualbox-iso-1546820004',
+ },
+ {
+ field: 'host.name',
+ value: 'demo-stack-client-01',
+ },
+ ]);
+ });
+});
diff --git a/x-pack/plugins/infra/server/lib/domains/log_entries_domain/convert_document_source_to_log_item_fields.ts b/x-pack/plugins/infra/server/lib/domains/log_entries_domain/convert_document_source_to_log_item_fields.ts
new file mode 100644
index 0000000000000..923c0c22211fe
--- /dev/null
+++ b/x-pack/plugins/infra/server/lib/domains/log_entries_domain/convert_document_source_to_log_item_fields.ts
@@ -0,0 +1,36 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import { isArray, isPlainObject } from 'lodash';
+import { JsonObject } from 'x-pack/plugins/infra/common/typed_json';
+import { InfraLogItemField } from '../../../graphql/types';
+
+const isJsonObject = (subject: any): subject is JsonObject => {
+ return isPlainObject(subject);
+};
+
+const serializeValue = (value: any): string => {
+ if (isArray(value) || isPlainObject(value)) {
+ return JSON.stringify(value);
+ }
+ return `${value}`;
+};
+
+export const convertDocumentSourceToLogItemFields = (
+ source: JsonObject,
+ path: string[] = [],
+ fields: InfraLogItemField[] = []
+): InfraLogItemField[] => {
+ return Object.keys(source).reduce((acc, key) => {
+ const value = source[key];
+ const nextPath = [...path, key];
+ if (isJsonObject(value)) {
+ return convertDocumentSourceToLogItemFields(value, nextPath, acc);
+ }
+ const field = { field: nextPath.join('.'), value: serializeValue(value) };
+ return [...acc, field];
+ }, fields);
+};
diff --git a/x-pack/plugins/infra/server/lib/domains/log_entries_domain/log_entries_domain.ts b/x-pack/plugins/infra/server/lib/domains/log_entries_domain/log_entries_domain.ts
index 5781ca3ad8ef8..e605efc105617 100644
--- a/x-pack/plugins/infra/server/lib/domains/log_entries_domain/log_entries_domain.ts
+++ b/x-pack/plugins/infra/server/lib/domains/log_entries_domain/log_entries_domain.ts
@@ -4,8 +4,10 @@
* you may not use this file except in compliance with the Elastic License.
*/
+import { sortBy } from 'lodash';
import { TimeKey } from '../../../../common/time';
import { JsonObject } from '../../../../common/typed_json';
+import { InfraLogItem } from '../../../graphql/types';
import {
InfraLogEntry,
InfraLogMessageSegment,
@@ -14,6 +16,7 @@ import {
import { InfraDateRangeAggregationBucket, InfraFrameworkRequest } from '../../adapters/framework';
import { InfraSourceConfiguration, InfraSources } from '../../sources';
import { builtinRules } from './builtin_rules';
+import { convertDocumentSourceToLogItemFields } from './convert_document_source_to_log_item_fields';
import { compileFormattingRules } from './message';
export class InfraLogEntriesDomain {
@@ -121,6 +124,32 @@ export class InfraLogEntriesDomain {
const buckets = dateRangeBuckets.map(convertDateRangeBucketToSummaryBucket);
return buckets;
}
+
+ public async getLogItem(
+ request: InfraFrameworkRequest,
+ id: string,
+ sourceConfiguration: InfraSourceConfiguration
+ ): Promise {
+ const document = await this.adapter.getLogItem(request, id, sourceConfiguration);
+ const defaultFields = [
+ { field: '_index', value: document._index },
+ { field: '_id', value: document._id },
+ ];
+ return {
+ id: document._id,
+ index: document._index,
+ fields: sortBy(
+ [...defaultFields, ...convertDocumentSourceToLogItemFields(document._source)],
+ 'field'
+ ),
+ };
+ }
+}
+
+interface LogItemHit {
+ _index: string;
+ _id: string;
+ _source: JsonObject;
}
export interface LogEntriesAdapter {
@@ -153,6 +182,12 @@ export interface LogEntriesAdapter {
bucketSize: number,
filterQuery?: LogEntryQuery
): Promise;
+
+ getLogItem(
+ request: InfraFrameworkRequest,
+ id: string,
+ source: InfraSourceConfiguration
+ ): Promise;
}
export type LogEntryQuery = JsonObject;
diff --git a/x-pack/plugins/infra/tsconfig.json b/x-pack/plugins/infra/tsconfig.json
index 4082f16a5d91c..01bddbfc4264d 100644
--- a/x-pack/plugins/infra/tsconfig.json
+++ b/x-pack/plugins/infra/tsconfig.json
@@ -1,3 +1,3 @@
{
- "extends": "../../tsconfig.json"
-}
+ "extends": "../../tsconfig.json",
+}
\ No newline at end of file
diff --git a/x-pack/plugins/infra/types/eui.d.ts b/x-pack/plugins/infra/types/eui.d.ts
index c22337f16feda..78a9f81e5e6fd 100644
--- a/x-pack/plugins/infra/types/eui.d.ts
+++ b/x-pack/plugins/infra/types/eui.d.ts
@@ -170,4 +170,34 @@ declare module '@elastic/eui' {
};
export const EuiDatePickerRange: React.SFC;
+
+ type EuiInMemoryTableProps = CommonProps & {
+ items?: any;
+ columns?: any;
+ sorting?: any;
+ search?: any;
+ selection?: any;
+ pagination?: any;
+ itemId?: any;
+ isSelectable?: any;
+ loading?: any;
+ hasActions?: any;
+ message?: any;
+ };
+ export const EuiInMemoryTable: React.SFC;
+
+ type EuiButtonGroupProps = CommonProps & {
+ buttonSize?: any;
+ color?: any;
+ idToSelectedMap?: any;
+ options?: any;
+ type?: any;
+ onChange?: any;
+ isIconOnly?: any;
+ isDisabled?: any;
+ isFullWidth?: any;
+ legend?: any;
+ idSelected?: any;
+ };
+ export const EuiButtonGroup: React.SFC;
}
diff --git a/x-pack/plugins/ml/public/explorer/explorer_charts/__mocks__/mock_chart_data.js b/x-pack/plugins/ml/public/explorer/explorer_charts/__mocks__/mock_chart_data.js
index e150335114a20..82f8b8d30580f 100644
--- a/x-pack/plugins/ml/public/explorer/explorer_charts/__mocks__/mock_chart_data.js
+++ b/x-pack/plugins/ml/public/explorer/explorer_charts/__mocks__/mock_chart_data.js
@@ -22,5 +22,10 @@ export const chartData = [
date: new Date('2017-02-23T13:00:00.000Z'),
value: 201039318, anomalyScore: 59.83488, numberOfCauses: 1,
actual: [201039318], typical: [132739.5267403542]
+ },
+ {
+ date: new Date('2017-02-23T14:00:00.000Z'),
+ value: null, anomalyScore: 98.56166,
+ actual: [201039318], typical: [132739.5267403542]
}
];
diff --git a/x-pack/plugins/ml/public/explorer/explorer_charts/explorer_chart_single_metric.js b/x-pack/plugins/ml/public/explorer/explorer_charts/explorer_chart_single_metric.js
index a1d79be061edc..f849271f91c2d 100644
--- a/x-pack/plugins/ml/public/explorer/explorer_charts/explorer_chart_single_metric.js
+++ b/x-pack/plugins/ml/public/explorer/explorer_charts/explorer_chart_single_metric.js
@@ -267,11 +267,13 @@ export const ExplorerChartSingleMetric = injectI18n(class ExplorerChartSingleMet
function drawLineChartMarkers(data) {
// Render circle markers for the points.
// These are used for displaying tooltips on mouseover.
- // Don't render dots where value=null (data gaps) or for multi-bucket anomalies.
+ // Don't render dots where value=null (data gaps, with no anomalies)
+ // or for multi-bucket anomalies.
const dots = lineChartGroup.append('g')
.attr('class', 'chart-markers')
.selectAll('.metric-value')
- .data(data.filter(d => (d.value !== null && !showMultiBucketAnomalyMarker(d))));
+ .data(data.filter(d => ((d.value !== null || typeof d.anomalyScore === 'number') &&
+ !showMultiBucketAnomalyMarker(d))));
// Remove dots that are no longer needed i.e. if number of chart points has decreased.
dots.exit().remove();
diff --git a/x-pack/plugins/ml/public/explorer/explorer_charts/explorer_chart_single_metric.test.js b/x-pack/plugins/ml/public/explorer/explorer_charts/explorer_chart_single_metric.test.js
index ad8a04e1af75d..3398eb2e168ec 100644
--- a/x-pack/plugins/ml/public/explorer/explorer_charts/explorer_chart_single_metric.test.js
+++ b/x-pack/plugins/ml/public/explorer/explorer_charts/explorer_chart_single_metric.test.js
@@ -135,8 +135,8 @@ describe('ExplorerChart', () => {
expect(dots[0].getAttribute('r')).toBe('1.5');
const chartMarkers = wrapper.getDOMNode().querySelector('.chart-markers').querySelectorAll('circle');
- expect([...chartMarkers]).toHaveLength(3);
- expect([...chartMarkers].map(d => +d.getAttribute('r'))).toEqual([7, 7, 7]);
+ expect([...chartMarkers]).toHaveLength(4);
+ expect([...chartMarkers].map(d => +d.getAttribute('r'))).toEqual([7, 7, 7, 7]);
});
it('Anomaly Explorer Chart with single data point', () => {
diff --git a/x-pack/plugins/ml/public/jobs/new_job/simple/recognize/create_job/create_job.html b/x-pack/plugins/ml/public/jobs/new_job/simple/recognize/create_job/create_job.html
index 608adad54fb43..c97d5dde13117 100644
--- a/x-pack/plugins/ml/public/jobs/new_job/simple/recognize/create_job/create_job.html
+++ b/x-pack/plugins/ml/public/jobs/new_job/simple/recognize/create_job/create_job.html
@@ -340,6 +340,7 @@ {{ui.kibanaLabels[key]}}
i18n-default-message="(already exists)"
>
+ {{error}}
diff --git a/x-pack/plugins/ml/public/jobs/new_job/simple/recognize/create_job/create_job_controller.js b/x-pack/plugins/ml/public/jobs/new_job/simple/recognize/create_job/create_job_controller.js
index a7899729d8df7..0e518e38f8eca 100644
--- a/x-pack/plugins/ml/public/jobs/new_job/simple/recognize/create_job/create_job_controller.js
+++ b/x-pack/plugins/ml/public/jobs/new_job/simple/recognize/create_job/create_job_controller.js
@@ -212,7 +212,8 @@ module
title: o.title,
saveState: SAVE_STATE.NOT_SAVED,
config: o.config,
- exists: false
+ exists: false,
+ errors: [],
};
});
});
@@ -342,6 +343,9 @@ module
obj.saveState = SAVE_STATE.SAVED;
} else {
obj.saveState = SAVE_STATE.FAILED;
+ if (kibanaObjectResult.error && kibanaObjectResult.error.message) {
+ obj.errors.push(kibanaObjectResult.error.message);
+ }
}
} else {
obj.saveState = SAVE_STATE.FAILED;
diff --git a/x-pack/plugins/ml/public/jobs/new_job/wizard/steps/job_type/job_type_controller.js b/x-pack/plugins/ml/public/jobs/new_job/wizard/steps/job_type/job_type_controller.js
index 56d8b9b2567ba..970107e474b8c 100644
--- a/x-pack/plugins/ml/public/jobs/new_job/wizard/steps/job_type/job_type_controller.js
+++ b/x-pack/plugins/ml/public/jobs/new_job/wizard/steps/job_type/job_type_controller.js
@@ -74,7 +74,12 @@ module.controller('MlNewJobStepJobType',
$scope.indexPattern = indexPattern;
$scope.savedSearch = savedSearch;
- $scope.recognizerResults = { count: 0 };
+ $scope.recognizerResults = {
+ count: 0,
+ onChange() {
+ $scope.$applyAsync();
+ }
+ };
$scope.pageTitleLabel = (savedSearch.id !== undefined) ?
i18n('xpack.ml.newJob.wizard.jobType.savedSearchPageTitleLabel', {
diff --git a/x-pack/plugins/ml/public/timeseriesexplorer/components/timeseries_chart/timeseries_chart.js b/x-pack/plugins/ml/public/timeseriesexplorer/components/timeseries_chart/timeseries_chart.js
index 91129acf772d0..ee08c9376c8dc 100644
--- a/x-pack/plugins/ml/public/timeseriesexplorer/components/timeseries_chart/timeseries_chart.js
+++ b/x-pack/plugins/ml/public/timeseriesexplorer/components/timeseries_chart/timeseries_chart.js
@@ -677,10 +677,20 @@ export const TimeseriesChart = injectI18n(class TimeseriesChart extends React.Co
}
yMin = d3.min(combinedData, (d) => {
- return d.lower !== undefined ? Math.min(d.value, d.lower) : d.value;
+ let metricValue = d.value;
+ if (metricValue === null && d.anomalyScore !== undefined && d.actual !== undefined) {
+ // If an anomaly coincides with a gap in the data, use the anomaly actual value.
+ metricValue = Array.isArray(d.actual) ? d.actual[0] : d.actual;
+ }
+ return d.lower !== undefined ? Math.min(metricValue, d.lower) : metricValue;
});
yMax = d3.max(combinedData, (d) => {
- return d.upper !== undefined ? Math.max(d.value, d.upper) : d.value;
+ let metricValue = d.value;
+ if (metricValue === null && d.anomalyScore !== undefined && d.actual !== undefined) {
+ // If an anomaly coincides with a gap in the data, use the anomaly actual value.
+ metricValue = Array.isArray(d.actual) ? d.actual[0] : d.actual;
+ }
+ return d.upper !== undefined ? Math.max(metricValue, d.upper) : metricValue;
});
if (yMax === yMin) {
@@ -702,9 +712,10 @@ export const TimeseriesChart = injectI18n(class TimeseriesChart extends React.Co
if (mlAnnotationsEnabled && focusAnnotationData && focusAnnotationData.length > 0) {
const levels = getAnnotationLevels(focusAnnotationData);
const maxLevel = d3.max(Object.keys(levels).map(key => levels[key]));
- // TODO needs revisting to be a more robust normalization
+ // TODO needs revisiting to be a more robust normalization
yMax = yMax * (1 + (maxLevel + 1) / 5);
}
+
this.focusYScale.domain([yMin, yMax]);
} else {
@@ -758,9 +769,11 @@ export const TimeseriesChart = injectI18n(class TimeseriesChart extends React.Co
// Render circle markers for the points.
// These are used for displaying tooltips on mouseover.
- // Don't render dots where value=null (data gaps) or for multi-bucket anomalies.
+ // Don't render dots where value=null (data gaps, with no anomalies)
+ // or for multi-bucket anomalies.
const dots = d3.select('.focus-chart-markers').selectAll('.metric-value')
- .data(data.filter(d => (d.value !== null && !showMultiBucketAnomalyMarker(d))));
+ .data(data.filter(d => ((d.value !== null || typeof d.anomalyScore === 'number') &&
+ !showMultiBucketAnomalyMarker(d))));
// Remove dots that are no longer needed i.e. if number of chart points has decreased.
dots.exit().remove();
diff --git a/x-pack/plugins/ml/public/util/__tests__/chart_utils.js b/x-pack/plugins/ml/public/util/__tests__/chart_utils.js
index 75d575889eaec..979615f2778be 100644
--- a/x-pack/plugins/ml/public/util/__tests__/chart_utils.js
+++ b/x-pack/plugins/ml/public/util/__tests__/chart_utils.js
@@ -71,6 +71,26 @@ describe('ML - chart utils', () => {
expect(limits.max).to.be(105);
});
+ it('returns minimum of 0 when data includes an anomaly for missing data', () => {
+ const data = [
+ { date: new Date('2017-02-23T09:00:00.000Z'), value: 22.2 },
+ { date: new Date('2017-02-23T10:00:00.000Z'), value: 23.3 },
+ { date: new Date('2017-02-23T11:00:00.000Z'), value: 24.4 },
+ {
+ date: new Date('2017-02-23T12:00:00.000Z'),
+ value: null, anomalyScore: 97.32085,
+ actual: [0], typical: [22.2]
+ },
+ { date: new Date('2017-02-23T13:00:00.000Z'), value: 21.3 },
+ { date: new Date('2017-02-23T14:00:00.000Z'), value: 21.2 },
+ { date: new Date('2017-02-23T15:00:00.000Z'), value: 21.1 }
+ ];
+
+ const limits = chartLimits(data);
+ expect(limits.min).to.be(0);
+ expect(limits.max).to.be(24.4);
+ });
+
});
describe('filterAxisLabels', () => {
diff --git a/x-pack/plugins/ml/public/util/chart_utils.js b/x-pack/plugins/ml/public/util/chart_utils.js
index 0a061f32fbf6f..0163116bd3367 100644
--- a/x-pack/plugins/ml/public/util/chart_utils.js
+++ b/x-pack/plugins/ml/public/util/chart_utils.js
@@ -24,10 +24,16 @@ export const SCHEDULED_EVENT_SYMBOL_HEIGHT = 5;
const MAX_LABEL_WIDTH = 100;
export function chartLimits(data = []) {
- const limits = { max: 0, min: 0 };
+ const domain = d3.extent(data, (d) => {
+ let metricValue = d.value;
+ if (metricValue === null && d.anomalyScore !== undefined && d.actual !== undefined) {
+ // If an anomaly coincides with a gap in the data, use the anomaly actual value.
+ metricValue = Array.isArray(d.actual) ? d.actual[0] : d.actual;
+ }
+ return metricValue;
+ });
+ const limits = { max: domain[1], min: domain[0] };
- limits.max = d3.max(data, (d) => d.value);
- limits.min = d3.min(data, (d) => d.value);
if (limits.max === limits.min) {
limits.max = d3.max(data, (d) => {
if (d.typical) {
diff --git a/x-pack/plugins/ml/server/models/data_recognizer/modules/apache2/kibana/dashboard/ML-Apache2-Access-Remote-IP-Count-Explorer.json b/x-pack/plugins/ml/server/models/data_recognizer/modules/apache2/kibana/dashboard/ML-Apache2-Access-Remote-IP-Count-Explorer.json
index 5fc696c6c702d..24b87e39b35db 100644
--- a/x-pack/plugins/ml/server/models/data_recognizer/modules/apache2/kibana/dashboard/ML-Apache2-Access-Remote-IP-Count-Explorer.json
+++ b/x-pack/plugins/ml/server/models/data_recognizer/modules/apache2/kibana/dashboard/ML-Apache2-Access-Remote-IP-Count-Explorer.json
@@ -7,6 +7,7 @@
"panelsJSON": "[{\"size_x\":6,\"size_y\":3,\"panelIndex\":1,\"type\":\"visualization\",\"id\":\"ML-Apache2-Access-Remote-IP-Timechart\",\"col\":1,\"row\":1},{\"size_x\":6,\"size_y\":3,\"panelIndex\":2,\"type\":\"visualization\",\"id\":\"ML-Apache2-Access-Response-Code-Timechart\",\"col\":7,\"row\":1},{\"size_x\":6,\"size_y\":3,\"panelIndex\":3,\"type\":\"visualization\",\"id\":\"ML-Apache2-Access-Top-Remote-IPs-Table\",\"col\":1,\"row\":4},{\"size_x\":6,\"size_y\":3,\"panelIndex\":4,\"type\":\"visualization\",\"id\":\"ML-Apache2-Access-Map\",\"col\":7,\"row\":4},{\"size_x\":12,\"size_y\":9,\"panelIndex\":5,\"type\":\"visualization\",\"id\":\"ML-Apache2-Access-Top-URLs-Table\",\"col\":1,\"row\":7}]",
"optionsJSON": "{}",
"version": 1,
+ "migrationVersion": {},
"kibanaSavedObjectMeta": {
"searchSourceJSON": "{\"filter\":[{\"query\":{\"query_string\":{\"analyze_wildcard\":true,\"query\":\"*\"}}}],\"highlightAll\":true,\"version\":true}"
}
diff --git a/x-pack/plugins/ml/server/models/data_recognizer/modules/apache2/kibana/dashboard/ML-Apache2-Remote-IP-URL-Explorer.json b/x-pack/plugins/ml/server/models/data_recognizer/modules/apache2/kibana/dashboard/ML-Apache2-Remote-IP-URL-Explorer.json
index b04050ceb6e19..d4ef153201bf2 100644
--- a/x-pack/plugins/ml/server/models/data_recognizer/modules/apache2/kibana/dashboard/ML-Apache2-Remote-IP-URL-Explorer.json
+++ b/x-pack/plugins/ml/server/models/data_recognizer/modules/apache2/kibana/dashboard/ML-Apache2-Remote-IP-URL-Explorer.json
@@ -7,6 +7,7 @@
"panelsJSON": "[{\"col\":1,\"id\":\"ML-Apache2-Access-Unique-Count-URL-Timechart\",\"panelIndex\":1,\"row\":1,\"size_x\":6,\"size_y\":3,\"type\":\"visualization\"},{\"col\":7,\"id\":\"ML-Apache2-Access-Response-Code-Timechart\",\"panelIndex\":2,\"row\":1,\"size_x\":6,\"size_y\":3,\"type\":\"visualization\"},{\"col\":1,\"id\":\"ML-Apache2-Access-Top-Remote-IPs-Table\",\"panelIndex\":3,\"row\":4,\"size_x\":6,\"size_y\":3,\"type\":\"visualization\"},{\"col\":7,\"id\":\"ML-Apache2-Access-Map\",\"panelIndex\":4,\"row\":4,\"size_x\":6,\"size_y\":3,\"type\":\"visualization\"},{\"size_x\":12,\"size_y\":8,\"panelIndex\":5,\"type\":\"visualization\",\"id\":\"ML-Apache2-Access-Top-URLs-Table\",\"col\":1,\"row\":7}]",
"optionsJSON": "{}",
"version": 1,
+ "migrationVersion": {},
"kibanaSavedObjectMeta": {
"searchSourceJSON": "{\"filter\":[{\"query\":{\"query_string\":{\"analyze_wildcard\":true,\"query\":\"*\"}}}],\"highlightAll\":true,\"version\":true}"
}
diff --git a/x-pack/plugins/ml/server/models/data_recognizer/modules/apache2/kibana/search/ML-Filebeat-Apache2-Access.json b/x-pack/plugins/ml/server/models/data_recognizer/modules/apache2/kibana/search/ML-Filebeat-Apache2-Access.json
index edb54752c2ffe..7c6124295aae3 100644
--- a/x-pack/plugins/ml/server/models/data_recognizer/modules/apache2/kibana/search/ML-Filebeat-Apache2-Access.json
+++ b/x-pack/plugins/ml/server/models/data_recognizer/modules/apache2/kibana/search/ML-Filebeat-Apache2-Access.json
@@ -7,6 +7,7 @@
"description": "Filebeat Apache2 Access Data",
"title": "ML Apache2 Access Data",
"version": 1,
+ "migrationVersion": {},
"kibanaSavedObjectMeta": {
"searchSourceJSON": "{\"index\":\"INDEX_PATTERN_ID\",\"query\":{\"query_string\":{\"query\":\"_exists_:apache2.access\",\"analyze_wildcard\":true}},\"filter\":[],\"highlight\":{\"pre_tags\":[\"@kibana-highlighted-field@\"],\"post_tags\":[\"@/kibana-highlighted-field@\"],\"fields\":{\"*\":{}},\"require_field_match\":false,\"fragment_size\":2147483647}}"
},
diff --git a/x-pack/plugins/ml/server/models/data_recognizer/modules/apache2/kibana/visualization/ML-Apache2-Access-Map.json b/x-pack/plugins/ml/server/models/data_recognizer/modules/apache2/kibana/visualization/ML-Apache2-Access-Map.json
index f782f329c037b..c2df807f18985 100644
--- a/x-pack/plugins/ml/server/models/data_recognizer/modules/apache2/kibana/visualization/ML-Apache2-Access-Map.json
+++ b/x-pack/plugins/ml/server/models/data_recognizer/modules/apache2/kibana/visualization/ML-Apache2-Access-Map.json
@@ -1,11 +1,12 @@
{
- "visState": "{\"aggs\":[{\"enabled\":true,\"id\":\"1\",\"params\":{},\"schema\":\"metric\",\"type\":\"count\"},{\"enabled\":true,\"id\":\"2\",\"params\":{\"autoPrecision\":true,\"field\":\"apache2.access.geoip.location\"},\"schema\":\"segment\",\"type\":\"geohash_grid\"}],\"listeners\":{},\"params\":{\"addTooltip\":true,\"heatBlur\":15,\"heatMaxZoom\":16,\"heatMinOpacity\":0.1,\"heatNormalizeData\":true,\"heatRadius\":25,\"isDesaturated\":true,\"legendPosition\":\"bottomright\",\"mapCenter\":[15,5],\"mapType\":\"Scaled Circle Markers\",\"mapZoom\":2,\"wms\":{\"enabled\":false,\"options\":{\"attribution\":\"Maps provided by USGS\",\"format\":\"image/png\",\"layers\":\"0\",\"styles\":\"\",\"transparent\":true,\"version\":\"1.3.0\"},\"url\":\"https://basemap.nationalmap.gov/arcgis/services/USGSTopo/MapServer/WMSServer\"}},\"title\":\"ML Apache2 Access Map\",\"type\":\"tile_map\"}",
- "description": "",
- "title": "ML Apache2 Access Map",
- "uiStateJSON": "{\n \"mapCenter\": [\n 12.039320557540572,\n -0.17578125\n ]\n}",
- "version": 1,
- "savedSearchId": "ML-Filebeat-Apache2-Access",
+ "visState": "{\"aggs\":[{\"enabled\":true,\"id\":\"1\",\"params\":{},\"schema\":\"metric\",\"type\":\"count\"},{\"enabled\":true,\"id\":\"2\",\"params\":{\"autoPrecision\":true,\"field\":\"apache2.access.geoip.location\"},\"schema\":\"segment\",\"type\":\"geohash_grid\"}],\"listeners\":{},\"params\":{\"addTooltip\":true,\"heatBlur\":15,\"heatMaxZoom\":16,\"heatMinOpacity\":0.1,\"heatNormalizeData\":true,\"heatRadius\":25,\"isDesaturated\":true,\"legendPosition\":\"bottomright\",\"mapCenter\":[15,5],\"mapType\":\"Scaled Circle Markers\",\"mapZoom\":2,\"wms\":{\"enabled\":false,\"options\":{\"attribution\":\"Maps provided by USGS\",\"format\":\"image/png\",\"layers\":\"0\",\"styles\":\"\",\"transparent\":true,\"version\":\"1.3.0\"},\"url\":\"https://basemap.nationalmap.gov/arcgis/services/USGSTopo/MapServer/WMSServer\"}},\"title\":\"ML Apache2 Access Map\",\"type\":\"tile_map\"}",
+ "description": "",
+ "title": "ML Apache2 Access Map",
+ "uiStateJSON": "{\n \"mapCenter\": [\n 12.039320557540572,\n -0.17578125\n ]\n}",
+ "version": 1,
+ "migrationVersion": {},
+ "savedSearchId": "ML-Filebeat-Apache2-Access",
"kibanaSavedObjectMeta": {
"searchSourceJSON": "{\"filter\":[]}"
}
-}
\ No newline at end of file
+}
diff --git a/x-pack/plugins/ml/server/models/data_recognizer/modules/apache2/kibana/visualization/ML-Apache2-Access-Remote-IP-Timechart.json b/x-pack/plugins/ml/server/models/data_recognizer/modules/apache2/kibana/visualization/ML-Apache2-Access-Remote-IP-Timechart.json
index dcceff40a2c0f..0789ee1e03f6f 100644
--- a/x-pack/plugins/ml/server/models/data_recognizer/modules/apache2/kibana/visualization/ML-Apache2-Access-Remote-IP-Timechart.json
+++ b/x-pack/plugins/ml/server/models/data_recognizer/modules/apache2/kibana/visualization/ML-Apache2-Access-Remote-IP-Timechart.json
@@ -1,11 +1,12 @@
{
- "visState": "{\"title\":\"ML Apache2 Access Remote IP Timechart\",\"type\":\"area\",\"params\":{\"addLegend\":true,\"addTimeMarker\":false,\"addTooltip\":true,\"categoryAxes\":[{\"id\":\"CategoryAxis-1\",\"labels\":{\"show\":true,\"truncate\":100},\"position\":\"bottom\",\"scale\":{\"type\":\"linear\"},\"show\":true,\"style\":{},\"title\":{\"text\":\"@timestamp per 5 minutes\"},\"type\":\"category\"}],\"defaultYExtents\":false,\"drawLinesBetweenPoints\":true,\"grid\":{\"categoryLines\":false,\"style\":{\"color\":\"#eee\"}},\"interpolate\":\"linear\",\"legendPosition\":\"right\",\"radiusRatio\":9,\"scale\":\"linear\",\"seriesParams\":[{\"data\":{\"id\":\"1\",\"label\":\"Count\"},\"drawLinesBetweenPoints\":true,\"interpolate\":\"linear\",\"mode\":\"stacked\",\"show\":\"true\",\"showCircles\":true,\"type\":\"area\",\"valueAxis\":\"ValueAxis-1\"}],\"setYExtents\":false,\"showCircles\":true,\"times\":[],\"valueAxes\":[{\"id\":\"ValueAxis-1\",\"labels\":{\"filter\":false,\"rotate\":0,\"show\":true,\"truncate\":100},\"name\":\"LeftAxis-1\",\"position\":\"left\",\"scale\":{\"mode\":\"normal\",\"type\":\"linear\"},\"show\":true,\"style\":{},\"title\":{},\"type\":\"value\"}]},\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"schema\":\"metric\",\"params\":{}},{\"id\":\"2\",\"enabled\":true,\"type\":\"date_histogram\",\"schema\":\"segment\",\"params\":{\"field\":\"@timestamp\",\"interval\":\"auto\",\"customInterval\":\"2h\",\"min_doc_count\":1,\"extended_bounds\":{}}},{\"id\":\"3\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"group\",\"params\":{\"field\":\"apache2.access.remote_ip\",\"size\":5,\"order\":\"desc\",\"orderBy\":\"1\"}}],\"listeners\":{}}",
- "description": "",
- "title": "ML Apache2 Access Remote IP Timechart",
- "uiStateJSON": "{\"vis\":{\"legendOpen\":false}}",
- "version": 1,
- "savedSearchId": "ML-Filebeat-Apache2-Access",
+ "visState": "{\"title\":\"ML Apache2 Access Remote IP Timechart\",\"type\":\"area\",\"params\":{\"addLegend\":true,\"addTimeMarker\":false,\"addTooltip\":true,\"categoryAxes\":[{\"id\":\"CategoryAxis-1\",\"labels\":{\"show\":true,\"truncate\":100},\"position\":\"bottom\",\"scale\":{\"type\":\"linear\"},\"show\":true,\"style\":{},\"title\":{\"text\":\"@timestamp per 5 minutes\"},\"type\":\"category\"}],\"defaultYExtents\":false,\"drawLinesBetweenPoints\":true,\"grid\":{\"categoryLines\":false,\"style\":{\"color\":\"#eee\"}},\"interpolate\":\"linear\",\"legendPosition\":\"right\",\"radiusRatio\":9,\"scale\":\"linear\",\"seriesParams\":[{\"data\":{\"id\":\"1\",\"label\":\"Count\"},\"drawLinesBetweenPoints\":true,\"interpolate\":\"linear\",\"mode\":\"stacked\",\"show\":\"true\",\"showCircles\":true,\"type\":\"area\",\"valueAxis\":\"ValueAxis-1\"}],\"setYExtents\":false,\"showCircles\":true,\"times\":[],\"valueAxes\":[{\"id\":\"ValueAxis-1\",\"labels\":{\"filter\":false,\"rotate\":0,\"show\":true,\"truncate\":100},\"name\":\"LeftAxis-1\",\"position\":\"left\",\"scale\":{\"mode\":\"normal\",\"type\":\"linear\"},\"show\":true,\"style\":{},\"title\":{},\"type\":\"value\"}]},\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"schema\":\"metric\",\"params\":{}},{\"id\":\"2\",\"enabled\":true,\"type\":\"date_histogram\",\"schema\":\"segment\",\"params\":{\"field\":\"@timestamp\",\"interval\":\"auto\",\"customInterval\":\"2h\",\"min_doc_count\":1,\"extended_bounds\":{}}},{\"id\":\"3\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"group\",\"params\":{\"field\":\"apache2.access.remote_ip\",\"size\":5,\"order\":\"desc\",\"orderBy\":\"1\"}}],\"listeners\":{}}",
+ "description": "",
+ "title": "ML Apache2 Access Remote IP Timechart",
+ "uiStateJSON": "{\"vis\":{\"legendOpen\":false}}",
+ "version": 1,
+ "migrationVersion": {},
+ "savedSearchId": "ML-Filebeat-Apache2-Access",
"kibanaSavedObjectMeta": {
"searchSourceJSON": "{}"
}
-}
\ No newline at end of file
+}
diff --git a/x-pack/plugins/ml/server/models/data_recognizer/modules/apache2/kibana/visualization/ML-Apache2-Access-Response-Code-Timechart.json b/x-pack/plugins/ml/server/models/data_recognizer/modules/apache2/kibana/visualization/ML-Apache2-Access-Response-Code-Timechart.json
index f52019014b138..bc0a22685d5cf 100644
--- a/x-pack/plugins/ml/server/models/data_recognizer/modules/apache2/kibana/visualization/ML-Apache2-Access-Response-Code-Timechart.json
+++ b/x-pack/plugins/ml/server/models/data_recognizer/modules/apache2/kibana/visualization/ML-Apache2-Access-Response-Code-Timechart.json
@@ -1,11 +1,12 @@
{
- "visState": "{\"title\":\"ML Apache2 Access Response Code Timechart\",\"type\":\"histogram\",\"params\":{\"shareYAxis\":true,\"addTooltip\":true,\"addLegend\":true,\"legendPosition\":\"right\",\"scale\":\"linear\",\"mode\":\"stacked\",\"times\":[],\"addTimeMarker\":false,\"defaultYExtents\":false,\"setYExtents\":false,\"yAxis\":{}},\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"schema\":\"metric\",\"params\":{}},{\"id\":\"2\",\"enabled\":true,\"type\":\"date_histogram\",\"schema\":\"segment\",\"params\":{\"field\":\"@timestamp\",\"interval\":\"auto\",\"customInterval\":\"2h\",\"min_doc_count\":1,\"extended_bounds\":{}}},{\"id\":\"3\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"group\",\"params\":{\"field\":\"apache2.access.response_code\",\"size\":5,\"order\":\"desc\",\"orderBy\":\"1\"}}],\"listeners\":{}}",
- "description": "",
- "title": "ML Apache2 Access Response Code Timechart",
- "uiStateJSON": "{\n \"vis\": {\n \"colors\": {\n \"200\": \"#7EB26D\",\n \"404\": \"#614D93\"\n }\n }\n}",
- "version": 1,
- "savedSearchId": "ML-Filebeat-Apache2-Access",
+ "visState": "{\"title\":\"ML Apache2 Access Response Code Timechart\",\"type\":\"histogram\",\"params\":{\"shareYAxis\":true,\"addTooltip\":true,\"addLegend\":true,\"legendPosition\":\"right\",\"scale\":\"linear\",\"mode\":\"stacked\",\"times\":[],\"addTimeMarker\":false,\"defaultYExtents\":false,\"setYExtents\":false,\"yAxis\":{}},\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"schema\":\"metric\",\"params\":{}},{\"id\":\"2\",\"enabled\":true,\"type\":\"date_histogram\",\"schema\":\"segment\",\"params\":{\"field\":\"@timestamp\",\"interval\":\"auto\",\"customInterval\":\"2h\",\"min_doc_count\":1,\"extended_bounds\":{}}},{\"id\":\"3\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"group\",\"params\":{\"field\":\"apache2.access.response_code\",\"size\":5,\"order\":\"desc\",\"orderBy\":\"1\"}}],\"listeners\":{}}",
+ "description": "",
+ "title": "ML Apache2 Access Response Code Timechart",
+ "uiStateJSON": "{\n \"vis\": {\n \"colors\": {\n \"200\": \"#7EB26D\",\n \"404\": \"#614D93\"\n }\n }\n}",
+ "version": 1,
+ "migrationVersion": {},
+ "savedSearchId": "ML-Filebeat-Apache2-Access",
"kibanaSavedObjectMeta": {
"searchSourceJSON": "{\"filter\":[]}"
}
-}
\ No newline at end of file
+}
diff --git a/x-pack/plugins/ml/server/models/data_recognizer/modules/apache2/kibana/visualization/ML-Apache2-Access-Top-Remote-IPs-Table.json b/x-pack/plugins/ml/server/models/data_recognizer/modules/apache2/kibana/visualization/ML-Apache2-Access-Top-Remote-IPs-Table.json
index 0c49d9de46001..38943fd9ee6ac 100644
--- a/x-pack/plugins/ml/server/models/data_recognizer/modules/apache2/kibana/visualization/ML-Apache2-Access-Top-Remote-IPs-Table.json
+++ b/x-pack/plugins/ml/server/models/data_recognizer/modules/apache2/kibana/visualization/ML-Apache2-Access-Top-Remote-IPs-Table.json
@@ -1,11 +1,12 @@
{
- "visState": "{\"title\":\"ML Apache2 Access Top Remote IPs Table\",\"type\":\"table\",\"params\":{\"perPage\":10,\"showPartialRows\":false,\"showMetricsAtAllLevels\":false,\"sort\":{\"columnIndex\":null,\"direction\":null},\"showTotal\":false,\"totalFunc\":\"sum\"},\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"schema\":\"metric\",\"params\":{}},{\"id\":\"2\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"bucket\",\"params\":{\"field\":\"apache2.access.remote_ip\",\"size\":5,\"order\":\"desc\",\"orderBy\":\"1\"}}],\"listeners\":{}}",
- "description": "",
- "title": "ML Apache2 Access Top Remote IPs Table",
- "uiStateJSON": "{\"vis\":{\"params\":{\"sort\":{\"columnIndex\":null,\"direction\":null}}}}",
- "version": 1,
- "savedSearchId": "ML-Filebeat-Apache2-Access",
+ "visState": "{\"title\":\"ML Apache2 Access Top Remote IPs Table\",\"type\":\"table\",\"params\":{\"perPage\":10,\"showPartialRows\":false,\"showMetricsAtAllLevels\":false,\"sort\":{\"columnIndex\":null,\"direction\":null},\"showTotal\":false,\"totalFunc\":\"sum\"},\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"schema\":\"metric\",\"params\":{}},{\"id\":\"2\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"bucket\",\"params\":{\"field\":\"apache2.access.remote_ip\",\"size\":5,\"order\":\"desc\",\"orderBy\":\"1\"}}],\"listeners\":{}}",
+ "description": "",
+ "title": "ML Apache2 Access Top Remote IPs Table",
+ "uiStateJSON": "{\"vis\":{\"params\":{\"sort\":{\"columnIndex\":null,\"direction\":null}}}}",
+ "version": 1,
+ "migrationVersion": {},
+ "savedSearchId": "ML-Filebeat-Apache2-Access",
"kibanaSavedObjectMeta": {
"searchSourceJSON": "{}"
}
-}
\ No newline at end of file
+}
diff --git a/x-pack/plugins/ml/server/models/data_recognizer/modules/apache2/kibana/visualization/ML-Apache2-Access-Top-URLs-Table.json b/x-pack/plugins/ml/server/models/data_recognizer/modules/apache2/kibana/visualization/ML-Apache2-Access-Top-URLs-Table.json
index ab7760feff999..406c314787c72 100644
--- a/x-pack/plugins/ml/server/models/data_recognizer/modules/apache2/kibana/visualization/ML-Apache2-Access-Top-URLs-Table.json
+++ b/x-pack/plugins/ml/server/models/data_recognizer/modules/apache2/kibana/visualization/ML-Apache2-Access-Top-URLs-Table.json
@@ -1,11 +1,12 @@
{
- "visState": "{\"title\":\"ML Apache2 Access Top URLs Table\",\"type\":\"table\",\"params\":{\"perPage\":100,\"showPartialRows\":false,\"showMetricsAtAllLevels\":false,\"sort\":{\"columnIndex\":null,\"direction\":null},\"showTotal\":false,\"totalFunc\":\"sum\"},\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"schema\":\"metric\",\"params\":{}},{\"id\":\"2\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"bucket\",\"params\":{\"field\":\"apache2.access.url\",\"size\":1000,\"order\":\"desc\",\"orderBy\":\"1\"}}],\"listeners\":{}}",
- "description": "",
- "title": "ML Apache2 Access Top URLs Table",
- "uiStateJSON": "{\"vis\":{\"params\":{\"sort\":{\"columnIndex\":null,\"direction\":null}}}}",
- "version": 1,
- "savedSearchId": "ML-Filebeat-Apache2-Access",
+ "visState": "{\"title\":\"ML Apache2 Access Top URLs Table\",\"type\":\"table\",\"params\":{\"perPage\":100,\"showPartialRows\":false,\"showMetricsAtAllLevels\":false,\"sort\":{\"columnIndex\":null,\"direction\":null},\"showTotal\":false,\"totalFunc\":\"sum\"},\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"schema\":\"metric\",\"params\":{}},{\"id\":\"2\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"bucket\",\"params\":{\"field\":\"apache2.access.url\",\"size\":1000,\"order\":\"desc\",\"orderBy\":\"1\"}}],\"listeners\":{}}",
+ "description": "",
+ "title": "ML Apache2 Access Top URLs Table",
+ "uiStateJSON": "{\"vis\":{\"params\":{\"sort\":{\"columnIndex\":null,\"direction\":null}}}}",
+ "version": 1,
+ "migrationVersion": {},
+ "savedSearchId": "ML-Filebeat-Apache2-Access",
"kibanaSavedObjectMeta": {
"searchSourceJSON": "{}"
}
-}
\ No newline at end of file
+}
diff --git a/x-pack/plugins/ml/server/models/data_recognizer/modules/apache2/kibana/visualization/ML-Apache2-Access-Unique-Count-URL-Timechart.json b/x-pack/plugins/ml/server/models/data_recognizer/modules/apache2/kibana/visualization/ML-Apache2-Access-Unique-Count-URL-Timechart.json
index c6ce4fcf741eb..54d324434925c 100644
--- a/x-pack/plugins/ml/server/models/data_recognizer/modules/apache2/kibana/visualization/ML-Apache2-Access-Unique-Count-URL-Timechart.json
+++ b/x-pack/plugins/ml/server/models/data_recognizer/modules/apache2/kibana/visualization/ML-Apache2-Access-Unique-Count-URL-Timechart.json
@@ -1,11 +1,12 @@
{
- "visState": "{\"title\":\"ML Apache2 Access Unique Count URL Timechart\",\"type\":\"line\",\"params\":{\"grid\":{\"categoryLines\":false,\"style\":{\"color\":\"#eee\"}},\"categoryAxes\":[{\"id\":\"CategoryAxis-1\",\"type\":\"category\",\"position\":\"bottom\",\"show\":true,\"style\":{},\"scale\":{\"type\":\"linear\"},\"labels\":{\"show\":true,\"truncate\":100},\"title\":{\"text\":\"@timestamp per day\"}}],\"valueAxes\":[{\"id\":\"ValueAxis-1\",\"name\":\"LeftAxis-1\",\"type\":\"value\",\"position\":\"left\",\"show\":true,\"style\":{},\"scale\":{\"type\":\"linear\",\"mode\":\"normal\"},\"labels\":{\"show\":true,\"rotate\":0,\"filter\":false,\"truncate\":100},\"title\":{\"text\":\"Unique count of apache2.access.url\"}}],\"seriesParams\":[{\"show\":true,\"mode\":\"normal\",\"type\":\"line\",\"drawLinesBetweenPoints\":true,\"showCircles\":true,\"interpolate\":\"linear\",\"lineWidth\":2,\"data\":{\"id\":\"1\",\"label\":\"Unique count of apache2.access.url\"},\"valueAxis\":\"ValueAxis-1\"}],\"addTooltip\":true,\"addLegend\":true,\"legendPosition\":\"right\",\"showCircles\":true,\"interpolate\":\"linear\",\"scale\":\"linear\",\"drawLinesBetweenPoints\":true,\"radiusRatio\":9,\"times\":[],\"addTimeMarker\":false,\"defaultYExtents\":false,\"setYExtents\":false},\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"cardinality\",\"schema\":\"metric\",\"params\":{\"field\":\"apache2.access.url\"}},{\"id\":\"2\",\"enabled\":true,\"type\":\"date_histogram\",\"schema\":\"segment\",\"params\":{\"field\":\"@timestamp\",\"interval\":\"auto\",\"customInterval\":\"2h\",\"min_doc_count\":1,\"extended_bounds\":{}}}],\"listeners\":{}}",
- "description": "",
- "title": "ML Apache2 Access Unique Count URL Timechart",
- "uiStateJSON": "{}",
- "version": 1,
- "savedSearchId": "ML-Filebeat-Apache2-Access",
+ "visState": "{\"title\":\"ML Apache2 Access Unique Count URL Timechart\",\"type\":\"line\",\"params\":{\"grid\":{\"categoryLines\":false,\"style\":{\"color\":\"#eee\"}},\"categoryAxes\":[{\"id\":\"CategoryAxis-1\",\"type\":\"category\",\"position\":\"bottom\",\"show\":true,\"style\":{},\"scale\":{\"type\":\"linear\"},\"labels\":{\"show\":true,\"truncate\":100},\"title\":{\"text\":\"@timestamp per day\"}}],\"valueAxes\":[{\"id\":\"ValueAxis-1\",\"name\":\"LeftAxis-1\",\"type\":\"value\",\"position\":\"left\",\"show\":true,\"style\":{},\"scale\":{\"type\":\"linear\",\"mode\":\"normal\"},\"labels\":{\"show\":true,\"rotate\":0,\"filter\":false,\"truncate\":100},\"title\":{\"text\":\"Unique count of apache2.access.url\"}}],\"seriesParams\":[{\"show\":true,\"mode\":\"normal\",\"type\":\"line\",\"drawLinesBetweenPoints\":true,\"showCircles\":true,\"interpolate\":\"linear\",\"lineWidth\":2,\"data\":{\"id\":\"1\",\"label\":\"Unique count of apache2.access.url\"},\"valueAxis\":\"ValueAxis-1\"}],\"addTooltip\":true,\"addLegend\":true,\"legendPosition\":\"right\",\"showCircles\":true,\"interpolate\":\"linear\",\"scale\":\"linear\",\"drawLinesBetweenPoints\":true,\"radiusRatio\":9,\"times\":[],\"addTimeMarker\":false,\"defaultYExtents\":false,\"setYExtents\":false},\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"cardinality\",\"schema\":\"metric\",\"params\":{\"field\":\"apache2.access.url\"}},{\"id\":\"2\",\"enabled\":true,\"type\":\"date_histogram\",\"schema\":\"segment\",\"params\":{\"field\":\"@timestamp\",\"interval\":\"auto\",\"customInterval\":\"2h\",\"min_doc_count\":1,\"extended_bounds\":{}}}],\"listeners\":{}}",
+ "description": "",
+ "title": "ML Apache2 Access Unique Count URL Timechart",
+ "uiStateJSON": "{}",
+ "version": 1,
+ "migrationVersion": {},
+ "savedSearchId": "ML-Filebeat-Apache2-Access",
"kibanaSavedObjectMeta": {
"searchSourceJSON": "{}"
}
-}
\ No newline at end of file
+}
diff --git a/x-pack/plugins/ml/server/models/data_recognizer/modules/apache_ecs/kibana/dashboard/ml_http_access_explorer_ecs.json b/x-pack/plugins/ml/server/models/data_recognizer/modules/apache_ecs/kibana/dashboard/ml_http_access_explorer_ecs.json
new file mode 100644
index 0000000000000..681ad572417f6
--- /dev/null
+++ b/x-pack/plugins/ml/server/models/data_recognizer/modules/apache_ecs/kibana/dashboard/ml_http_access_explorer_ecs.json
@@ -0,0 +1,13 @@
+{
+ "hits": 0,
+ "timeRestore": false,
+ "description": "",
+ "title": "ML HTTP Access Explorer (ECS)",
+ "uiStateJSON": "{\"P-3\":{\"vis\":{\"params\":{\"sort\":{\"columnIndex\":null,\"direction\":null}}}},\"P-5\":{\"vis\":{\"params\":{\"sort\":{\"columnIndex\":null,\"direction\":null}}}}}",
+ "panelsJSON": "[{\"size_x\":6,\"size_y\":3,\"panelIndex\":1,\"type\":\"visualization\",\"id\":\"ml_http_access_events_timechart_ecs\",\"col\":1,\"row\":1},{\"size_x\":6,\"size_y\":3,\"panelIndex\":2,\"type\":\"visualization\",\"id\":\"ml_http_access_unique_count_url_timechart_ecs\",\"col\":7,\"row\":1},{\"size_x\":6,\"size_y\":3,\"panelIndex\":3,\"type\":\"visualization\",\"id\":\"ml_http_access_status_code_timechart_ecs\",\"col\":1,\"row\":4},{\"size_x\":6,\"size_y\":3,\"panelIndex\":4,\"type\":\"visualization\",\"id\":\"ml_http_access_source_ip_timechart_ecs\",\"col\":7,\"row\":4},{\"size_x\":6,\"size_y\":3,\"panelIndex\":5,\"type\":\"visualization\",\"id\":\"ml_http_access_top_source_ips_table_ecs\",\"col\":1,\"row\":8},{\"size_x\":6,\"size_y\":3,\"panelIndex\":6,\"type\":\"visualization\",\"id\":\"ml_http_access_map_ecs\",\"col\":7,\"row\":8},{\"size_x\":12,\"size_y\":9,\"panelIndex\":7,\"type\":\"visualization\",\"id\":\"ml_http_access_top_urls_table_ecs\",\"col\":1,\"row\":11}]",
+ "optionsJSON": "{\"darkTheme\":false}",
+ "version": 1,
+ "kibanaSavedObjectMeta": {
+ "searchSourceJSON": "{\n \"filter\": [],\n \"highlightAll\": true,\n \"version\": true,\n \"query\": {\n \"query\": \"\",\n \"language\": \"lucene\"\n }\n}"
+ }
+}
\ No newline at end of file
diff --git a/x-pack/plugins/ml/server/models/data_recognizer/modules/apache_ecs/kibana/search/ml_http_access_filebeat_ecs.json b/x-pack/plugins/ml/server/models/data_recognizer/modules/apache_ecs/kibana/search/ml_http_access_filebeat_ecs.json
new file mode 100644
index 0000000000000..6575c7e65d78d
--- /dev/null
+++ b/x-pack/plugins/ml/server/models/data_recognizer/modules/apache_ecs/kibana/search/ml_http_access_filebeat_ecs.json
@@ -0,0 +1,16 @@
+{
+ "sort": [
+ "@timestamp",
+ "desc"
+ ],
+ "hits": 0,
+ "description": "Filebeat HTTP Access Data (ECS)",
+ "title": "ML HTTP Access Data (ECS)",
+ "version": 1,
+ "kibanaSavedObjectMeta": {
+ "searchSourceJSON": "{\"index\":\"INDEX_PATTERN_ID\",\"query\":{\"query_string\":{\"query\":\"fileset.name:access\",\"analyze_wildcard\":true}},\"filter\":[],\"highlight\":{\"pre_tags\":[\"@kibana-highlighted-field@\"],\"post_tags\":[\"@/kibana-highlighted-field@\"],\"fields\":{\"*\":{}},\"require_field_match\":false,\"fragment_size\":2147483647}}"
+ },
+ "columns": [
+ "_source"
+ ]
+}
diff --git a/x-pack/plugins/ml/server/models/data_recognizer/modules/apache_ecs/kibana/visualization/ml_http_access_events_timechart_ecs.json b/x-pack/plugins/ml/server/models/data_recognizer/modules/apache_ecs/kibana/visualization/ml_http_access_events_timechart_ecs.json
new file mode 100644
index 0000000000000..ff507da41d1a5
--- /dev/null
+++ b/x-pack/plugins/ml/server/models/data_recognizer/modules/apache_ecs/kibana/visualization/ml_http_access_events_timechart_ecs.json
@@ -0,0 +1,11 @@
+{
+ "visState": "{\"title\":\"ML HTTP Access Event Timechart (ECS)\",\"type\":\"histogram\",\"params\":{\"shareYAxis\":true,\"addTooltip\":true,\"addLegend\":true,\"legendPosition\":\"right\",\"scale\":\"linear\",\"mode\":\"stacked\",\"times\":[],\"addTimeMarker\":false,\"defaultYExtents\":false,\"setYExtents\":false,\"yAxis\":{}},\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"schema\":\"metric\",\"params\":{}},{\"id\":\"2\",\"enabled\":true,\"type\":\"date_histogram\",\"schema\":\"segment\",\"params\":{\"field\":\"@timestamp\",\"interval\":\"auto\",\"customInterval\":\"2h\",\"min_doc_count\":1,\"extended_bounds\":{}}},{\"id\":\"3\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"group\",\"params\":{\"field\":\"event.module\",\"size\":10,\"order\":\"desc\",\"orderBy\":\"1\"}},{\"id\":\"4\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"group\",\"params\":{\"field\":\"event.dataset\",\"size\":10,\"order\":\"desc\",\"orderBy\":\"1\"}}],\"listeners\":{}}",
+ "description": "",
+ "title": "ML HTTP Access Event Timechart (ECS)",
+ "uiStateJSON": "{\"vis\":{\"colors\":{\"apache - access\":\"#629E51\",\"nginx - access\":\"#1F78C1\"}}}",
+ "version": 1,
+ "savedSearchId": "ml_http_access_filebeat_ecs",
+ "kibanaSavedObjectMeta": {
+ "searchSourceJSON": "{}"
+ }
+ }
\ No newline at end of file
diff --git a/x-pack/plugins/ml/server/models/data_recognizer/modules/apache_ecs/kibana/visualization/ml_http_access_map_ecs.json b/x-pack/plugins/ml/server/models/data_recognizer/modules/apache_ecs/kibana/visualization/ml_http_access_map_ecs.json
new file mode 100644
index 0000000000000..4cf3982f5ac6a
--- /dev/null
+++ b/x-pack/plugins/ml/server/models/data_recognizer/modules/apache_ecs/kibana/visualization/ml_http_access_map_ecs.json
@@ -0,0 +1,11 @@
+{
+ "visState": "{\"aggs\":[{\"enabled\":true,\"id\":\"1\",\"params\":{},\"schema\":\"metric\",\"type\":\"count\"},{\"enabled\":true,\"id\":\"2\",\"params\":{\"autoPrecision\":true,\"field\":\"source.geo.location\"},\"schema\":\"segment\",\"type\":\"geohash_grid\"}],\"listeners\":{},\"params\":{\"addTooltip\":true,\"heatBlur\":15,\"heatMaxZoom\":16,\"heatMinOpacity\":0.1,\"heatNormalizeData\":true,\"heatRadius\":25,\"isDesaturated\":true,\"legendPosition\":\"bottomright\",\"mapCenter\":[15,5],\"mapType\":\"Scaled Circle Markers\",\"mapZoom\":2,\"wms\":{\"enabled\":false,\"options\":{\"attribution\":\"Maps provided by USGS\",\"format\":\"image/png\",\"layers\":\"0\",\"styles\":\"\",\"transparent\":true,\"version\":\"1.3.0\"},\"url\":\"https://basemap.nationalmap.gov/arcgis/services/USGSTopo/MapServer/WMSServer\"}},\"title\":\"ML HTTP Access Map (ECS)\",\"type\":\"tile_map\"}",
+ "description": "",
+ "title": "ML HTTP Access Map (ECS)",
+ "uiStateJSON": "{\n \"mapCenter\": [\n 12.039320557540572,\n -0.17578125\n ]\n}",
+ "version": 1,
+ "savedSearchId": "ml_http_access_filebeat_ecs",
+ "kibanaSavedObjectMeta": {
+ "searchSourceJSON": "{}"
+ }
+}
\ No newline at end of file
diff --git a/x-pack/plugins/ml/server/models/data_recognizer/modules/apache_ecs/kibana/visualization/ml_http_access_source_ip_timechart_ecs.json b/x-pack/plugins/ml/server/models/data_recognizer/modules/apache_ecs/kibana/visualization/ml_http_access_source_ip_timechart_ecs.json
new file mode 100644
index 0000000000000..7525752abb053
--- /dev/null
+++ b/x-pack/plugins/ml/server/models/data_recognizer/modules/apache_ecs/kibana/visualization/ml_http_access_source_ip_timechart_ecs.json
@@ -0,0 +1,11 @@
+{
+ "visState": "{\"title\":\"ML HTTP Access Source IP Timechart (ECS)\",\"type\":\"area\",\"params\":{\"addLegend\":true,\"addTimeMarker\":false,\"addTooltip\":true,\"categoryAxes\":[{\"id\":\"CategoryAxis-1\",\"labels\":{\"show\":true,\"truncate\":100},\"position\":\"bottom\",\"scale\":{\"type\":\"linear\"},\"show\":true,\"style\":{},\"title\":{\"text\":\"@timestamp per 5 minutes\"},\"type\":\"category\"}],\"defaultYExtents\":false,\"drawLinesBetweenPoints\":true,\"grid\":{\"categoryLines\":false,\"style\":{\"color\":\"#eee\"}},\"interpolate\":\"linear\",\"legendPosition\":\"right\",\"radiusRatio\":9,\"scale\":\"linear\",\"seriesParams\":[{\"data\":{\"id\":\"1\",\"label\":\"Count\"},\"drawLinesBetweenPoints\":true,\"interpolate\":\"linear\",\"mode\":\"stacked\",\"show\":\"true\",\"showCircles\":true,\"type\":\"area\",\"valueAxis\":\"ValueAxis-1\"}],\"setYExtents\":false,\"showCircles\":true,\"times\":[],\"valueAxes\":[{\"id\":\"ValueAxis-1\",\"labels\":{\"filter\":false,\"rotate\":0,\"show\":true,\"truncate\":100},\"name\":\"LeftAxis-1\",\"position\":\"left\",\"scale\":{\"mode\":\"normal\",\"type\":\"linear\"},\"show\":true,\"style\":{},\"title\":{},\"type\":\"value\"}]},\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"schema\":\"metric\",\"params\":{}},{\"id\":\"2\",\"enabled\":true,\"type\":\"date_histogram\",\"schema\":\"segment\",\"params\":{\"field\":\"@timestamp\",\"interval\":\"auto\",\"customInterval\":\"2h\",\"min_doc_count\":1,\"extended_bounds\":{}}},{\"id\":\"3\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"group\",\"params\":{\"field\":\"source.address\",\"size\":5,\"order\":\"desc\",\"orderBy\":\"1\"}}],\"listeners\":{}}",
+ "description": "",
+ "title": "ML HTTP Access Source IP Timechart (ECS)",
+ "uiStateJSON": "{}",
+ "version": 1,
+ "savedSearchId": "ml_http_access_filebeat_ecs",
+ "kibanaSavedObjectMeta": {
+ "searchSourceJSON": "{}"
+ }
+}
diff --git a/x-pack/plugins/ml/server/models/data_recognizer/modules/apache_ecs/kibana/visualization/ml_http_access_status_code_timechart_ecs.json b/x-pack/plugins/ml/server/models/data_recognizer/modules/apache_ecs/kibana/visualization/ml_http_access_status_code_timechart_ecs.json
new file mode 100644
index 0000000000000..e104b047f924b
--- /dev/null
+++ b/x-pack/plugins/ml/server/models/data_recognizer/modules/apache_ecs/kibana/visualization/ml_http_access_status_code_timechart_ecs.json
@@ -0,0 +1,11 @@
+{
+ "visState": "{\"title\":\"ML HTTP Access Status Code Timechart (ECS)\",\"type\":\"histogram\",\"params\":{\"shareYAxis\":true,\"addTooltip\":true,\"addLegend\":true,\"legendPosition\":\"right\",\"scale\":\"linear\",\"mode\":\"stacked\",\"times\":[],\"addTimeMarker\":false,\"defaultYExtents\":false,\"setYExtents\":false,\"yAxis\":{}},\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"schema\":\"metric\",\"params\":{}},{\"id\":\"2\",\"enabled\":true,\"type\":\"date_histogram\",\"schema\":\"segment\",\"params\":{\"field\":\"@timestamp\",\"interval\":\"auto\",\"customInterval\":\"2h\",\"min_doc_count\":1,\"extended_bounds\":{}}},{\"id\":\"3\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"group\",\"params\":{\"field\":\"http.response.status_code\",\"size\":50,\"order\":\"desc\",\"orderBy\":\"1\"}}],\"listeners\":{}}",
+ "description": "",
+ "title": "ML HTTP Access Status Code Timechart (ECS)",
+ "uiStateJSON": "{\n \"vis\": {\n \"colors\": {\n \"200\": \"#7EB26D\",\n \"404\": \"#614D93\"\n }\n }\n}",
+ "version": 1,
+ "savedSearchId": "ml_http_access_filebeat_ecs",
+ "kibanaSavedObjectMeta": {
+ "searchSourceJSON": "{}"
+ }
+}
\ No newline at end of file
diff --git a/x-pack/plugins/ml/server/models/data_recognizer/modules/apache_ecs/kibana/visualization/ml_http_access_top_source_ips_table_ecs.json b/x-pack/plugins/ml/server/models/data_recognizer/modules/apache_ecs/kibana/visualization/ml_http_access_top_source_ips_table_ecs.json
new file mode 100644
index 0000000000000..c9afd66ea39b1
--- /dev/null
+++ b/x-pack/plugins/ml/server/models/data_recognizer/modules/apache_ecs/kibana/visualization/ml_http_access_top_source_ips_table_ecs.json
@@ -0,0 +1,11 @@
+{
+ "visState": "{\"title\":\"ML HTTP Access Top Source IPs Table (ECS)\",\"type\":\"table\",\"params\":{\"perPage\":10,\"showPartialRows\":false,\"showMetricsAtAllLevels\":false,\"sort\":{\"columnIndex\":null,\"direction\":null},\"showTotal\":false,\"totalFunc\":\"sum\"},\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"schema\":\"metric\",\"params\":{}},{\"id\":\"2\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"bucket\",\"params\":{\"field\":\"source.address\",\"size\":50,\"order\":\"desc\",\"orderBy\":\"1\"}}],\"listeners\":{}}",
+ "description": "",
+ "title": "ML HTTP Access Top Source IPs Table (ECS)",
+ "uiStateJSON": "{\"vis\":{\"params\":{\"sort\":{\"columnIndex\":null,\"direction\":null}}}}",
+ "version": 1,
+ "savedSearchId": "ml_http_access_filebeat_ecs",
+ "kibanaSavedObjectMeta": {
+ "searchSourceJSON": "{}"
+ }
+}
\ No newline at end of file
diff --git a/x-pack/plugins/ml/server/models/data_recognizer/modules/apache_ecs/kibana/visualization/ml_http_access_top_urls_table_ecs.json b/x-pack/plugins/ml/server/models/data_recognizer/modules/apache_ecs/kibana/visualization/ml_http_access_top_urls_table_ecs.json
new file mode 100644
index 0000000000000..34fbcb621085c
--- /dev/null
+++ b/x-pack/plugins/ml/server/models/data_recognizer/modules/apache_ecs/kibana/visualization/ml_http_access_top_urls_table_ecs.json
@@ -0,0 +1,11 @@
+{
+ "visState": "{\"title\":\"ML HTTP Access Top URLs Table (ECS)\",\"type\":\"table\",\"params\":{\"perPage\":100,\"showPartialRows\":false,\"showMetricsAtAllLevels\":false,\"sort\":{\"columnIndex\":null,\"direction\":null},\"showTotal\":false,\"totalFunc\":\"sum\"},\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"schema\":\"metric\",\"params\":{}},{\"id\":\"2\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"bucket\",\"params\":{\"field\":\"url.original\",\"size\":1000,\"order\":\"desc\",\"orderBy\":\"1\"}}],\"listeners\":{}}",
+ "description": "",
+ "title": "ML HTTP Access Top URLs Table (ECS)",
+ "uiStateJSON": "{\"vis\":{\"params\":{\"sort\":{\"columnIndex\":null,\"direction\":null}}}}",
+ "version": 1,
+ "savedSearchId": "ml_http_access_filebeat_ecs",
+ "kibanaSavedObjectMeta": {
+ "searchSourceJSON": "{}"
+ }
+}
\ No newline at end of file
diff --git a/x-pack/plugins/ml/server/models/data_recognizer/modules/apache_ecs/kibana/visualization/ml_http_access_unique_count_url_timechart_ecs.json b/x-pack/plugins/ml/server/models/data_recognizer/modules/apache_ecs/kibana/visualization/ml_http_access_unique_count_url_timechart_ecs.json
new file mode 100644
index 0000000000000..d14592e68bb6e
--- /dev/null
+++ b/x-pack/plugins/ml/server/models/data_recognizer/modules/apache_ecs/kibana/visualization/ml_http_access_unique_count_url_timechart_ecs.json
@@ -0,0 +1,11 @@
+{
+ "visState": "{\"title\":\"ML HTTP Access Unique Count URL Timechart (ECS)\",\"type\":\"line\",\"params\":{\"grid\":{\"categoryLines\":false,\"style\":{\"color\":\"#eee\"}},\"categoryAxes\":[{\"id\":\"CategoryAxis-1\",\"type\":\"category\",\"position\":\"bottom\",\"show\":true,\"style\":{},\"scale\":{\"type\":\"linear\"},\"labels\":{\"show\":true,\"truncate\":100},\"title\":{\"text\":\"@timestamp per day\"}}],\"valueAxes\":[{\"id\":\"ValueAxis-1\",\"name\":\"LeftAxis-1\",\"type\":\"value\",\"position\":\"left\",\"show\":true,\"style\":{},\"scale\":{\"type\":\"linear\",\"mode\":\"normal\"},\"labels\":{\"show\":true,\"rotate\":0,\"filter\":false,\"truncate\":100},\"title\":{\"text\":\"Unique count of url.original\"}}],\"seriesParams\":[{\"show\":true,\"mode\":\"normal\",\"type\":\"line\",\"drawLinesBetweenPoints\":true,\"showCircles\":true,\"interpolate\":\"linear\",\"lineWidth\":2,\"data\":{\"id\":\"1\",\"label\":\"Unique count of url.original\"},\"valueAxis\":\"ValueAxis-1\"}],\"addTooltip\":true,\"addLegend\":true,\"legendPosition\":\"right\",\"showCircles\":true,\"interpolate\":\"linear\",\"scale\":\"linear\",\"drawLinesBetweenPoints\":true,\"radiusRatio\":9,\"times\":[],\"addTimeMarker\":false,\"defaultYExtents\":false,\"setYExtents\":false},\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"cardinality\",\"schema\":\"metric\",\"params\":{\"field\":\"url.original\"}},{\"id\":\"2\",\"enabled\":true,\"type\":\"date_histogram\",\"schema\":\"segment\",\"params\":{\"field\":\"@timestamp\",\"interval\":\"auto\",\"customInterval\":\"2h\",\"min_doc_count\":1,\"extended_bounds\":{}}}],\"listeners\":{}}",
+ "description": "",
+ "title": "ML HTTP Access Unique Count URL Timechart (ECS)",
+ "uiStateJSON": "{}",
+ "version": 1,
+ "savedSearchId": "ml_http_access_filebeat_ecs",
+ "kibanaSavedObjectMeta": {
+ "searchSourceJSON": "{}"
+ }
+}
\ No newline at end of file
diff --git a/x-pack/plugins/ml/server/models/data_recognizer/modules/apache_ecs/logo.json b/x-pack/plugins/ml/server/models/data_recognizer/modules/apache_ecs/logo.json
new file mode 100644
index 0000000000000..e15620ed29fcc
--- /dev/null
+++ b/x-pack/plugins/ml/server/models/data_recognizer/modules/apache_ecs/logo.json
@@ -0,0 +1,6 @@
+{
+ "src": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAA5CAIAAADYwb7wAAAHTUlEQVR4AbXTa1iT5xkH8Lvt7BTFtXioxjcJggIiHkQFUQQFJgdEUGB27arOQxHdCgNdUStFC1OrbR3latU5kIAogoKUg1JQAjkgkIQEAjSExBBCSAIkkDM5sMf5rR/64ZU81/vhzvX+r/v33s/zBKZnYtlVPHOhl/EGwabo+dUrmInu3aYrYM4Dwzcw+QXYdaoZBTQi/eVX3c233zbdnKfNAkNxzMwBZo3+azD++1V3c76T6SYYrsPkFZg2js0EYLOidsbvwHQLpu76ThV5mhHwPWgvARrLbre/KTCRG69Jh6kCMJUGTlXuM99Cc4DpRzBfhWm9wmq1cbg8iUSCEzAz78oTYfQ0mAq9ppnpZoqTpQCm8sH4AxivoS1So8zYuFqhUOIBrAqxbB8oU2cp/gbG6kxjUfhENkzkOKuznEfTQH01eNpux38GdptVdgBkB0F+BLR3UvTlWYpjoEpbqEpzUZ1aOHIAjI15b3SL1DfTxBEwfGSJMiPQ0ERRnnZXpswfPb1g7HOX8Qxn5TGwjUnxA+Z+jsAfhg57SBJA/zRfczt16ACMpBAVqUtUp5YqjsJE7m78/2S71SIMf1e0e554z2zVt8n65/cG/wSypOXDyST5SeLIZ5gsAaxDvfgBVe65nrUg3u8zEOViaH6szP5Ikug0dHiF7Ijb8HG3wXgYzY5GMZyARSrikUG427tvy9vjd67qfi4VhsDgXzyln6yQHnIfOkQWh4FVJcUL2O09fht6NswV7FrVH71Gz2iQJkcKo4niRK+X+z0HD3j3B4D6zpcoiBPQPKigAfQGb+ryfEtdckvzuLhnHQzE+ojiVokTVgsCYfDgGvQROAGb0dgGi1ngwVu++pfIAH1ri2h/iGCHe3+UtzDGqz+CMJJ10KpWoSROYPh8Dh2At8L/BThr7t+frCnnEqBv59q+nT59OzwHj+8fu5E3WVdnt1rxABbVKANmsz9Yx17k07V2p57G7A0K5WLePLf13OUbuO6+Pf6hDICJigqcE7xMTmeCU6e7Xyu8P1Zwd/zeQwbM78Q2dy7x5RJ8uZgvC1w5Lp7TFgsewCIbocHvOYQN7KXrOkkbtejzQ2NZ8705mC8H29BJ8uWSN9IAtPWNKIwHEB/9jA7OHDd/JixQ3aZM1NYz0ee7bkQA8tC+obFkZy6gJB5galBGhfdYyzaxl25sn+OtY3YIEw93zPLoxF4BnCXr+JvCRH89ae4X4QQkGTlNQGgnb2UAceSbHyYbqQxw4ZD8ONgm9KB94/v9kesRYJHJ8QDWSe1zWE13CXhB2t4M7loqU5KW2QrubDQQesibO+Z602G2rqkFhfEA8vzyOnClk0OaYJ0wJUvLYLXAyjZSQAfmx1q2uWPxen5wrDLvNkriAew2W8vK6EbY0kIKeworNc+ZwzeLnsGKVuL2F9jWNmxLG2Ezb3OE+PgpdDvxANouQRX4NGHhjfOCWFGfalndNCyk5YMgOhbEwIJalwW2uQY+gzljxWU4JxBcuFEB6xtdo6tgjbKyQVXVWANezeSwFmIIDdtJx4LR2VDB26bV4QFsFkuda1z1nNCnhOgnfwjTvOCx4v7e4BTchO2iYmHNy0L/v29uA2k5KIwHmOgSlsG2WmLcI9gmvEZR0zmV4NtAjmokRjzDwhHTRAitgZVmqRwnMHCjsgS2V5MTSmHrOJMnvFZYCdvqSTH1pKifiZHP3HdXgkdv2mWUxAlQYzNKIfKhczQj4aya3ff4vegawp46YuwTLKaevKfmnR2VsNZmMOEErFpD+eL4soXxFNg+/BNdXk27CwHVpPhq0t5aclwtIaYIlqtpHJTECYzypXcg7uHSxPtOcWMdvfQ/Z5XNiakkJlSREquW7i0Ar4HcEhTDD3Q/Yn0HH5dAJPcrymh7HwV2PSJ9WOH64YM5MRTwF+WVogwewGa1qfrkqGAXtFx8N+lHiBxl8oUFTwog/P77CRQIfbRgr/YXyeskzgmEDfzWvAZm7tMv3kku3Hp+omvgJ5+jFa6f0D/+Sl7bajNbNNJxLoWOH0DrvxHfZs46cQ4+5dxrk9F6L8G+yvhr/GKatE30+GTxxd8lTemMKIYfUPWNpMOxc28lyzsHGy7VZcz9x79WZmYtSj8Fh66vOmPU6FEGJ2C32V//uLLqy+8DLsu40gvY5zluZ3NIGdfXZ1G/rhvqEKO3+IEpk0XS/lLGHcrEzrRTmP1UQSqcyPY4f5GYcXZu6vWN2Qq+7I0AtPi13Ulw4iScUAmU+R/lJ8HxM4v+eX5ZRunRwmHOIArgB9DFkHXLO8rYvfW9jHwm+yGnNKUM1cImgVYx+es4PkA3bnh9EkK6SDeuk7ClOJv99i0SNA/waviosE5ZTTrTzAPNBW1olN9O4wdGpZqmgnZUOArg1gu6GoQOBJpLuNpxg6OAyTED9QEPFY4CWM2CDqrAgUD5vRaVcsJRgFZrKC5qnHbYAiazt6623YHAf27ViUQjDgTo9J5pR67/AfRrVpVr6wheAAAAAElFTkSuQmCC",
+ "height": 25,
+ "width": 125
+}
+
diff --git a/x-pack/plugins/ml/server/models/data_recognizer/modules/apache_ecs/manifest.json b/x-pack/plugins/ml/server/models/data_recognizer/modules/apache_ecs/manifest.json
new file mode 100644
index 0000000000000..031cf05ca39cd
--- /dev/null
+++ b/x-pack/plugins/ml/server/models/data_recognizer/modules/apache_ecs/manifest.json
@@ -0,0 +1,111 @@
+{
+ "id": "apache_ecs",
+ "title": "Apache access logs",
+ "description": "Find unusual activity in HTTP access logs from filebeat (ECS)",
+ "type": "Web Access Logs",
+ "logoFile": "logo.json",
+ "defaultIndexPattern": "filebeat-*",
+ "query": {
+ "bool": {
+ "filter": [
+ { "term": { "event.dataset": "apache.access" } },
+ { "exists": { "field": "source.address" } },
+ { "exists": { "field": "url.original" } },
+ { "exists": { "field": "http.response.status_code" } }
+ ]
+ }
+ },
+ "jobs": [
+ {
+ "id": "visitor_rate_ecs",
+ "file": "visitor_rate_ecs.json"
+ },
+ {
+ "id": "status_code_rate_ecs",
+ "file": "status_code_rate_ecs.json"
+ },
+ {
+ "id": "source_ip_url_count_ecs",
+ "file": "source_ip_url_count_ecs.json"
+ },
+ {
+ "id": "source_ip_request_rate_ecs",
+ "file": "source_ip_request_rate_ecs.json"
+ },
+ {
+ "id": "low_request_rate_ecs",
+ "file": "low_request_rate_ecs.json"
+ }
+ ],
+ "datafeeds": [
+ {
+ "id": "datafeed-visitor_rate_ecs",
+ "file": "datafeed_visitor_rate_ecs.json",
+ "job_id": "visitor_rate_ecs"
+ },
+ {
+ "id": "datafeed-status_code_rate_ecs",
+ "file": "datafeed_status_code_rate_ecs.json",
+ "job_id": "status_code_rate_ecs"
+ },
+ {
+ "id": "datafeed-source_ip_url_count_ecs",
+ "file": "datafeed_source_ip_url_count_ecs.json",
+ "job_id": "source_ip_url_count_ecs"
+ },
+ {
+ "id": "datafeed-source_ip_request_rate_ecs",
+ "file": "datafeed_source_ip_request_rate_ecs.json",
+ "job_id": "source_ip_request_rate_ecs"
+ },
+ {
+ "id": "datafeed-low_request_rate_ecs",
+ "file": "datafeed_low_request_rate_ecs.json",
+ "job_id": "low_request_rate_ecs"
+ }
+ ],
+ "kibana": {
+ "dashboard": [
+ {
+ "id": "ml_http_access_explorer_ecs",
+ "file": "ml_http_access_explorer_ecs.json"
+ }
+ ],
+ "search": [
+ {
+ "id": "ml_http_access_filebeat_ecs",
+ "file": "ml_http_access_filebeat_ecs.json"
+ }
+ ],
+ "visualization": [
+ {
+ "id": "ml_http_access_map_ecs",
+ "file": "ml_http_access_map_ecs.json"
+ },
+ {
+ "id": "ml_http_access_source_ip_timechart_ecs",
+ "file": "ml_http_access_source_ip_timechart_ecs.json"
+ },
+ {
+ "id": "ml_http_access_status_code_timechart_ecs",
+ "file": "ml_http_access_status_code_timechart_ecs.json"
+ },
+ {
+ "id": "ml_http_access_top_source_ips_table_ecs",
+ "file": "ml_http_access_top_source_ips_table_ecs.json"
+ },
+ {
+ "id": "ml_http_access_top_urls_table_ecs",
+ "file": "ml_http_access_top_urls_table_ecs.json"
+ },
+ {
+ "id": "ml_http_access_unique_count_url_timechart_ecs",
+ "file": "ml_http_access_unique_count_url_timechart_ecs.json"
+ },
+ {
+ "id": "ml_http_access_events_timechart_ecs",
+ "file": "ml_http_access_events_timechart_ecs.json"
+ }
+ ]
+ }
+}
diff --git a/x-pack/plugins/ml/server/models/data_recognizer/modules/apache_ecs/ml/datafeed_low_request_rate_ecs.json b/x-pack/plugins/ml/server/models/data_recognizer/modules/apache_ecs/ml/datafeed_low_request_rate_ecs.json
new file mode 100644
index 0000000000000..b08a8526b17e5
--- /dev/null
+++ b/x-pack/plugins/ml/server/models/data_recognizer/modules/apache_ecs/ml/datafeed_low_request_rate_ecs.json
@@ -0,0 +1,34 @@
+{
+ "job_id": "JOB_ID",
+ "indexes": [
+ "INDEX_PATTERN_NAME"
+ ],
+ "query": {
+ "bool": {
+ "filter": [
+ { "term": { "event.dataset": "apache.access" } }
+ ]
+ }
+ },
+ "aggregations": {
+ "buckets": {
+ "date_histogram": {
+ "field": "@timestamp",
+ "interval": 900000,
+ "offset": 0,
+ "order": {
+ "_key": "asc"
+ },
+ "keyed": false,
+ "min_doc_count": 0
+ },
+ "aggregations": {
+ "@timestamp": {
+ "max": {
+ "field": "@timestamp"
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/x-pack/plugins/ml/server/models/data_recognizer/modules/apache_ecs/ml/datafeed_source_ip_request_rate_ecs.json b/x-pack/plugins/ml/server/models/data_recognizer/modules/apache_ecs/ml/datafeed_source_ip_request_rate_ecs.json
new file mode 100644
index 0000000000000..824d6a934d865
--- /dev/null
+++ b/x-pack/plugins/ml/server/models/data_recognizer/modules/apache_ecs/ml/datafeed_source_ip_request_rate_ecs.json
@@ -0,0 +1,13 @@
+{
+ "job_id": "JOB_ID",
+ "indexes": [
+ "INDEX_PATTERN_NAME"
+ ],
+ "query": {
+ "bool": {
+ "filter": [
+ { "term": { "event.dataset": "apache.access" } }
+ ]
+ }
+ }
+}
diff --git a/x-pack/plugins/ml/server/models/data_recognizer/modules/apache_ecs/ml/datafeed_source_ip_url_count_ecs.json b/x-pack/plugins/ml/server/models/data_recognizer/modules/apache_ecs/ml/datafeed_source_ip_url_count_ecs.json
new file mode 100644
index 0000000000000..824d6a934d865
--- /dev/null
+++ b/x-pack/plugins/ml/server/models/data_recognizer/modules/apache_ecs/ml/datafeed_source_ip_url_count_ecs.json
@@ -0,0 +1,13 @@
+{
+ "job_id": "JOB_ID",
+ "indexes": [
+ "INDEX_PATTERN_NAME"
+ ],
+ "query": {
+ "bool": {
+ "filter": [
+ { "term": { "event.dataset": "apache.access" } }
+ ]
+ }
+ }
+}
diff --git a/x-pack/plugins/ml/server/models/data_recognizer/modules/apache_ecs/ml/datafeed_status_code_rate_ecs.json b/x-pack/plugins/ml/server/models/data_recognizer/modules/apache_ecs/ml/datafeed_status_code_rate_ecs.json
new file mode 100644
index 0000000000000..824d6a934d865
--- /dev/null
+++ b/x-pack/plugins/ml/server/models/data_recognizer/modules/apache_ecs/ml/datafeed_status_code_rate_ecs.json
@@ -0,0 +1,13 @@
+{
+ "job_id": "JOB_ID",
+ "indexes": [
+ "INDEX_PATTERN_NAME"
+ ],
+ "query": {
+ "bool": {
+ "filter": [
+ { "term": { "event.dataset": "apache.access" } }
+ ]
+ }
+ }
+}
diff --git a/x-pack/plugins/ml/server/models/data_recognizer/modules/apache_ecs/ml/datafeed_visitor_rate_ecs.json b/x-pack/plugins/ml/server/models/data_recognizer/modules/apache_ecs/ml/datafeed_visitor_rate_ecs.json
new file mode 100644
index 0000000000000..b88b66f15b329
--- /dev/null
+++ b/x-pack/plugins/ml/server/models/data_recognizer/modules/apache_ecs/ml/datafeed_visitor_rate_ecs.json
@@ -0,0 +1,39 @@
+{
+ "job_id": "JOB_ID",
+ "indexes": [
+ "INDEX_PATTERN_NAME"
+ ],
+ "query": {
+ "bool": {
+ "filter": [
+ { "term": { "event.dataset": "apache.access" } }
+ ]
+ }
+ },
+ "aggregations": {
+ "buckets": {
+ "date_histogram": {
+ "field": "@timestamp",
+ "interval": 900000,
+ "offset": 0,
+ "order": {
+ "_key": "asc"
+ },
+ "keyed": false,
+ "min_doc_count": 0
+ },
+ "aggregations": {
+ "@timestamp": {
+ "max": {
+ "field": "@timestamp"
+ }
+ },
+ "dc_source_address": {
+ "cardinality": {
+ "field": "source.address"
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/x-pack/plugins/ml/server/models/data_recognizer/modules/apache_ecs/ml/low_request_rate_ecs.json b/x-pack/plugins/ml/server/models/data_recognizer/modules/apache_ecs/ml/low_request_rate_ecs.json
new file mode 100644
index 0000000000000..1bfb864bef9ee
--- /dev/null
+++ b/x-pack/plugins/ml/server/models/data_recognizer/modules/apache_ecs/ml/low_request_rate_ecs.json
@@ -0,0 +1,34 @@
+{
+ "groups": ["apache"],
+ "description": "HTTP Access Logs: Detect low request rate (ECS)",
+ "analysis_config" : {
+ "bucket_span": "15m",
+ "summary_count_field_name": "doc_count",
+ "detectors": [
+ {
+ "detector_description": "apache_access_low_request_rate",
+ "function": "low_count"
+ }
+ ],
+ "influencers": []
+ },
+ "analysis_limits": {
+ "model_memory_limit": "10mb"
+ },
+ "data_description": {
+ "time_field": "@timestamp",
+ "time_format": "epoch_ms"
+ },
+ "model_plot_config": {
+ "enabled": true
+ },
+ "custom_settings": {
+ "created_by": "ml-module-apache-access",
+ "custom_urls": [
+ {
+ "url_name": "Raw data",
+ "url_value": "kibana#/discover/ml_http_access_filebeat_ecs?_g=(time:(from:\u0027$earliest$\u0027,mode:absolute,to:\u0027$latest$\u0027))&_a=(columns:!(_source),filters:!((\u0027$state\u0027:(store:appState),meta:(alias:!n,disabled:!f,index:\u0027INDEX_PATTERN_ID\u0027,key:event.dataset,negate:!f,params:(query:\u0027apache.access\u0027,type:phrase),type:phrase,value:\u0027apache.access\u0027),query:(match:(event.dataset:(query:\u0027apache.access\u0027,type:phrase))))),index:\u0027INDEX_PATTERN_ID\u0027,interval:auto,query:(language:lucene,query:\u0027\u0027),sort:!(\u0027@timestamp\u0027,desc))"
+ }
+ ]
+ }
+}
diff --git a/x-pack/plugins/ml/server/models/data_recognizer/modules/apache_ecs/ml/source_ip_request_rate_ecs.json b/x-pack/plugins/ml/server/models/data_recognizer/modules/apache_ecs/ml/source_ip_request_rate_ecs.json
new file mode 100644
index 0000000000000..25c51caec8727
--- /dev/null
+++ b/x-pack/plugins/ml/server/models/data_recognizer/modules/apache_ecs/ml/source_ip_request_rate_ecs.json
@@ -0,0 +1,34 @@
+{
+ "groups": ["apache"],
+ "description": "HTTP Access Logs: Detect unusual source ips - high request rates (ECS)",
+ "analysis_config" : {
+ "bucket_span": "1h",
+ "detectors": [
+ {
+ "detector_description": "apache_access_source_ip_high_count",
+ "function": "high_count",
+ "over_field_name": "source.address"
+ }
+ ],
+ "influencers": [
+ "source.address"
+ ]
+ },
+ "data_description": {
+ "time_field": "@timestamp",
+ "time_format": "epoch_ms"
+ },
+ "custom_settings": {
+ "created_by": "ml-module-apache-access",
+ "custom_urls": [
+ {
+ "url_name": "Investigate source IP",
+ "url_value": "kibana#/dashboard/ml_http_access_explorer_ecs?_g=(time:(from:\u0027$earliest$\u0027,mode:absolute,to:\u0027$latest$\u0027))&_a=(description:\u0027\u0027,filters:!((\u0027$state\u0027:(store:appState),meta:(alias:!n,disabled:!f,index:\u0027INDEX_PATTERN_ID\u0027,key:event.dataset,negate:!f,params:(query:\u0027apache.access\u0027,type:phrase),type:phrase,value:\u0027apache.access\u0027),query:(match:(event.dataset:(query:\u0027apache.access\u0027,type:phrase)))),(\u0027$state\u0027:(store:appState),meta:(alias:!n,disabled:!f,index:\u0027INDEX_PATTERN_ID\u0027,key:source.address,negate:!f,type:phrase,value:\u0027$source.address$\u0027),query:(match:(source.address:(query:\u0027$source.address$\u0027,type:phrase))))),query:(language:lucene,query:\u0027\u0027))"
+ },
+ {
+ "url_name": "Raw data",
+ "url_value": "kibana#/discover/ml_http_access_filebeat_ecs?_g=(time:(from:\u0027$earliest$\u0027,mode:absolute,to:\u0027$latest$\u0027))&_a=(columns:!(_source),filters:!((\u0027$state\u0027:(store:appState),meta:(alias:!n,disabled:!f,index:\u0027INDEX_PATTERN_ID\u0027,key:event.dataset,negate:!f,params:(query:\u0027apache.access\u0027,type:phrase),type:phrase,value:\u0027apache.access\u0027),query:(match:(event.dataset:(query:\u0027apache.access\u0027,type:phrase)))),(\u0027$state\u0027:(store:appState),meta:(alias:!n,disabled:!f,index:\u0027INDEX_PATTERN_ID\u0027,key:source.address,negate:!f,type:phrase,value:\u0027$source.address$\u0027),query:(match:(source.address:(query:\u0027$source.address$\u0027,type:phrase))))),index:\u0027INDEX_PATTERN_ID\u0027,interval:auto,query:(language:lucene,query:\u0027\u0027),sort:!(\u0027@timestamp\u0027,desc))"
+ }
+ ]
+ }
+}
diff --git a/x-pack/plugins/ml/server/models/data_recognizer/modules/apache_ecs/ml/source_ip_url_count_ecs.json b/x-pack/plugins/ml/server/models/data_recognizer/modules/apache_ecs/ml/source_ip_url_count_ecs.json
new file mode 100644
index 0000000000000..2982e04771086
--- /dev/null
+++ b/x-pack/plugins/ml/server/models/data_recognizer/modules/apache_ecs/ml/source_ip_url_count_ecs.json
@@ -0,0 +1,35 @@
+{
+ "groups": ["apache"],
+ "description": "HTTP Access Logs: Detect unusual source ips - high distinct count of urls (ECS)",
+ "analysis_config" : {
+ "bucket_span": "1h",
+ "detectors": [
+ {
+ "detector_description": "apache_access_source_ip_high_dc_url",
+ "function": "high_distinct_count",
+ "field_name": "url.original",
+ "over_field_name": "source.address"
+ }
+ ],
+ "influencers": [
+ "source.address"
+ ]
+ },
+ "data_description": {
+ "time_field": "@timestamp",
+ "time_format": "epoch_ms"
+ },
+ "custom_settings": {
+ "created_by": "ml-module-apache-access",
+ "custom_urls": [
+ {
+ "url_name": "Investigate source IP",
+ "url_value": "kibana#/dashboard/ml_http_access_explorer_ecs?_g=(time:(from:\u0027$earliest$\u0027,mode:absolute,to:\u0027$latest$\u0027))&_a=(description:\u0027\u0027,filters:!((\u0027$state\u0027:(store:appState),meta:(alias:!n,disabled:!f,index:\u0027INDEX_PATTERN_ID\u0027,key:event.dataset,negate:!f,params:(query:\u0027apache.access\u0027,type:phrase),type:phrase,value:\u0027apache.access\u0027),query:(match:(event.dataset:(query:\u0027apache.access\u0027,type:phrase)))),(\u0027$state\u0027:(store:appState),meta:(alias:!n,disabled:!f,index:\u0027INDEX_PATTERN_ID\u0027,key:source.address,negate:!f,type:phrase,value:\u0027$source.address$\u0027),query:(match:(source.address:(query:\u0027$source.address$\u0027,type:phrase))))),query:(language:lucene,query:\u0027\u0027))"
+ },
+ {
+ "url_name": "Raw data",
+ "url_value": "kibana#/discover/ml_http_access_filebeat_ecs?_g=(time:(from:\u0027$earliest$\u0027,mode:absolute,to:\u0027$latest$\u0027))&_a=(columns:!(_source),filters:!((\u0027$state\u0027:(store:appState),meta:(alias:!n,disabled:!f,index:\u0027INDEX_PATTERN_ID\u0027,key:event.dataset,negate:!f,params:(query:\u0027apache.access\u0027,type:phrase),type:phrase,value:\u0027apache.access\u0027),query:(match:(event.dataset:(query:\u0027apache.access\u0027,type:phrase)))),(\u0027$state\u0027:(store:appState),meta:(alias:!n,disabled:!f,index:\u0027INDEX_PATTERN_ID\u0027,key:source.address,negate:!f,type:phrase,value:\u0027$source.address$\u0027),query:(match:(source.address:(query:\u0027$source.address$\u0027,type:phrase))))),index:\u0027INDEX_PATTERN_ID\u0027,interval:auto,query:(language:lucene,query:\u0027\u0027),sort:!(\u0027@timestamp\u0027,desc))"
+ }
+ ]
+ }
+}
diff --git a/x-pack/plugins/ml/server/models/data_recognizer/modules/apache_ecs/ml/status_code_rate_ecs.json b/x-pack/plugins/ml/server/models/data_recognizer/modules/apache_ecs/ml/status_code_rate_ecs.json
new file mode 100644
index 0000000000000..39bf67c71ae31
--- /dev/null
+++ b/x-pack/plugins/ml/server/models/data_recognizer/modules/apache_ecs/ml/status_code_rate_ecs.json
@@ -0,0 +1,41 @@
+{
+ "groups": ["apache"],
+ "description": "HTTP Access Logs: Detect unusual status_code rates (ECS)",
+ "analysis_config" : {
+ "bucket_span": "15m",
+ "detectors": [
+ {
+ "detector_description": "apache_access_status_code_rate",
+ "function": "count",
+ "partition_field_name": "http.response.status_code"
+ }
+ ],
+ "influencers": [
+ "http.response.status_code",
+ "source.address"
+ ]
+ },
+ "analysis_limits": {
+ "model_memory_limit": "100mb"
+ },
+ "data_description": {
+ "time_field": "@timestamp",
+ "time_format": "epoch_ms"
+ },
+ "model_plot_config": {
+ "enabled": true
+ },
+ "custom_settings": {
+ "created_by": "ml-module-apache-access",
+ "custom_urls": [
+ {
+ "url_name": "Investigate status code",
+ "url_value": "kibana#/dashboard/ml_http_access_explorer_ecs?_g=(time:(from:\u0027$earliest$\u0027,mode:absolute,to:\u0027$latest$\u0027))&_a=(description:\u0027\u0027,filters:!((\u0027$state\u0027:(store:appState),meta:(alias:!n,disabled:!f,index:\u0027INDEX_PATTERN_ID\u0027,key:event.dataset,negate:!f,params:(query:\u0027apache.access\u0027,type:phrase),type:phrase,value:\u0027apache.access\u0027),query:(match:(event.dataset:(query:\u0027apache.access\u0027,type:phrase)))),(\u0027$state\u0027:(store:appState),meta:(alias:!n,disabled:!f,index:\u0027INDEX_PATTERN_ID\u0027,key:http.response.status_code,negate:!f,params:(query:\u0027$http.response.status_code$\u0027,type:phrase),type:phrase,value:\u0027$http.response.status_code$\u0027),query:(match:(http.response.status_code:(query:\u0027$http.response.status_code$\u0027,type:phrase))))),query:(language:lucene,query:\u0027\u0027))"
+ },
+ {
+ "url_name": "Raw data",
+ "url_value": "kibana#/discover/ml_http_access_filebeat_ecs?_g=(time:(from:\u0027$earliest$\u0027,mode:absolute,to:\u0027$latest$\u0027))&_a=(columns:!(_source),filters:!((\u0027$state\u0027:(store:appState),meta:(alias:!n,disabled:!f,index:\u0027INDEX_PATTERN_ID\u0027,key:event.dataset,negate:!f,params:(query:\u0027apache.access\u0027,type:phrase),type:phrase,value:\u0027apache.access\u0027),query:(match:(event.dataset:(query:\u0027apache.access\u0027,type:phrase)))),(\u0027$state\u0027:(store:appState),meta:(alias:!n,disabled:!f,index:\u0027INDEX_PATTERN_ID\u0027,key:http.response.status_code,negate:!f,type:phrase,value:\u0027$http.response.status_code$\u0027),query:(match:(http.response.status_code:(query:\u0027$http.response.status_code$\u0027,type:phrase))))),index:\u0027INDEX_PATTERN_ID\u0027,interval:auto,query:(language:lucene,query:\u0027\u0027),sort:!(\u0027@timestamp\u0027,desc))"
+ }
+ ]
+ }
+}
\ No newline at end of file
diff --git a/x-pack/plugins/ml/server/models/data_recognizer/modules/apache_ecs/ml/visitor_rate_ecs.json b/x-pack/plugins/ml/server/models/data_recognizer/modules/apache_ecs/ml/visitor_rate_ecs.json
new file mode 100644
index 0000000000000..66ffde6bccf84
--- /dev/null
+++ b/x-pack/plugins/ml/server/models/data_recognizer/modules/apache_ecs/ml/visitor_rate_ecs.json
@@ -0,0 +1,34 @@
+{
+ "groups": ["apache"],
+ "description": "HTTP Access Logs: Detect unusual visitor rate (ECS)",
+ "analysis_config" : {
+ "bucket_span": "15m",
+ "summary_count_field_name": "dc_source_address",
+ "detectors": [
+ {
+ "detector_description": "apache_access_visitor_rate",
+ "function": "non_zero_count"
+ }
+ ],
+ "influencers": []
+ },
+ "analysis_limits": {
+ "model_memory_limit": "10mb"
+ },
+ "data_description": {
+ "time_field": "@timestamp",
+ "time_format": "epoch_ms"
+ },
+ "model_plot_config": {
+ "enabled": true
+ },
+ "custom_settings": {
+ "created_by": "ml-module-apache-access",
+ "custom_urls": [
+ {
+ "url_name": "Raw data",
+ "url_value": "kibana#/discover/ml_http_access_filebeat_ecs?_g=(time:(from:\u0027$earliest$\u0027,mode:absolute,to:\u0027$latest$\u0027))&_a=(columns:!(_source),filters:!((\u0027$state\u0027:(store:appState),meta:(alias:!n,disabled:!f,index:\u0027INDEX_PATTERN_ID\u0027,key:event.dataset,negate:!f,params:(query:\u0027apache.access\u0027,type:phrase),type:phrase,value:\u0027apache.access\u0027),query:(match:(event.dataset:(query:\u0027apache.access\u0027,type:phrase))))),index:\u0027INDEX_PATTERN_ID\u0027,interval:auto,query:(language:lucene,query:\u0027\u0027),sort:!(\u0027@timestamp\u0027,desc))"
+ }
+ ]
+ }
+}
diff --git a/x-pack/plugins/ml/server/models/data_recognizer/modules/nginx_ecs/kibana/dashboard/ml_http_access_explorer_ecs.json b/x-pack/plugins/ml/server/models/data_recognizer/modules/nginx_ecs/kibana/dashboard/ml_http_access_explorer_ecs.json
new file mode 100644
index 0000000000000..681ad572417f6
--- /dev/null
+++ b/x-pack/plugins/ml/server/models/data_recognizer/modules/nginx_ecs/kibana/dashboard/ml_http_access_explorer_ecs.json
@@ -0,0 +1,13 @@
+{
+ "hits": 0,
+ "timeRestore": false,
+ "description": "",
+ "title": "ML HTTP Access Explorer (ECS)",
+ "uiStateJSON": "{\"P-3\":{\"vis\":{\"params\":{\"sort\":{\"columnIndex\":null,\"direction\":null}}}},\"P-5\":{\"vis\":{\"params\":{\"sort\":{\"columnIndex\":null,\"direction\":null}}}}}",
+ "panelsJSON": "[{\"size_x\":6,\"size_y\":3,\"panelIndex\":1,\"type\":\"visualization\",\"id\":\"ml_http_access_events_timechart_ecs\",\"col\":1,\"row\":1},{\"size_x\":6,\"size_y\":3,\"panelIndex\":2,\"type\":\"visualization\",\"id\":\"ml_http_access_unique_count_url_timechart_ecs\",\"col\":7,\"row\":1},{\"size_x\":6,\"size_y\":3,\"panelIndex\":3,\"type\":\"visualization\",\"id\":\"ml_http_access_status_code_timechart_ecs\",\"col\":1,\"row\":4},{\"size_x\":6,\"size_y\":3,\"panelIndex\":4,\"type\":\"visualization\",\"id\":\"ml_http_access_source_ip_timechart_ecs\",\"col\":7,\"row\":4},{\"size_x\":6,\"size_y\":3,\"panelIndex\":5,\"type\":\"visualization\",\"id\":\"ml_http_access_top_source_ips_table_ecs\",\"col\":1,\"row\":8},{\"size_x\":6,\"size_y\":3,\"panelIndex\":6,\"type\":\"visualization\",\"id\":\"ml_http_access_map_ecs\",\"col\":7,\"row\":8},{\"size_x\":12,\"size_y\":9,\"panelIndex\":7,\"type\":\"visualization\",\"id\":\"ml_http_access_top_urls_table_ecs\",\"col\":1,\"row\":11}]",
+ "optionsJSON": "{\"darkTheme\":false}",
+ "version": 1,
+ "kibanaSavedObjectMeta": {
+ "searchSourceJSON": "{\n \"filter\": [],\n \"highlightAll\": true,\n \"version\": true,\n \"query\": {\n \"query\": \"\",\n \"language\": \"lucene\"\n }\n}"
+ }
+}
\ No newline at end of file
diff --git a/x-pack/plugins/ml/server/models/data_recognizer/modules/nginx_ecs/kibana/search/ml_http_access_filebeat_ecs.json b/x-pack/plugins/ml/server/models/data_recognizer/modules/nginx_ecs/kibana/search/ml_http_access_filebeat_ecs.json
new file mode 100644
index 0000000000000..6575c7e65d78d
--- /dev/null
+++ b/x-pack/plugins/ml/server/models/data_recognizer/modules/nginx_ecs/kibana/search/ml_http_access_filebeat_ecs.json
@@ -0,0 +1,16 @@
+{
+ "sort": [
+ "@timestamp",
+ "desc"
+ ],
+ "hits": 0,
+ "description": "Filebeat HTTP Access Data (ECS)",
+ "title": "ML HTTP Access Data (ECS)",
+ "version": 1,
+ "kibanaSavedObjectMeta": {
+ "searchSourceJSON": "{\"index\":\"INDEX_PATTERN_ID\",\"query\":{\"query_string\":{\"query\":\"fileset.name:access\",\"analyze_wildcard\":true}},\"filter\":[],\"highlight\":{\"pre_tags\":[\"@kibana-highlighted-field@\"],\"post_tags\":[\"@/kibana-highlighted-field@\"],\"fields\":{\"*\":{}},\"require_field_match\":false,\"fragment_size\":2147483647}}"
+ },
+ "columns": [
+ "_source"
+ ]
+}
diff --git a/x-pack/plugins/ml/server/models/data_recognizer/modules/nginx_ecs/kibana/visualization/ml_http_access_events_timechart_ecs.json b/x-pack/plugins/ml/server/models/data_recognizer/modules/nginx_ecs/kibana/visualization/ml_http_access_events_timechart_ecs.json
new file mode 100644
index 0000000000000..ff507da41d1a5
--- /dev/null
+++ b/x-pack/plugins/ml/server/models/data_recognizer/modules/nginx_ecs/kibana/visualization/ml_http_access_events_timechart_ecs.json
@@ -0,0 +1,11 @@
+{
+ "visState": "{\"title\":\"ML HTTP Access Event Timechart (ECS)\",\"type\":\"histogram\",\"params\":{\"shareYAxis\":true,\"addTooltip\":true,\"addLegend\":true,\"legendPosition\":\"right\",\"scale\":\"linear\",\"mode\":\"stacked\",\"times\":[],\"addTimeMarker\":false,\"defaultYExtents\":false,\"setYExtents\":false,\"yAxis\":{}},\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"schema\":\"metric\",\"params\":{}},{\"id\":\"2\",\"enabled\":true,\"type\":\"date_histogram\",\"schema\":\"segment\",\"params\":{\"field\":\"@timestamp\",\"interval\":\"auto\",\"customInterval\":\"2h\",\"min_doc_count\":1,\"extended_bounds\":{}}},{\"id\":\"3\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"group\",\"params\":{\"field\":\"event.module\",\"size\":10,\"order\":\"desc\",\"orderBy\":\"1\"}},{\"id\":\"4\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"group\",\"params\":{\"field\":\"event.dataset\",\"size\":10,\"order\":\"desc\",\"orderBy\":\"1\"}}],\"listeners\":{}}",
+ "description": "",
+ "title": "ML HTTP Access Event Timechart (ECS)",
+ "uiStateJSON": "{\"vis\":{\"colors\":{\"apache - access\":\"#629E51\",\"nginx - access\":\"#1F78C1\"}}}",
+ "version": 1,
+ "savedSearchId": "ml_http_access_filebeat_ecs",
+ "kibanaSavedObjectMeta": {
+ "searchSourceJSON": "{}"
+ }
+ }
\ No newline at end of file
diff --git a/x-pack/plugins/ml/server/models/data_recognizer/modules/nginx_ecs/kibana/visualization/ml_http_access_map_ecs.json b/x-pack/plugins/ml/server/models/data_recognizer/modules/nginx_ecs/kibana/visualization/ml_http_access_map_ecs.json
new file mode 100644
index 0000000000000..4cf3982f5ac6a
--- /dev/null
+++ b/x-pack/plugins/ml/server/models/data_recognizer/modules/nginx_ecs/kibana/visualization/ml_http_access_map_ecs.json
@@ -0,0 +1,11 @@
+{
+ "visState": "{\"aggs\":[{\"enabled\":true,\"id\":\"1\",\"params\":{},\"schema\":\"metric\",\"type\":\"count\"},{\"enabled\":true,\"id\":\"2\",\"params\":{\"autoPrecision\":true,\"field\":\"source.geo.location\"},\"schema\":\"segment\",\"type\":\"geohash_grid\"}],\"listeners\":{},\"params\":{\"addTooltip\":true,\"heatBlur\":15,\"heatMaxZoom\":16,\"heatMinOpacity\":0.1,\"heatNormalizeData\":true,\"heatRadius\":25,\"isDesaturated\":true,\"legendPosition\":\"bottomright\",\"mapCenter\":[15,5],\"mapType\":\"Scaled Circle Markers\",\"mapZoom\":2,\"wms\":{\"enabled\":false,\"options\":{\"attribution\":\"Maps provided by USGS\",\"format\":\"image/png\",\"layers\":\"0\",\"styles\":\"\",\"transparent\":true,\"version\":\"1.3.0\"},\"url\":\"https://basemap.nationalmap.gov/arcgis/services/USGSTopo/MapServer/WMSServer\"}},\"title\":\"ML HTTP Access Map (ECS)\",\"type\":\"tile_map\"}",
+ "description": "",
+ "title": "ML HTTP Access Map (ECS)",
+ "uiStateJSON": "{\n \"mapCenter\": [\n 12.039320557540572,\n -0.17578125\n ]\n}",
+ "version": 1,
+ "savedSearchId": "ml_http_access_filebeat_ecs",
+ "kibanaSavedObjectMeta": {
+ "searchSourceJSON": "{}"
+ }
+}
\ No newline at end of file
diff --git a/x-pack/plugins/ml/server/models/data_recognizer/modules/nginx_ecs/kibana/visualization/ml_http_access_source_ip_timechart_ecs.json b/x-pack/plugins/ml/server/models/data_recognizer/modules/nginx_ecs/kibana/visualization/ml_http_access_source_ip_timechart_ecs.json
new file mode 100644
index 0000000000000..8b2a9e14a74b8
--- /dev/null
+++ b/x-pack/plugins/ml/server/models/data_recognizer/modules/nginx_ecs/kibana/visualization/ml_http_access_source_ip_timechart_ecs.json
@@ -0,0 +1,11 @@
+{
+ "visState": "{\"title\":\"ML HTTP Access Source IP Timechart (ECS)\",\"type\":\"area\",\"params\":{\"addLegend\":true,\"addTimeMarker\":false,\"addTooltip\":true,\"categoryAxes\":[{\"id\":\"CategoryAxis-1\",\"labels\":{\"show\":true,\"truncate\":100},\"position\":\"bottom\",\"scale\":{\"type\":\"linear\"},\"show\":true,\"style\":{},\"title\":{\"text\":\"@timestamp per 5 minutes\"},\"type\":\"category\"}],\"defaultYExtents\":false,\"drawLinesBetweenPoints\":true,\"grid\":{\"categoryLines\":false,\"style\":{\"color\":\"#eee\"}},\"interpolate\":\"linear\",\"legendPosition\":\"right\",\"radiusRatio\":9,\"scale\":\"linear\",\"seriesParams\":[{\"data\":{\"id\":\"1\",\"label\":\"Count\"},\"drawLinesBetweenPoints\":true,\"interpolate\":\"linear\",\"mode\":\"stacked\",\"show\":\"true\",\"showCircles\":true,\"type\":\"area\",\"valueAxis\":\"ValueAxis-1\"}],\"setYExtents\":false,\"showCircles\":true,\"times\":[],\"valueAxes\":[{\"id\":\"ValueAxis-1\",\"labels\":{\"filter\":false,\"rotate\":0,\"show\":true,\"truncate\":100},\"name\":\"LeftAxis-1\",\"position\":\"left\",\"scale\":{\"mode\":\"normal\",\"type\":\"linear\"},\"show\":true,\"style\":{},\"title\":{},\"type\":\"value\"}]},\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"schema\":\"metric\",\"params\":{}},{\"id\":\"2\",\"enabled\":true,\"type\":\"date_histogram\",\"schema\":\"segment\",\"params\":{\"field\":\"@timestamp\",\"interval\":\"auto\",\"customInterval\":\"2h\",\"min_doc_count\":1,\"extended_bounds\":{}}},{\"id\":\"3\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"group\",\"params\":{\"field\":\"source.address\",\"size\":5,\"order\":\"desc\",\"orderBy\":\"1\"}}],\"listeners\":{}}",
+ "description": "",
+ "title": "ML HTTP Access Source IP Timechart (ECS)",
+ "uiStateJSON": "{}",
+ "version": 1,
+ "savedSearchId": "ml_http_access_filebeat_ecs",
+ "kibanaSavedObjectMeta": {
+ "searchSourceJSON": "{}"
+ }
+}
\ No newline at end of file
diff --git a/x-pack/plugins/ml/server/models/data_recognizer/modules/nginx_ecs/kibana/visualization/ml_http_access_status_code_timechart_ecs.json b/x-pack/plugins/ml/server/models/data_recognizer/modules/nginx_ecs/kibana/visualization/ml_http_access_status_code_timechart_ecs.json
new file mode 100644
index 0000000000000..e104b047f924b
--- /dev/null
+++ b/x-pack/plugins/ml/server/models/data_recognizer/modules/nginx_ecs/kibana/visualization/ml_http_access_status_code_timechart_ecs.json
@@ -0,0 +1,11 @@
+{
+ "visState": "{\"title\":\"ML HTTP Access Status Code Timechart (ECS)\",\"type\":\"histogram\",\"params\":{\"shareYAxis\":true,\"addTooltip\":true,\"addLegend\":true,\"legendPosition\":\"right\",\"scale\":\"linear\",\"mode\":\"stacked\",\"times\":[],\"addTimeMarker\":false,\"defaultYExtents\":false,\"setYExtents\":false,\"yAxis\":{}},\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"schema\":\"metric\",\"params\":{}},{\"id\":\"2\",\"enabled\":true,\"type\":\"date_histogram\",\"schema\":\"segment\",\"params\":{\"field\":\"@timestamp\",\"interval\":\"auto\",\"customInterval\":\"2h\",\"min_doc_count\":1,\"extended_bounds\":{}}},{\"id\":\"3\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"group\",\"params\":{\"field\":\"http.response.status_code\",\"size\":50,\"order\":\"desc\",\"orderBy\":\"1\"}}],\"listeners\":{}}",
+ "description": "",
+ "title": "ML HTTP Access Status Code Timechart (ECS)",
+ "uiStateJSON": "{\n \"vis\": {\n \"colors\": {\n \"200\": \"#7EB26D\",\n \"404\": \"#614D93\"\n }\n }\n}",
+ "version": 1,
+ "savedSearchId": "ml_http_access_filebeat_ecs",
+ "kibanaSavedObjectMeta": {
+ "searchSourceJSON": "{}"
+ }
+}
\ No newline at end of file
diff --git a/x-pack/plugins/ml/server/models/data_recognizer/modules/nginx_ecs/kibana/visualization/ml_http_access_top_source_ips_table_ecs.json b/x-pack/plugins/ml/server/models/data_recognizer/modules/nginx_ecs/kibana/visualization/ml_http_access_top_source_ips_table_ecs.json
new file mode 100644
index 0000000000000..c9afd66ea39b1
--- /dev/null
+++ b/x-pack/plugins/ml/server/models/data_recognizer/modules/nginx_ecs/kibana/visualization/ml_http_access_top_source_ips_table_ecs.json
@@ -0,0 +1,11 @@
+{
+ "visState": "{\"title\":\"ML HTTP Access Top Source IPs Table (ECS)\",\"type\":\"table\",\"params\":{\"perPage\":10,\"showPartialRows\":false,\"showMetricsAtAllLevels\":false,\"sort\":{\"columnIndex\":null,\"direction\":null},\"showTotal\":false,\"totalFunc\":\"sum\"},\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"schema\":\"metric\",\"params\":{}},{\"id\":\"2\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"bucket\",\"params\":{\"field\":\"source.address\",\"size\":50,\"order\":\"desc\",\"orderBy\":\"1\"}}],\"listeners\":{}}",
+ "description": "",
+ "title": "ML HTTP Access Top Source IPs Table (ECS)",
+ "uiStateJSON": "{\"vis\":{\"params\":{\"sort\":{\"columnIndex\":null,\"direction\":null}}}}",
+ "version": 1,
+ "savedSearchId": "ml_http_access_filebeat_ecs",
+ "kibanaSavedObjectMeta": {
+ "searchSourceJSON": "{}"
+ }
+}
\ No newline at end of file
diff --git a/x-pack/plugins/ml/server/models/data_recognizer/modules/nginx_ecs/kibana/visualization/ml_http_access_top_urls_table_ecs.json b/x-pack/plugins/ml/server/models/data_recognizer/modules/nginx_ecs/kibana/visualization/ml_http_access_top_urls_table_ecs.json
new file mode 100644
index 0000000000000..34fbcb621085c
--- /dev/null
+++ b/x-pack/plugins/ml/server/models/data_recognizer/modules/nginx_ecs/kibana/visualization/ml_http_access_top_urls_table_ecs.json
@@ -0,0 +1,11 @@
+{
+ "visState": "{\"title\":\"ML HTTP Access Top URLs Table (ECS)\",\"type\":\"table\",\"params\":{\"perPage\":100,\"showPartialRows\":false,\"showMetricsAtAllLevels\":false,\"sort\":{\"columnIndex\":null,\"direction\":null},\"showTotal\":false,\"totalFunc\":\"sum\"},\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"schema\":\"metric\",\"params\":{}},{\"id\":\"2\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"bucket\",\"params\":{\"field\":\"url.original\",\"size\":1000,\"order\":\"desc\",\"orderBy\":\"1\"}}],\"listeners\":{}}",
+ "description": "",
+ "title": "ML HTTP Access Top URLs Table (ECS)",
+ "uiStateJSON": "{\"vis\":{\"params\":{\"sort\":{\"columnIndex\":null,\"direction\":null}}}}",
+ "version": 1,
+ "savedSearchId": "ml_http_access_filebeat_ecs",
+ "kibanaSavedObjectMeta": {
+ "searchSourceJSON": "{}"
+ }
+}
\ No newline at end of file
diff --git a/x-pack/plugins/ml/server/models/data_recognizer/modules/nginx_ecs/kibana/visualization/ml_http_access_unique_count_url_timechart_ecs.json b/x-pack/plugins/ml/server/models/data_recognizer/modules/nginx_ecs/kibana/visualization/ml_http_access_unique_count_url_timechart_ecs.json
new file mode 100644
index 0000000000000..d14592e68bb6e
--- /dev/null
+++ b/x-pack/plugins/ml/server/models/data_recognizer/modules/nginx_ecs/kibana/visualization/ml_http_access_unique_count_url_timechart_ecs.json
@@ -0,0 +1,11 @@
+{
+ "visState": "{\"title\":\"ML HTTP Access Unique Count URL Timechart (ECS)\",\"type\":\"line\",\"params\":{\"grid\":{\"categoryLines\":false,\"style\":{\"color\":\"#eee\"}},\"categoryAxes\":[{\"id\":\"CategoryAxis-1\",\"type\":\"category\",\"position\":\"bottom\",\"show\":true,\"style\":{},\"scale\":{\"type\":\"linear\"},\"labels\":{\"show\":true,\"truncate\":100},\"title\":{\"text\":\"@timestamp per day\"}}],\"valueAxes\":[{\"id\":\"ValueAxis-1\",\"name\":\"LeftAxis-1\",\"type\":\"value\",\"position\":\"left\",\"show\":true,\"style\":{},\"scale\":{\"type\":\"linear\",\"mode\":\"normal\"},\"labels\":{\"show\":true,\"rotate\":0,\"filter\":false,\"truncate\":100},\"title\":{\"text\":\"Unique count of url.original\"}}],\"seriesParams\":[{\"show\":true,\"mode\":\"normal\",\"type\":\"line\",\"drawLinesBetweenPoints\":true,\"showCircles\":true,\"interpolate\":\"linear\",\"lineWidth\":2,\"data\":{\"id\":\"1\",\"label\":\"Unique count of url.original\"},\"valueAxis\":\"ValueAxis-1\"}],\"addTooltip\":true,\"addLegend\":true,\"legendPosition\":\"right\",\"showCircles\":true,\"interpolate\":\"linear\",\"scale\":\"linear\",\"drawLinesBetweenPoints\":true,\"radiusRatio\":9,\"times\":[],\"addTimeMarker\":false,\"defaultYExtents\":false,\"setYExtents\":false},\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"cardinality\",\"schema\":\"metric\",\"params\":{\"field\":\"url.original\"}},{\"id\":\"2\",\"enabled\":true,\"type\":\"date_histogram\",\"schema\":\"segment\",\"params\":{\"field\":\"@timestamp\",\"interval\":\"auto\",\"customInterval\":\"2h\",\"min_doc_count\":1,\"extended_bounds\":{}}}],\"listeners\":{}}",
+ "description": "",
+ "title": "ML HTTP Access Unique Count URL Timechart (ECS)",
+ "uiStateJSON": "{}",
+ "version": 1,
+ "savedSearchId": "ml_http_access_filebeat_ecs",
+ "kibanaSavedObjectMeta": {
+ "searchSourceJSON": "{}"
+ }
+}
\ No newline at end of file
diff --git a/x-pack/plugins/ml/server/models/data_recognizer/modules/nginx_ecs/logo.json b/x-pack/plugins/ml/server/models/data_recognizer/modules/nginx_ecs/logo.json
new file mode 100644
index 0000000000000..9372c36cbfa6d
--- /dev/null
+++ b/x-pack/plugins/ml/server/models/data_recognizer/modules/nginx_ecs/logo.json
@@ -0,0 +1,5 @@
+{
+ "src": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAlCAMAAAAUaRt1AAACPVBMVEUAcQAAdgAAfQAAfgAAfwAAgAAAggAAhAAAhQAAhgAAhwIAhwUAiAcAiAoAiQkAiQwAiQ8Aig4AihEAixMAixUAixcAjBYAjBcAjBkAjRgAjRoAjRwAjh0Ajh8Ajx8AjyAAkCIAkCMAkSMAkSUAkSYAkiYAkicAkigAkikAkykAkyoAkywAlCsAlC0AlS4AlTAAli8AljEAljIAlzIAlzMAlzUAmDQAmDYAmDcAmTcAmTgAmToAmTsAmjgAmjkAmjsEmToLmz0TnD4TnEAYnEAanUEcnkMfnkMhn0Qhn0UnoUcroksvo0svo0w4pVI+qFY+qFdEq1xFq1xIrF5KrF9KrWFLrWBNrWFNrmJPr2NTsWhUsGdVsWdXsWlYsmtZs2xbtW5puXhvvH1vvH5zv4N2v4R3wId3wYd6w4p/w4uAw4uAxIyBxIyBxY6CxY6ExY+FxpCHyJSJyZaMypmOy5uQypmRy5uSzJyUzZ2b0aed0aig06yj06ul1K2p1rCq1rGs2LWu2reu2rix2rex3Ly84MS94MO+4MO+4cS+4ca/4sfB4cbC48nJ5c3L5s7L5s/M59DM6NLN6NLO6NLO6dXQ6tbR69jU69bY7t7Z7t3Z7t7a79/b8OHc8OHe8OLf8ePh8OTh8uXm9Oro8+no9Ovp9Orp9ezq9ezq9u3r9u3s9e3s9e/u9e/u9/Hv+PPw9/Lx+PPy+fTy+fXz+fXz+vb0+vb3+/n3/Pn4/Pr5+/n6/Pr9/v3+/v7+//7///+8pzoSAAACRElEQVR42nXU91/TQBQA8CiUpli4po22jaVNRevosulLzgQXuAruiVi3uPceqKgI4sK6994b9wD927ykkRJI3g/Ju8v3k1zu7h311xCPly58YOwxgE/7AiGe29NpBU6nXQmME+74yW4zcGMBimAggSNo3rV+4FUjG5BE0EKUgp51zwzgd1Mlm5KgJySB5Y/8KIALdWgMBkPgKJpxVgf3Vrt4LMbjUAgxERdxmFl5h4DP2/1+kIVSjqMjiv58opfl0DgM3JCNX6hZZUkMac/ajovbOC4vJO/M8x1ZBoM0FtVSUfXjzqz6uTZHhayCmO82aVUHSCpHqIxA7iUHtBE327Sxhmp+kcaKQSqemgf2Xfmf3lGUFgH48e9IXo96g536tCy3yQRUvSHpElPQPc2uWIIrr8nleRApVuDQdPUdOTo4wgKcodar4nixb5I5aC8deEwVmwdUvTUFbYOH0pdUMafkozlwiyjwlCTfaq9agORk+5Qukr18ZAVAsTVo82EJRCjaqoNFqO9atBMAUrS42fiGwmrmGAJArqBzGsjqq6ktcFk96TlIqxYUxN8krfdCOL8fZjuThHjWtOwfPkrfcO6RW1qO1rEy4FR5hvq6yceBDE6nY/T/LalU0k6Hb4Ikct4NnWRX313FhDGk0tArUoKIh7mW3dLr4lzGFe1bFzFXTWuhsn428axgrKzQ4e+G2nzR6DHW5pN+1X19fk91l8+9bHY+/DmVYhIYJ92xE11WJ8xeLsT7d3+wOmFIPGxYfN/Y8w+Jrert1P9yBgAAAABJRU5ErkJggg==",
+ "height": 25,
+ "width": 120
+}
diff --git a/x-pack/plugins/ml/server/models/data_recognizer/modules/nginx_ecs/manifest.json b/x-pack/plugins/ml/server/models/data_recognizer/modules/nginx_ecs/manifest.json
new file mode 100644
index 0000000000000..bd31fcd23f504
--- /dev/null
+++ b/x-pack/plugins/ml/server/models/data_recognizer/modules/nginx_ecs/manifest.json
@@ -0,0 +1,111 @@
+{
+ "id": "nginx_ecs",
+ "title": "Nginx access logs",
+ "description": "Find unusual activity in HTTP access logs from filebeat (ECS)",
+ "type": "Web Access Logs",
+ "logoFile": "logo.json",
+ "defaultIndexPattern": "filebeat-*",
+ "query": {
+ "bool": {
+ "filter": [
+ { "term": { "event.dataset": "nginx.access" } },
+ { "exists": { "field": "source.address" } },
+ { "exists": { "field": "url.original" } },
+ { "exists": { "field": "http.response.status_code" } }
+ ]
+ }
+ },
+ "jobs": [
+ {
+ "id": "visitor_rate_ecs",
+ "file": "visitor_rate_ecs.json"
+ },
+ {
+ "id": "status_code_rate_ecs",
+ "file": "status_code_rate_ecs.json"
+ },
+ {
+ "id": "source_ip_url_count_ecs",
+ "file": "source_ip_url_count_ecs.json"
+ },
+ {
+ "id": "source_ip_request_rate_ecs",
+ "file": "source_ip_request_rate_ecs.json"
+ },
+ {
+ "id": "low_request_rate_ecs",
+ "file": "low_request_rate_ecs.json"
+ }
+ ],
+ "datafeeds": [
+ {
+ "id": "datafeed-visitor_rate_ecs",
+ "file": "datafeed_visitor_rate_ecs.json",
+ "job_id": "visitor_rate_ecs"
+ },
+ {
+ "id": "datafeed-status_code_rate_ecs",
+ "file": "datafeed_status_code_rate_ecs.json",
+ "job_id": "status_code_rate_ecs"
+ },
+ {
+ "id": "datafeed-source_ip_url_count_ecs",
+ "file": "datafeed_source_ip_url_count_ecs.json",
+ "job_id": "source_ip_url_count_ecs"
+ },
+ {
+ "id": "datafeed-source_ip_request_rate_ecs",
+ "file": "datafeed_source_ip_request_rate_ecs.json",
+ "job_id": "source_ip_request_rate_ecs"
+ },
+ {
+ "id": "datafeed-low_request_rate_ecs",
+ "file": "datafeed_low_request_rate_ecs.json",
+ "job_id": "low_request_rate_ecs"
+ }
+ ],
+ "kibana": {
+ "dashboard": [
+ {
+ "id": "ml_http_access_explorer_ecs",
+ "file": "ml_http_access_explorer_ecs.json"
+ }
+ ],
+ "search": [
+ {
+ "id": "ml_http_access_filebeat_ecs",
+ "file": "ml_http_access_filebeat_ecs.json"
+ }
+ ],
+ "visualization": [
+ {
+ "id": "ml_http_access_map_ecs",
+ "file": "ml_http_access_map_ecs.json"
+ },
+ {
+ "id": "ml_http_access_source_ip_timechart_ecs",
+ "file": "ml_http_access_source_ip_timechart_ecs.json"
+ },
+ {
+ "id": "ml_http_access_status_code_timechart_ecs",
+ "file": "ml_http_access_status_code_timechart_ecs.json"
+ },
+ {
+ "id": "ml_http_access_top_source_ips_table_ecs",
+ "file": "ml_http_access_top_source_ips_table_ecs.json"
+ },
+ {
+ "id": "ml_http_access_top_urls_table_ecs",
+ "file": "ml_http_access_top_urls_table_ecs.json"
+ },
+ {
+ "id": "ml_http_access_unique_count_url_timechart_ecs",
+ "file": "ml_http_access_unique_count_url_timechart_ecs.json"
+ },
+ {
+ "id": "ml_http_access_events_timechart_ecs",
+ "file": "ml_http_access_events_timechart_ecs.json"
+ }
+ ]
+ }
+}
diff --git a/x-pack/plugins/ml/server/models/data_recognizer/modules/nginx_ecs/ml/datafeed_low_request_rate_ecs.json b/x-pack/plugins/ml/server/models/data_recognizer/modules/nginx_ecs/ml/datafeed_low_request_rate_ecs.json
new file mode 100644
index 0000000000000..cf143071aa519
--- /dev/null
+++ b/x-pack/plugins/ml/server/models/data_recognizer/modules/nginx_ecs/ml/datafeed_low_request_rate_ecs.json
@@ -0,0 +1,34 @@
+{
+ "job_id": "JOB_ID",
+ "indexes": [
+ "INDEX_PATTERN_NAME"
+ ],
+ "query": {
+ "bool": {
+ "filter": [
+ { "term": { "event.dataset": "nginx.access" } }
+ ]
+ }
+ },
+ "aggregations": {
+ "buckets": {
+ "date_histogram": {
+ "field": "@timestamp",
+ "interval": 900000,
+ "offset": 0,
+ "order": {
+ "_key": "asc"
+ },
+ "keyed": false,
+ "min_doc_count": 0
+ },
+ "aggregations": {
+ "@timestamp": {
+ "max": {
+ "field": "@timestamp"
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/x-pack/plugins/ml/server/models/data_recognizer/modules/nginx_ecs/ml/datafeed_source_ip_request_rate_ecs.json b/x-pack/plugins/ml/server/models/data_recognizer/modules/nginx_ecs/ml/datafeed_source_ip_request_rate_ecs.json
new file mode 100644
index 0000000000000..bccf1bd8de6d5
--- /dev/null
+++ b/x-pack/plugins/ml/server/models/data_recognizer/modules/nginx_ecs/ml/datafeed_source_ip_request_rate_ecs.json
@@ -0,0 +1,13 @@
+{
+ "job_id": "JOB_ID",
+ "indexes": [
+ "INDEX_PATTERN_NAME"
+ ],
+ "query": {
+ "bool": {
+ "filter": [
+ { "term": { "event.dataset": "nginx.access" } }
+ ]
+ }
+ }
+}
diff --git a/x-pack/plugins/ml/server/models/data_recognizer/modules/nginx_ecs/ml/datafeed_source_ip_url_count_ecs.json b/x-pack/plugins/ml/server/models/data_recognizer/modules/nginx_ecs/ml/datafeed_source_ip_url_count_ecs.json
new file mode 100644
index 0000000000000..bccf1bd8de6d5
--- /dev/null
+++ b/x-pack/plugins/ml/server/models/data_recognizer/modules/nginx_ecs/ml/datafeed_source_ip_url_count_ecs.json
@@ -0,0 +1,13 @@
+{
+ "job_id": "JOB_ID",
+ "indexes": [
+ "INDEX_PATTERN_NAME"
+ ],
+ "query": {
+ "bool": {
+ "filter": [
+ { "term": { "event.dataset": "nginx.access" } }
+ ]
+ }
+ }
+}
diff --git a/x-pack/plugins/ml/server/models/data_recognizer/modules/nginx_ecs/ml/datafeed_status_code_rate_ecs.json b/x-pack/plugins/ml/server/models/data_recognizer/modules/nginx_ecs/ml/datafeed_status_code_rate_ecs.json
new file mode 100644
index 0000000000000..bccf1bd8de6d5
--- /dev/null
+++ b/x-pack/plugins/ml/server/models/data_recognizer/modules/nginx_ecs/ml/datafeed_status_code_rate_ecs.json
@@ -0,0 +1,13 @@
+{
+ "job_id": "JOB_ID",
+ "indexes": [
+ "INDEX_PATTERN_NAME"
+ ],
+ "query": {
+ "bool": {
+ "filter": [
+ { "term": { "event.dataset": "nginx.access" } }
+ ]
+ }
+ }
+}
diff --git a/x-pack/plugins/ml/server/models/data_recognizer/modules/nginx_ecs/ml/datafeed_visitor_rate_ecs.json b/x-pack/plugins/ml/server/models/data_recognizer/modules/nginx_ecs/ml/datafeed_visitor_rate_ecs.json
new file mode 100644
index 0000000000000..297bd16db4edf
--- /dev/null
+++ b/x-pack/plugins/ml/server/models/data_recognizer/modules/nginx_ecs/ml/datafeed_visitor_rate_ecs.json
@@ -0,0 +1,39 @@
+{
+ "job_id": "JOB_ID",
+ "indexes": [
+ "INDEX_PATTERN_NAME"
+ ],
+ "query": {
+ "bool": {
+ "filter": [
+ { "term": { "event.dataset": "nginx.access" } }
+ ]
+ }
+ },
+ "aggregations": {
+ "buckets": {
+ "date_histogram": {
+ "field": "@timestamp",
+ "interval": 900000,
+ "offset": 0,
+ "order": {
+ "_key": "asc"
+ },
+ "keyed": false,
+ "min_doc_count": 0
+ },
+ "aggregations": {
+ "@timestamp": {
+ "max": {
+ "field": "@timestamp"
+ }
+ },
+ "dc_source_address": {
+ "cardinality": {
+ "field": "source.address"
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/x-pack/plugins/ml/server/models/data_recognizer/modules/nginx_ecs/ml/low_request_rate_ecs.json b/x-pack/plugins/ml/server/models/data_recognizer/modules/nginx_ecs/ml/low_request_rate_ecs.json
new file mode 100644
index 0000000000000..22631813346dc
--- /dev/null
+++ b/x-pack/plugins/ml/server/models/data_recognizer/modules/nginx_ecs/ml/low_request_rate_ecs.json
@@ -0,0 +1,34 @@
+{
+ "groups": ["nginx"],
+ "description": "HTTP Access Logs: Detect low request rate (ECS)",
+ "analysis_config" : {
+ "bucket_span": "15m",
+ "summary_count_field_name": "doc_count",
+ "detectors": [
+ {
+ "detector_description": "nginx_access_low_request_rate",
+ "function": "low_count"
+ }
+ ],
+ "influencers": []
+ },
+ "analysis_limits": {
+ "model_memory_limit": "10mb"
+ },
+ "data_description": {
+ "time_field": "@timestamp",
+ "time_format": "epoch_ms"
+ },
+ "model_plot_config": {
+ "enabled": true
+ },
+ "custom_settings": {
+ "created_by": "ml-module-nginx-access",
+ "custom_urls": [
+ {
+ "url_name": "Raw data",
+ "url_value": "kibana#/discover/ml_http_access_filebeat_ecs?_g=(time:(from:\u0027$earliest$\u0027,mode:absolute,to:\u0027$latest$\u0027))&_a=(columns:!(_source),filters:!((\u0027$state\u0027:(store:appState),meta:(alias:!n,disabled:!f,index:\u0027INDEX_PATTERN_ID\u0027,key:event.dataset,negate:!f,params:(query:\u0027nginx.access\u0027,type:phrase),type:phrase,value:\u0027nginx.access\u0027),query:(match:(event.dataset:(query:\u0027nginx.access\u0027,type:phrase))))),index:\u0027INDEX_PATTERN_ID\u0027,interval:auto,query:(language:lucene,query:\u0027\u0027),sort:!(\u0027@timestamp\u0027,desc))"
+ }
+ ]
+ }
+}
diff --git a/x-pack/plugins/ml/server/models/data_recognizer/modules/nginx_ecs/ml/source_ip_request_rate_ecs.json b/x-pack/plugins/ml/server/models/data_recognizer/modules/nginx_ecs/ml/source_ip_request_rate_ecs.json
new file mode 100644
index 0000000000000..7d91ec8a81cd2
--- /dev/null
+++ b/x-pack/plugins/ml/server/models/data_recognizer/modules/nginx_ecs/ml/source_ip_request_rate_ecs.json
@@ -0,0 +1,34 @@
+{
+ "groups": ["nginx"],
+ "description": "HTTP Access Logs: Detect unusual source ips - high request rates (ECS)",
+ "analysis_config" : {
+ "bucket_span": "1h",
+ "detectors": [
+ {
+ "detector_description": "nginx_access_source_ip_high_count",
+ "function": "high_count",
+ "over_field_name": "source.address"
+ }
+ ],
+ "influencers": [
+ "source.address"
+ ]
+ },
+ "data_description": {
+ "time_field": "@timestamp",
+ "time_format": "epoch_ms"
+ },
+ "custom_settings": {
+ "created_by": "ml-module-nginx-access",
+ "custom_urls": [
+ {
+ "url_name": "Investigate source IP",
+ "url_value": "kibana#/dashboard/ml_http_access_explorer_ecs?_g=(time:(from:\u0027$earliest$\u0027,mode:absolute,to:\u0027$latest$\u0027))&_a=(description:\u0027\u0027,filters:!((\u0027$state\u0027:(store:appState),meta:(alias:!n,disabled:!f,index:\u0027INDEX_PATTERN_ID\u0027,key:event.dataset,negate:!f,params:(query:\u0027nginx.access\u0027,type:phrase),type:phrase,value:\u0027nginx.access\u0027),query:(match:(event.dataset:(query:\u0027nginx.access\u0027,type:phrase)))),(\u0027$state\u0027:(store:appState),meta:(alias:!n,disabled:!f,index:\u0027INDEX_PATTERN_ID\u0027,key:source.address,negate:!f,type:phrase,value:\u0027$source.address$\u0027),query:(match:(source.address:(query:\u0027$source.address$\u0027,type:phrase))))),query:(language:lucene,query:\u0027\u0027))"
+ },
+ {
+ "url_name": "Raw data",
+ "url_value": "kibana#/discover/ml_http_access_filebeat_ecs?_g=(time:(from:\u0027$earliest$\u0027,mode:absolute,to:\u0027$latest$\u0027))&_a=(columns:!(_source),filters:!((\u0027$state\u0027:(store:appState),meta:(alias:!n,disabled:!f,index:\u0027INDEX_PATTERN_ID\u0027,key:event.dataset,negate:!f,params:(query:\u0027nginx.access\u0027,type:phrase),type:phrase,value:\u0027nginx.access\u0027),query:(match:(event.dataset:(query:\u0027nginx.access\u0027,type:phrase)))),(\u0027$state\u0027:(store:appState),meta:(alias:!n,disabled:!f,index:\u0027INDEX_PATTERN_ID\u0027,key:source.address,negate:!f,type:phrase,value:\u0027$source.address$\u0027),query:(match:(source.address:(query:\u0027$source.address$\u0027,type:phrase))))),index:\u0027INDEX_PATTERN_ID\u0027,interval:auto,query:(language:lucene,query:\u0027\u0027),sort:!(\u0027@timestamp\u0027,desc))"
+ }
+ ]
+ }
+}
diff --git a/x-pack/plugins/ml/server/models/data_recognizer/modules/nginx_ecs/ml/source_ip_url_count_ecs.json b/x-pack/plugins/ml/server/models/data_recognizer/modules/nginx_ecs/ml/source_ip_url_count_ecs.json
new file mode 100644
index 0000000000000..dc965e7061b95
--- /dev/null
+++ b/x-pack/plugins/ml/server/models/data_recognizer/modules/nginx_ecs/ml/source_ip_url_count_ecs.json
@@ -0,0 +1,35 @@
+{
+ "groups": ["nginx"],
+ "description": "HTTP Access Logs: Detect unusual source ips - high distinct count of urls (ECS)",
+ "analysis_config" : {
+ "bucket_span": "1h",
+ "detectors": [
+ {
+ "detector_description": "nginx_access_source_ip_high_dc_url",
+ "function": "high_distinct_count",
+ "field_name": "url.original",
+ "over_field_name": "source.address"
+ }
+ ],
+ "influencers": [
+ "source.address"
+ ]
+ },
+ "data_description": {
+ "time_field": "@timestamp",
+ "time_format": "epoch_ms"
+ },
+ "custom_settings": {
+ "created_by": "ml-module-nginx-access",
+ "custom_urls": [
+ {
+ "url_name": "Investigate source IP",
+ "url_value": "kibana#/dashboard/ml_http_access_explorer_ecs?_g=(time:(from:\u0027$earliest$\u0027,mode:absolute,to:\u0027$latest$\u0027))&_a=(description:\u0027\u0027,filters:!((\u0027$state\u0027:(store:appState),meta:(alias:!n,disabled:!f,index:\u0027INDEX_PATTERN_ID\u0027,key:event.dataset,negate:!f,params:(query:\u0027nginx.access\u0027,type:phrase),type:phrase,value:\u0027nginx.access\u0027),query:(match:(event.dataset:(query:\u0027nginx.access\u0027,type:phrase)))),(\u0027$state\u0027:(store:appState),meta:(alias:!n,disabled:!f,index:\u0027INDEX_PATTERN_ID\u0027,key:source.address,negate:!f,type:phrase,value:\u0027$source.address$\u0027),query:(match:(source.address:(query:\u0027$source.address$\u0027,type:phrase))))),query:(language:lucene,query:\u0027\u0027))"
+ },
+ {
+ "url_name": "Raw data",
+ "url_value": "kibana#/discover/ml_http_access_filebeat_ecs?_g=(time:(from:\u0027$earliest$\u0027,mode:absolute,to:\u0027$latest$\u0027))&_a=(columns:!(_source),filters:!((\u0027$state\u0027:(store:appState),meta:(alias:!n,disabled:!f,index:\u0027INDEX_PATTERN_ID\u0027,key:event.dataset,negate:!f,params:(query:\u0027nginx.access\u0027,type:phrase),type:phrase,value:\u0027nginx.access\u0027),query:(match:(event.dataset:(query:\u0027nginx.access\u0027,type:phrase)))),(\u0027$state\u0027:(store:appState),meta:(alias:!n,disabled:!f,index:\u0027INDEX_PATTERN_ID\u0027,key:source.address,negate:!f,type:phrase,value:\u0027$source.address$\u0027),query:(match:(source.address:(query:\u0027$source.address$\u0027,type:phrase))))),index:\u0027INDEX_PATTERN_ID\u0027,interval:auto,query:(language:lucene,query:\u0027\u0027),sort:!(\u0027@timestamp\u0027,desc))"
+ }
+ ]
+ }
+}
diff --git a/x-pack/plugins/ml/server/models/data_recognizer/modules/nginx_ecs/ml/status_code_rate_ecs.json b/x-pack/plugins/ml/server/models/data_recognizer/modules/nginx_ecs/ml/status_code_rate_ecs.json
new file mode 100644
index 0000000000000..14cba15dd14f4
--- /dev/null
+++ b/x-pack/plugins/ml/server/models/data_recognizer/modules/nginx_ecs/ml/status_code_rate_ecs.json
@@ -0,0 +1,41 @@
+{
+ "groups": ["nginx"],
+ "description": "HTTP Access Logs: Detect unusual status_code rates (ECS)",
+ "analysis_config" : {
+ "bucket_span": "15m",
+ "detectors": [
+ {
+ "detector_description": "nginx_access_status_code_rate",
+ "function": "count",
+ "partition_field_name": "http.response.status_code"
+ }
+ ],
+ "influencers": [
+ "http.response.status_code",
+ "source.address"
+ ]
+ },
+ "analysis_limits": {
+ "model_memory_limit": "100mb"
+ },
+ "data_description": {
+ "time_field": "@timestamp",
+ "time_format": "epoch_ms"
+ },
+ "model_plot_config": {
+ "enabled": true
+ },
+ "custom_settings": {
+ "created_by": "ml-module-nginx-access",
+ "custom_urls": [
+ {
+ "url_name": "Investigate status code",
+ "url_value": "kibana#/dashboard/ml_http_access_explorer_ecs?_g=(time:(from:\u0027$earliest$\u0027,mode:absolute,to:\u0027$latest$\u0027))&_a=(description:\u0027\u0027,filters:!((\u0027$state\u0027:(store:appState),meta:(alias:!n,disabled:!f,index:\u0027INDEX_PATTERN_ID\u0027,key:event.dataset,negate:!f,params:(query:\u0027nginx.access\u0027,type:phrase),type:phrase,value:\u0027nginx.access\u0027),query:(match:(event.dataset:(query:\u0027nginx.access\u0027,type:phrase)))),(\u0027$state\u0027:(store:appState),meta:(alias:!n,disabled:!f,index:\u0027INDEX_PATTERN_ID\u0027,key:http.response.status_code,negate:!f,params:(query:\u0027$http.response.status_code$\u0027,type:phrase),type:phrase,value:\u0027$http.response.status_code$\u0027),query:(match:(http.response.status_code:(query:\u0027$http.response.status_code$\u0027,type:phrase))))),query:(language:lucene,query:\u0027\u0027))"
+ },
+ {
+ "url_name": "Raw data",
+ "url_value": "kibana#/discover/ml_http_access_filebeat_ecs?_g=(time:(from:\u0027$earliest$\u0027,mode:absolute,to:\u0027$latest$\u0027))&_a=(columns:!(_source),filters:!((\u0027$state\u0027:(store:appState),meta:(alias:!n,disabled:!f,index:\u0027INDEX_PATTERN_ID\u0027,key:event.dataset,negate:!f,params:(query:\u0027nginx.access\u0027,type:phrase),type:phrase,value:\u0027nginx.access\u0027),query:(match:(event.dataset:(query:\u0027nginx.access\u0027,type:phrase)))),(\u0027$state\u0027:(store:appState),meta:(alias:!n,disabled:!f,index:\u0027INDEX_PATTERN_ID\u0027,key:http.response.status_code,negate:!f,type:phrase,value:\u0027$http.response.status_code$\u0027),query:(match:(http.response.status_code:(query:\u0027$http.response.status_code$\u0027,type:phrase))))),index:\u0027INDEX_PATTERN_ID\u0027,interval:auto,query:(language:lucene,query:\u0027\u0027),sort:!(\u0027@timestamp\u0027,desc))"
+ }
+ ]
+ }
+}
\ No newline at end of file
diff --git a/x-pack/plugins/ml/server/models/data_recognizer/modules/nginx_ecs/ml/visitor_rate_ecs.json b/x-pack/plugins/ml/server/models/data_recognizer/modules/nginx_ecs/ml/visitor_rate_ecs.json
new file mode 100644
index 0000000000000..e0ba814facb8d
--- /dev/null
+++ b/x-pack/plugins/ml/server/models/data_recognizer/modules/nginx_ecs/ml/visitor_rate_ecs.json
@@ -0,0 +1,34 @@
+{
+ "groups": ["nginx"],
+ "description": "HTTP Access Logs: Detect unusual visitor rate (ECS)",
+ "analysis_config" : {
+ "bucket_span": "15m",
+ "summary_count_field_name": "dc_source_address",
+ "detectors": [
+ {
+ "detector_description": "nginx_access_visitor_rate",
+ "function": "non_zero_count"
+ }
+ ],
+ "influencers": []
+ },
+ "analysis_limits": {
+ "model_memory_limit": "10mb"
+ },
+ "data_description": {
+ "time_field": "@timestamp",
+ "time_format": "epoch_ms"
+ },
+ "model_plot_config": {
+ "enabled": true
+ },
+ "custom_settings": {
+ "created_by": "ml-module-nginx-access",
+ "custom_urls": [
+ {
+ "url_name": "Raw data",
+ "url_value": "kibana#/discover/ml_http_access_filebeat_ecs?_g=(time:(from:\u0027$earliest$\u0027,mode:absolute,to:\u0027$latest$\u0027))&_a=(columns:!(_source),filters:!((\u0027$state\u0027:(store:appState),meta:(alias:!n,disabled:!f,index:\u0027INDEX_PATTERN_ID\u0027,key:event.dataset,negate:!f,params:(query:\u0027nginx.access\u0027,type:phrase),type:phrase,value:\u0027nginx.access\u0027),query:(match:(event.dataset:(query:\u0027nginx.access\u0027,type:phrase))))),index:\u0027INDEX_PATTERN_ID\u0027,interval:auto,query:(language:lucene,query:\u0027\u0027),sort:!(\u0027@timestamp\u0027,desc))"
+ }
+ ]
+ }
+}
diff --git a/x-pack/plugins/monitoring/common/constants.js b/x-pack/plugins/monitoring/common/constants.js
index 372f0bd492d24..d87bb2c8be8fe 100644
--- a/x-pack/plugins/monitoring/common/constants.js
+++ b/x-pack/plugins/monitoring/common/constants.js
@@ -152,3 +152,10 @@ export const DEBOUNCE_FAST_MS = 10; // roughly how long it takes to render a fra
export const CLUSTER_ALERTS_ADDRESS_CONFIG_KEY = 'cluster_alerts.email_notifications.email_address';
export const STANDALONE_CLUSTER_CLUSTER_UUID = '__standalone_cluster__';
+
+export const INDEX_PATTERN = '.monitoring-*-6-*';
+export const INDEX_PATTERN_KIBANA = '.monitoring-kibana-6-*';
+export const INDEX_PATTERN_LOGSTASH = '.monitoring-logstash-6-*';
+export const INDEX_PATTERN_BEATS = '.monitoring-beats-6-*';
+export const INDEX_ALERTS = '.monitoring-alerts-6';
+export const INDEX_PATTERN_ELASTICSEARCH = '.monitoring-es-6-*';
diff --git a/x-pack/plugins/monitoring/config.js b/x-pack/plugins/monitoring/config.js
index 6074b8c34b232..0775d219c0238 100644
--- a/x-pack/plugins/monitoring/config.js
+++ b/x-pack/plugins/monitoring/config.js
@@ -30,23 +30,14 @@ export const config = (Joi) => {
}).default()
}).default()
}).default(),
- index_pattern: Joi.string().default('.monitoring-*-6-*'),
kibana: Joi.object({
- index_pattern: Joi.string().default('.monitoring-kibana-6-*'),
collection: Joi.object({
enabled: Joi.boolean().default(true),
interval: Joi.number().default(10000) // op status metrics get buffered at `ops.interval` and flushed to the bulk endpoint at this interval
}).default()
}).default(),
- logstash: Joi.object({
- index_pattern: Joi.string().default('.monitoring-logstash-6-*')
- }).default(),
- beats: Joi.object({
- index_pattern: Joi.string().default('.monitoring-beats-6-*')
- }).default(),
cluster_alerts: Joi.object({
enabled: Joi.boolean().default(true),
- index: Joi.string().default('.monitoring-alerts-6'),
email_notifications: Joi.object({
enabled: Joi.boolean().default(true),
email_address: Joi.string().email(),
@@ -62,7 +53,6 @@ export const config = (Joi) => {
}).default(),
elasticsearch: Joi.object({
customHeaders: Joi.object().default({}),
- index_pattern: Joi.string().default('.monitoring-es-6-*'),
logQueries: Joi.boolean().default(false),
requestHeadersWhitelist: Joi.array().items().single().default(DEFAULT_REQUEST_HEADERS),
sniffOnStart: Joi.boolean().default(false),
diff --git a/x-pack/plugins/monitoring/public/components/logstash/pipeline_listing/pipeline_listing.js b/x-pack/plugins/monitoring/public/components/logstash/pipeline_listing/pipeline_listing.js
index 99dc8afadaf12..73a78434e7116 100644
--- a/x-pack/plugins/monitoring/public/components/logstash/pipeline_listing/pipeline_listing.js
+++ b/x-pack/plugins/monitoring/public/components/logstash/pipeline_listing/pipeline_listing.js
@@ -16,8 +16,8 @@ import { injectI18n } from '@kbn/i18n/react';
import { i18n } from '@kbn/i18n';
class PipelineListingUI extends Component {
- tooltipXValueFormatter(xValue) {
- return moment(xValue).format(this.props.dateFormat);
+ tooltipXValueFormatter(xValue, dateFormat) {
+ return moment(xValue).format(dateFormat);
}
tooltipYValueFormatter(yValue, format, units) {
@@ -25,7 +25,7 @@ class PipelineListingUI extends Component {
}
getColumns() {
- const { onBrush } = this.props;
+ const { onBrush, dateFormat } = this.props;
const { kbnUrl, scope } = this.props.angular;
return [
@@ -66,7 +66,7 @@ class PipelineListingUI extends Component {
series={throughput.data}
onBrush={onBrush}
tooltip={{
- xValueFormatter: value => this.tooltipXValueFormatter(value),
+ xValueFormatter: value => this.tooltipXValueFormatter(value, dateFormat),
yValueFormatter: partialRight(this.tooltipYValueFormatter, throughput.metric.format, throughput.metric.units)
}}
options={{ xaxis: throughput.timeRange }}
@@ -100,7 +100,7 @@ class PipelineListingUI extends Component {
series={nodesCount.data}
onBrush={onBrush}
tooltip={{
- xValueFormatter: this.tooltipXValueFormatter,
+ xValueFormatter: value => this.tooltipXValueFormatter(value, dateFormat),
yValueFormatter: partialRight(this.tooltipYValueFormatter, nodesCount.metric.format, nodesCount.metric.units)
}}
options={{ xaxis: nodesCount.timeRange }}
diff --git a/x-pack/plugins/monitoring/public/services/title.js b/x-pack/plugins/monitoring/public/services/title.js
index 21e994ce970a2..15e9b0a6c8c4c 100644
--- a/x-pack/plugins/monitoring/public/services/title.js
+++ b/x-pack/plugins/monitoring/public/services/title.js
@@ -16,8 +16,8 @@ uiModule.service('title', (Private, i18n) => {
clusterName = (clusterName) ? `- ${clusterName}` : '';
suffix = (suffix) ? `- ${suffix}` : '';
docTitle.change(
- i18n('xpack.monitoring.monitoringDocTitle', {
- defaultMessage: 'Monitoring {clusterName} {suffix}',
+ i18n('xpack.monitoring.stackMonitoringDocTitle', {
+ defaultMessage: 'Stack Monitoring {clusterName} {suffix}',
values: { clusterName, suffix }
}), true);
};
diff --git a/x-pack/plugins/monitoring/public/views/logstash/node/pipelines/index.js b/x-pack/plugins/monitoring/public/views/logstash/node/pipelines/index.js
index d4ee051772899..f3adea3ecb75a 100644
--- a/x-pack/plugins/monitoring/public/views/logstash/node/pipelines/index.js
+++ b/x-pack/plugins/monitoring/public/views/logstash/node/pipelines/index.js
@@ -72,6 +72,7 @@ uiRoutes
controller: class extends MonitoringViewBaseEuiTableController {
constructor($injector, $scope, i18n) {
const kbnUrl = $injector.get('kbnUrl');
+ const config = $injector.get('config');
super({
defaultData: {},
@@ -103,6 +104,7 @@ uiRoutes
sorting={this.sorting}
pagination={this.pagination}
onTableChange={this.onTableChange}
+ dateFormat={config.get('dateFormat')}
upgradeMessage={makeUpgradeMessage(data.nodeSummary.version, i18n)}
angular={{
kbnUrl,
diff --git a/x-pack/plugins/monitoring/public/views/logstash/pipelines/index.js b/x-pack/plugins/monitoring/public/views/logstash/pipelines/index.js
index 1e88cc678b904..d800e565ba502 100644
--- a/x-pack/plugins/monitoring/public/views/logstash/pipelines/index.js
+++ b/x-pack/plugins/monitoring/public/views/logstash/pipelines/index.js
@@ -78,6 +78,7 @@ uiRoutes
const $route = $injector.get('$route');
const kbnUrl = $injector.get('kbnUrl');
+ const config = $injector.get('config');
this.data = $route.current.locals.pageData;
const globalState = $injector.get('globalState');
$scope.cluster = find($route.current.locals.clusters, { cluster_uuid: globalState.cluster_uuid });
@@ -110,6 +111,7 @@ uiRoutes
pagination={this.pagination}
onTableChange={this.onTableChange}
upgradeMessage={upgradeMessage}
+ dateFormat={config.get('dateFormat')}
angular={{
kbnUrl,
scope: $scope,
diff --git a/x-pack/plugins/monitoring/server/lib/__tests__/ccs_utils.js b/x-pack/plugins/monitoring/server/lib/__tests__/ccs_utils.js
index 8b2ae13803782..e2aa07ad78ee1 100644
--- a/x-pack/plugins/monitoring/server/lib/__tests__/ccs_utils.js
+++ b/x-pack/plugins/monitoring/server/lib/__tests__/ccs_utils.js
@@ -10,76 +10,65 @@ import { parseCrossClusterPrefix, prefixIndexPattern } from '../ccs_utils';
describe('ccs_utils', () => {
describe('prefixIndexPattern', () => {
- const indexPatternName = 'xyz';
const indexPattern = '.monitoring-xyz-1-*,.monitoring-xyz-2-*';
it('returns the index pattern if ccs is not enabled', () => {
const get = sinon.stub();
const config = { get };
- get.withArgs(indexPatternName).returns(indexPattern);
get.withArgs('xpack.monitoring.ccs.enabled').returns(false);
// falsy string values should be ignored
- const allPattern = prefixIndexPattern(config, indexPatternName, '*');
- const onePattern = prefixIndexPattern(config, indexPatternName, 'do_not_use_me');
+ const allPattern = prefixIndexPattern(config, indexPattern, '*');
+ const onePattern = prefixIndexPattern(config, indexPattern, 'do_not_use_me');
expect(allPattern).to.be(indexPattern);
expect(onePattern).to.be(indexPattern);
- // uses the config and indexPatternName supplied
- expect(get.callCount).to.eql(4);
+ expect(get.callCount).to.eql(2);
});
it('returns the index pattern if ccs is not used', () => {
const get = sinon.stub();
const config = { get };
- get.withArgs(indexPatternName).returns(indexPattern);
get.withArgs('xpack.monitoring.ccs.enabled').returns(true);
// falsy string values should be ignored
- const undefinedPattern = prefixIndexPattern(config, indexPatternName);
- const nullPattern = prefixIndexPattern(config, indexPatternName, null);
- const blankPattern = prefixIndexPattern(config, indexPatternName, '');
+ const undefinedPattern = prefixIndexPattern(config, indexPattern);
+ const nullPattern = prefixIndexPattern(config, indexPattern, null);
+ const blankPattern = prefixIndexPattern(config, indexPattern, '');
expect(undefinedPattern).to.be(indexPattern);
expect(nullPattern).to.be(indexPattern);
expect(blankPattern).to.be(indexPattern);
- // uses the config and indexPatternName supplied
- expect(get.callCount).to.eql(6);
+ expect(get.callCount).to.eql(3);
});
it('returns the ccs-prefixed index pattern', () => {
const get = sinon.stub();
const config = { get };
- get.withArgs(indexPatternName).returns(indexPattern);
get.withArgs('xpack.monitoring.ccs.enabled').returns(true);
- const abcPattern = prefixIndexPattern(config, indexPatternName, 'aBc');
- const underscorePattern = prefixIndexPattern(config, indexPatternName, 'cluster_one');
+ const abcPattern = prefixIndexPattern(config, indexPattern, 'aBc');
+ const underscorePattern = prefixIndexPattern(config, indexPattern, 'cluster_one');
expect(abcPattern).to.eql('aBc:.monitoring-xyz-1-*,aBc:.monitoring-xyz-2-*');
expect(underscorePattern).to.eql('cluster_one:.monitoring-xyz-1-*,cluster_one:.monitoring-xyz-2-*');
-
- // uses the config and indexPatternName supplied, but only calls once
- expect(get.callCount).to.eql(4);
+ expect(get.callCount).to.eql(2);
});
it('returns the ccs-prefixed index pattern when wildcard and the local cluster pattern', () => {
const get = sinon.stub();
const config = { get };
- get.withArgs(indexPatternName).returns(indexPattern);
get.withArgs('xpack.monitoring.ccs.enabled').returns(true);
- const pattern = prefixIndexPattern(config, indexPatternName, '*');
+ const pattern = prefixIndexPattern(config, indexPattern, '*');
// it should have BOTH patterns so that it searches all CCS clusters and the local cluster
expect(pattern).to.eql('*:.monitoring-xyz-1-*,*:.monitoring-xyz-2-*' + ',' + indexPattern);
-
- // uses the config and indexPatternName supplied, but only calls once
- expect(get.callCount).to.eql(2);
+ expect(get.callCount).to.eql(1);
});
});
diff --git a/x-pack/plugins/monitoring/server/lib/ccs_utils.js b/x-pack/plugins/monitoring/server/lib/ccs_utils.js
index d879a8d51c100..30409960edd9e 100644
--- a/x-pack/plugins/monitoring/server/lib/ccs_utils.js
+++ b/x-pack/plugins/monitoring/server/lib/ccs_utils.js
@@ -11,13 +11,12 @@
* which means that the index pattern will be returned without using {@code ccs}.
*
* @param {Object} config The Kibana configuration object.
- * @param {String} indexPatternName The index pattern name (e.g., 'xpack.monitoring.elasticsearch.index_pattern')
+ * @param {String} indexPattern The index pattern name
* @param {String} ccs The optional cluster-prefix to prepend.
* @return {String} The index pattern with the {@code cluster} prefix appropriately prepended.
*/
-export function prefixIndexPattern(config, indexPatternName, ccs) {
+export function prefixIndexPattern(config, indexPattern, ccs) {
const ccsEnabled = config.get('xpack.monitoring.ccs.enabled');
- const indexPattern = config.get(indexPatternName);
if (!ccsEnabled || !ccs) {
return indexPattern;
diff --git a/x-pack/plugins/monitoring/server/lib/elasticsearch/verify_monitoring_auth.js b/x-pack/plugins/monitoring/server/lib/elasticsearch/verify_monitoring_auth.js
index 609fc9d46394a..5462cd492fbc8 100644
--- a/x-pack/plugins/monitoring/server/lib/elasticsearch/verify_monitoring_auth.js
+++ b/x-pack/plugins/monitoring/server/lib/elasticsearch/verify_monitoring_auth.js
@@ -6,6 +6,7 @@
import { get } from 'lodash';
import Boom from 'boom';
+import { INDEX_PATTERN } from '../../../common/constants';
/*
* Check the currently logged-in user's privileges for "read" privileges on the
@@ -36,7 +37,6 @@ export async function verifyMonitoringAuth(req) {
*/
async function verifyHasPrivileges(req) {
const { callWithRequest } = req.server.plugins.elasticsearch.getCluster('monitoring');
- const config = req.server.config();
const response = await callWithRequest(req, 'transport.request', {
method: 'POST',
@@ -44,7 +44,7 @@ async function verifyHasPrivileges(req) {
body: {
index: [
{
- names: [ config.get('xpack.monitoring.index_pattern') ], // uses wildcard
+ names: [ INDEX_PATTERN ], // uses wildcard
privileges: [ 'read' ]
}
]
diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/alerts/index.js b/x-pack/plugins/monitoring/server/routes/api/v1/alerts/index.js
index d9cea7f88b322..093e71e66ee2d 100644
--- a/x-pack/plugins/monitoring/server/routes/api/v1/alerts/index.js
+++ b/x-pack/plugins/monitoring/server/routes/api/v1/alerts/index.js
@@ -9,6 +9,7 @@ import { alertsClusterSearch } from '../../../../cluster_alerts/alerts_cluster_s
import { checkLicense } from '../../../../cluster_alerts/check_license';
import { getClusterLicense } from '../../../../lib/cluster/get_cluster_license';
import { prefixIndexPattern } from '../../../../lib/ccs_utils';
+import { INDEX_PATTERN_ELASTICSEARCH, INDEX_ALERTS } from '../../../../../common/constants';
/*
* Cluster Alerts route.
@@ -35,8 +36,8 @@ export function clusterAlertsRoute(server) {
const config = server.config();
const ccs = req.payload.ccs;
const clusterUuid = req.params.clusterUuid;
- const esIndexPattern = prefixIndexPattern(config, 'xpack.monitoring.elasticsearch.index_pattern', ccs);
- const alertsIndex = prefixIndexPattern(config, 'xpack.monitoring.cluster_alerts.index', ccs);
+ const esIndexPattern = prefixIndexPattern(config, INDEX_PATTERN_ELASTICSEARCH, ccs);
+ const alertsIndex = prefixIndexPattern(config, INDEX_ALERTS, ccs);
const options = {
start: req.payload.timeRange.min,
end: req.payload.timeRange.max
diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/apm/instance.js b/x-pack/plugins/monitoring/server/routes/api/v1/apm/instance.js
index 7f9a79046d994..fad9e59902eed 100644
--- a/x-pack/plugins/monitoring/server/routes/api/v1/apm/instance.js
+++ b/x-pack/plugins/monitoring/server/routes/api/v1/apm/instance.js
@@ -10,6 +10,7 @@ import { getMetrics } from '../../../../lib/details/get_metrics';
import { metricSet } from './metric_set_overview';
import { handleError } from '../../../../lib/errors';
import { getApmInfo } from '../../../../lib/apm';
+import { INDEX_PATTERN_BEATS } from '../../../../../common/constants';
export function apmInstanceRoute(server) {
server.route({
@@ -35,7 +36,7 @@ export function apmInstanceRoute(server) {
const config = server.config();
const clusterUuid = req.params.clusterUuid;
const ccs = req.payload.ccs;
- const apmIndexPattern = prefixIndexPattern(config, 'xpack.monitoring.beats.index_pattern', ccs);
+ const apmIndexPattern = prefixIndexPattern(config, INDEX_PATTERN_BEATS, ccs);
try {
const [ metrics, apmSummary ] = await Promise.all([
diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/apm/instances.js b/x-pack/plugins/monitoring/server/routes/api/v1/apm/instances.js
index ec8c3cdd8d861..6a5ab2c45b9dc 100644
--- a/x-pack/plugins/monitoring/server/routes/api/v1/apm/instances.js
+++ b/x-pack/plugins/monitoring/server/routes/api/v1/apm/instances.js
@@ -8,6 +8,7 @@ import Joi from 'joi';
import { prefixIndexPattern } from '../../../../lib/ccs_utils';
import { getStats, getApms } from '../../../../lib/apm';
import { handleError } from '../../../../lib/errors';
+import { INDEX_PATTERN_BEATS } from '../../../../../common/constants';
export function apmInstancesRoute(server) {
server.route({
@@ -31,7 +32,7 @@ export function apmInstancesRoute(server) {
const config = server.config();
const ccs = req.payload.ccs;
const clusterUuid = req.params.clusterUuid;
- const apmIndexPattern = prefixIndexPattern(config, 'xpack.monitoring.beats.index_pattern', ccs);
+ const apmIndexPattern = prefixIndexPattern(config, INDEX_PATTERN_BEATS, ccs);
try {
diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/apm/overview.js b/x-pack/plugins/monitoring/server/routes/api/v1/apm/overview.js
index ecad1a444f7b0..66e39ce61ff77 100644
--- a/x-pack/plugins/monitoring/server/routes/api/v1/apm/overview.js
+++ b/x-pack/plugins/monitoring/server/routes/api/v1/apm/overview.js
@@ -10,6 +10,7 @@ import { getMetrics } from '../../../../lib/details/get_metrics';
import { metricSet } from './metric_set_overview';
import { handleError } from '../../../../lib/errors';
import { getApmClusterStatus } from './_get_apm_cluster_status';
+import { INDEX_PATTERN_BEATS } from '../../../../../common/constants';
export function apmOverviewRoute(server) {
server.route({
@@ -33,7 +34,7 @@ export function apmOverviewRoute(server) {
const config = server.config();
const ccs = req.payload.ccs;
const clusterUuid = req.params.clusterUuid;
- const apmIndexPattern = prefixIndexPattern(config, 'xpack.monitoring.beats.index_pattern', ccs);
+ const apmIndexPattern = prefixIndexPattern(config, INDEX_PATTERN_BEATS, ccs);
try {
const [
diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/beats/beat_detail.js b/x-pack/plugins/monitoring/server/routes/api/v1/beats/beat_detail.js
index 7bce52319c7e9..b8020fd007ba9 100644
--- a/x-pack/plugins/monitoring/server/routes/api/v1/beats/beat_detail.js
+++ b/x-pack/plugins/monitoring/server/routes/api/v1/beats/beat_detail.js
@@ -10,6 +10,7 @@ import { getBeatSummary } from '../../../../lib/beats';
import { getMetrics } from '../../../../lib/details/get_metrics';
import { handleError } from '../../../../lib/errors';
import { metricSet } from './metric_set_detail';
+import { INDEX_PATTERN_BEATS } from '../../../../../common/constants';
export function beatsDetailRoute(server) {
server.route({
@@ -36,7 +37,7 @@ export function beatsDetailRoute(server) {
const beatUuid = req.params.beatUuid;
const config = server.config();
const ccs = req.payload.ccs;
- const beatsIndexPattern = prefixIndexPattern(config, 'xpack.monitoring.beats.index_pattern', ccs);
+ const beatsIndexPattern = prefixIndexPattern(config, INDEX_PATTERN_BEATS, ccs);
const summaryOptions = {
clusterUuid,
diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/beats/beats.js b/x-pack/plugins/monitoring/server/routes/api/v1/beats/beats.js
index f2e7a46f0278a..282bbf7a353a4 100644
--- a/x-pack/plugins/monitoring/server/routes/api/v1/beats/beats.js
+++ b/x-pack/plugins/monitoring/server/routes/api/v1/beats/beats.js
@@ -8,6 +8,7 @@ import Joi from 'joi';
import { prefixIndexPattern } from '../../../../lib/ccs_utils';
import { getStats, getBeats } from '../../../../lib/beats';
import { handleError } from '../../../../lib/errors';
+import { INDEX_PATTERN_BEATS } from '../../../../../common/constants';
export function beatsListingRoute(server) {
server.route({
@@ -32,7 +33,7 @@ export function beatsListingRoute(server) {
const config = server.config();
const ccs = req.payload.ccs;
const clusterUuid = req.params.clusterUuid;
- const beatsIndexPattern = prefixIndexPattern(config, 'xpack.monitoring.beats.index_pattern', ccs);
+ const beatsIndexPattern = prefixIndexPattern(config, INDEX_PATTERN_BEATS, ccs);
try {
diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/beats/overview.js b/x-pack/plugins/monitoring/server/routes/api/v1/beats/overview.js
index b2f0267265538..0fc32f5c3de58 100644
--- a/x-pack/plugins/monitoring/server/routes/api/v1/beats/overview.js
+++ b/x-pack/plugins/monitoring/server/routes/api/v1/beats/overview.js
@@ -10,6 +10,7 @@ import { getMetrics } from '../../../../lib/details/get_metrics';
import { getLatestStats, getStats } from '../../../../lib/beats';
import { handleError } from '../../../../lib/errors';
import { metricSet } from './metric_set_overview';
+import { INDEX_PATTERN_BEATS } from '../../../../../common/constants';
export function beatsOverviewRoute(server) {
server.route({
@@ -34,7 +35,7 @@ export function beatsOverviewRoute(server) {
const config = server.config();
const ccs = req.payload.ccs;
const clusterUuid = req.params.clusterUuid;
- const beatsIndexPattern = prefixIndexPattern(config, 'xpack.monitoring.beats.index_pattern', ccs);
+ const beatsIndexPattern = prefixIndexPattern(config, INDEX_PATTERN_BEATS, ccs);
try {
const [
diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/cluster/cluster.js b/x-pack/plugins/monitoring/server/routes/api/v1/cluster/cluster.js
index 1b0d3d83f1316..7c3344626f852 100644
--- a/x-pack/plugins/monitoring/server/routes/api/v1/cluster/cluster.js
+++ b/x-pack/plugins/monitoring/server/routes/api/v1/cluster/cluster.js
@@ -8,6 +8,13 @@ import Joi from 'joi';
import { getClustersFromRequest } from '../../../../lib/cluster/get_clusters_from_request';
import { handleError } from '../../../../lib/errors';
import { prefixIndexPattern } from '../../../../lib/ccs_utils';
+import {
+ INDEX_PATTERN_KIBANA,
+ INDEX_PATTERN_ELASTICSEARCH,
+ INDEX_PATTERN_LOGSTASH,
+ INDEX_PATTERN_BEATS,
+ INDEX_ALERTS
+} from '../../../../../common/constants';
export function clusterRoute(server) {
/*
@@ -33,12 +40,12 @@ export function clusterRoute(server) {
handler: (req) => {
const config = server.config();
const ccs = req.payload.ccs;
- const esIndexPattern = prefixIndexPattern(config, 'xpack.monitoring.elasticsearch.index_pattern', ccs);
- const kbnIndexPattern = prefixIndexPattern(config, 'xpack.monitoring.kibana.index_pattern', ccs);
- const lsIndexPattern = prefixIndexPattern(config, 'xpack.monitoring.logstash.index_pattern', ccs);
- const beatsIndexPattern = prefixIndexPattern(config, 'xpack.monitoring.beats.index_pattern', ccs);
- const apmIndexPattern = prefixIndexPattern(config, 'xpack.monitoring.beats.index_pattern', ccs);
- const alertsIndex = prefixIndexPattern(config, 'xpack.monitoring.cluster_alerts.index', ccs);
+ const esIndexPattern = prefixIndexPattern(config, INDEX_PATTERN_ELASTICSEARCH, ccs);
+ const kbnIndexPattern = prefixIndexPattern(config, INDEX_PATTERN_KIBANA, ccs);
+ const lsIndexPattern = prefixIndexPattern(config, INDEX_PATTERN_LOGSTASH, ccs);
+ const beatsIndexPattern = prefixIndexPattern(config, INDEX_PATTERN_BEATS, ccs);
+ const apmIndexPattern = prefixIndexPattern(config, INDEX_PATTERN_BEATS, ccs);
+ const alertsIndex = prefixIndexPattern(config, INDEX_ALERTS, ccs);
const indexPatterns = { esIndexPattern, kbnIndexPattern, lsIndexPattern, beatsIndexPattern, apmIndexPattern, alertsIndex };
const options = {
clusterUuid: req.params.clusterUuid,
diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/cluster/clusters.js b/x-pack/plugins/monitoring/server/routes/api/v1/cluster/clusters.js
index 5d3a903ab38d7..2ce91020623df 100644
--- a/x-pack/plugins/monitoring/server/routes/api/v1/cluster/clusters.js
+++ b/x-pack/plugins/monitoring/server/routes/api/v1/cluster/clusters.js
@@ -9,6 +9,13 @@ import { getClustersFromRequest } from '../../../../lib/cluster/get_clusters_fro
import { verifyMonitoringAuth } from '../../../../lib/elasticsearch/verify_monitoring_auth';
import { handleError } from '../../../../lib/errors';
import { prefixIndexPattern } from '../../../../lib/ccs_utils';
+import {
+ INDEX_PATTERN_ELASTICSEARCH,
+ INDEX_PATTERN_KIBANA,
+ INDEX_PATTERN_LOGSTASH,
+ INDEX_PATTERN_BEATS,
+ INDEX_ALERTS
+} from '../../../../../common/constants';
export function clustersRoute(server) {
/*
@@ -40,12 +47,12 @@ export function clustersRoute(server) {
// wildcard means to search _all_ clusters
const ccs = '*';
const config = server.config();
- const esIndexPattern = prefixIndexPattern(config, 'xpack.monitoring.elasticsearch.index_pattern', ccs);
- const kbnIndexPattern = prefixIndexPattern(config, 'xpack.monitoring.kibana.index_pattern', ccs);
- const lsIndexPattern = prefixIndexPattern(config, 'xpack.monitoring.logstash.index_pattern', ccs);
- const beatsIndexPattern = prefixIndexPattern(config, 'xpack.monitoring.beats.index_pattern', ccs);
- const apmIndexPattern = prefixIndexPattern(config, 'xpack.monitoring.beats.index_pattern', ccs);
- const alertsIndex = prefixIndexPattern(config, 'xpack.monitoring.cluster_alerts.index', ccs);
+ const esIndexPattern = prefixIndexPattern(config, INDEX_PATTERN_ELASTICSEARCH, ccs);
+ const kbnIndexPattern = prefixIndexPattern(config, INDEX_PATTERN_KIBANA, ccs);
+ const lsIndexPattern = prefixIndexPattern(config, INDEX_PATTERN_LOGSTASH, ccs);
+ const beatsIndexPattern = prefixIndexPattern(config, INDEX_PATTERN_BEATS, ccs);
+ const apmIndexPattern = prefixIndexPattern(config, INDEX_PATTERN_BEATS, ccs);
+ const alertsIndex = prefixIndexPattern(config, INDEX_ALERTS, ccs);
const indexPatterns = { esIndexPattern, kbnIndexPattern, lsIndexPattern, beatsIndexPattern, apmIndexPattern, alertsIndex };
clusters = await getClustersFromRequest(req, indexPatterns);
diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/ccr.js b/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/ccr.js
index b3e85cdcee1e8..9047d1f676e85 100644
--- a/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/ccr.js
+++ b/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/ccr.js
@@ -9,6 +9,7 @@ import moment from 'moment';
import { get, groupBy } from 'lodash';
import { handleError } from '../../../../lib/errors/handle_error';
import { prefixIndexPattern } from '../../../../lib/ccs_utils';
+import { INDEX_PATTERN_ELASTICSEARCH } from '../../../../../common/constants';
function getBucketScript(max, min) {
return {
@@ -185,7 +186,7 @@ export function ccrRoute(server) {
async handler(req) {
const config = server.config();
const ccs = req.payload.ccs;
- const esIndexPattern = prefixIndexPattern(config, 'xpack.monitoring.elasticsearch.index_pattern', ccs);
+ const esIndexPattern = prefixIndexPattern(config, INDEX_PATTERN_ELASTICSEARCH, ccs);
try {
const { callWithRequest } = req.server.plugins.elasticsearch.getCluster('monitoring');
diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/ccr_shard.js b/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/ccr_shard.js
index cc8268a359911..955c32d5b6a79 100644
--- a/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/ccr_shard.js
+++ b/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/ccr_shard.js
@@ -10,6 +10,7 @@ import Joi from 'joi';
import { handleError } from '../../../../lib/errors/handle_error';
import { prefixIndexPattern } from '../../../../lib/ccs_utils';
import { getMetrics } from '../../../../lib/details/get_metrics';
+import { INDEX_PATTERN_ELASTICSEARCH } from '../../../../../common/constants';
function getFormattedLeaderIndex(leaderIndex) {
let leader = leaderIndex;
@@ -92,7 +93,7 @@ export function ccrShardRoute(server) {
const index = req.params.index;
const shardId = req.params.shardId;
const ccs = req.payload.ccs;
- const esIndexPattern = prefixIndexPattern(config, 'xpack.monitoring.elasticsearch.index_pattern', ccs);
+ const esIndexPattern = prefixIndexPattern(config, INDEX_PATTERN_ELASTICSEARCH, ccs);
const filters = [
{
diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/index_detail.js b/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/index_detail.js
index e27ec33db86ab..76ba483b0fdd7 100644
--- a/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/index_detail.js
+++ b/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/index_detail.js
@@ -13,6 +13,7 @@ import { getShardAllocation, getShardStats } from '../../../../lib/elasticsearch
import { handleError } from '../../../../lib/errors/handle_error';
import { prefixIndexPattern } from '../../../../lib/ccs_utils';
import { metricSet } from './metric_set_index_detail';
+import { INDEX_PATTERN_ELASTICSEARCH } from '../../../../../common/constants';
const { advanced: metricSetAdvanced, overview: metricSetOverview } = metricSet;
@@ -45,7 +46,7 @@ export function esIndexRoute(server) {
const indexUuid = req.params.id;
const start = req.payload.timeRange.min;
const end = req.payload.timeRange.max;
- const esIndexPattern = prefixIndexPattern(config, 'xpack.monitoring.elasticsearch.index_pattern', ccs);
+ const esIndexPattern = prefixIndexPattern(config, INDEX_PATTERN_ELASTICSEARCH, ccs);
const isAdvanced = req.payload.is_advanced;
const metricSet = isAdvanced ? metricSetAdvanced : metricSetOverview;
diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/indices.js b/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/indices.js
index 4e9d434372bae..22ad4f6e330c4 100644
--- a/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/indices.js
+++ b/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/indices.js
@@ -11,6 +11,7 @@ import { getIndices } from '../../../../lib/elasticsearch/indices';
import { getShardStats } from '../../../../lib/elasticsearch/shards';
import { handleError } from '../../../../lib/errors/handle_error';
import { prefixIndexPattern } from '../../../../lib/ccs_utils';
+import { INDEX_PATTERN_ELASTICSEARCH } from '../../../../../common/constants';
export function esIndicesRoute(server) {
server.route({
@@ -38,7 +39,7 @@ export function esIndicesRoute(server) {
const { clusterUuid } = req.params;
const { show_system_indices: showSystemIndices } = req.query;
const { ccs } = req.payload;
- const esIndexPattern = prefixIndexPattern(config, 'xpack.monitoring.elasticsearch.index_pattern', ccs);
+ const esIndexPattern = prefixIndexPattern(config, INDEX_PATTERN_ELASTICSEARCH, ccs);
try {
const clusterStats = await getClusterStats(req, esIndexPattern, clusterUuid);
diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/ml_jobs.js b/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/ml_jobs.js
index f6387bd1fa25e..a84e63539554e 100644
--- a/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/ml_jobs.js
+++ b/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/ml_jobs.js
@@ -11,6 +11,7 @@ import { getMlJobs } from '../../../../lib/elasticsearch/get_ml_jobs';
import { getShardStats } from '../../../../lib/elasticsearch/shards';
import { handleError } from '../../../../lib/errors/handle_error';
import { prefixIndexPattern } from '../../../../lib/ccs_utils';
+import { INDEX_PATTERN_ELASTICSEARCH } from '../../../../../common/constants';
export function mlJobRoute(server) {
server.route({
@@ -34,7 +35,7 @@ export function mlJobRoute(server) {
const config = server.config();
const ccs = req.payload.ccs;
const clusterUuid = req.params.clusterUuid;
- const esIndexPattern = prefixIndexPattern(config, 'xpack.monitoring.elasticsearch.index_pattern', ccs);
+ const esIndexPattern = prefixIndexPattern(config, INDEX_PATTERN_ELASTICSEARCH, ccs);
try {
const clusterStats = await getClusterStats(req, esIndexPattern, clusterUuid);
diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/node_detail.js b/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/node_detail.js
index 6f5d37930e7c1..2bec1646f896e 100644
--- a/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/node_detail.js
+++ b/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/node_detail.js
@@ -13,6 +13,7 @@ import { getMetrics } from '../../../../lib/details/get_metrics';
import { handleError } from '../../../../lib/errors/handle_error';
import { prefixIndexPattern } from '../../../../lib/ccs_utils';
import { metricSets } from './metric_set_node_detail';
+import { INDEX_PATTERN_ELASTICSEARCH } from '../../../../../common/constants';
const { advanced: metricSetAdvanced, overview: metricSetOverview } = metricSets;
@@ -45,7 +46,7 @@ export function esNodeRoute(server) {
const nodeUuid = req.params.nodeUuid;
const start = req.payload.timeRange.min;
const end = req.payload.timeRange.max;
- const esIndexPattern = prefixIndexPattern(config, 'xpack.monitoring.elasticsearch.index_pattern', ccs);
+ const esIndexPattern = prefixIndexPattern(config, INDEX_PATTERN_ELASTICSEARCH, ccs);
const isAdvanced = req.payload.is_advanced;
let metricSet;
diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/nodes.js b/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/nodes.js
index 7fe93e1394b21..217cc3d2262c9 100644
--- a/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/nodes.js
+++ b/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/nodes.js
@@ -11,6 +11,7 @@ import { getNodes } from '../../../../lib/elasticsearch/nodes';
import { getShardStats } from '../../../../lib/elasticsearch/shards';
import { handleError } from '../../../../lib/errors/handle_error';
import { prefixIndexPattern } from '../../../../lib/ccs_utils';
+import { INDEX_PATTERN_ELASTICSEARCH } from '../../../../../common/constants';
export function esNodesRoute(server) {
server.route({
@@ -34,7 +35,7 @@ export function esNodesRoute(server) {
const config = server.config();
const ccs = req.payload.ccs;
const clusterUuid = req.params.clusterUuid;
- const esIndexPattern = prefixIndexPattern(config, 'xpack.monitoring.elasticsearch.index_pattern', ccs);
+ const esIndexPattern = prefixIndexPattern(config, INDEX_PATTERN_ELASTICSEARCH, ccs);
try {
const clusterStats = await getClusterStats(req, esIndexPattern, clusterUuid);
diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/overview.js b/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/overview.js
index ad1d65c67b6b0..068c36f5064e9 100644
--- a/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/overview.js
+++ b/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/overview.js
@@ -13,6 +13,7 @@ import { getShardStats } from '../../../../lib/elasticsearch/shards';
import { handleError } from '../../../../lib/errors/handle_error';
import { prefixIndexPattern } from '../../../../lib/ccs_utils';
import { metricSet } from './metric_set_overview';
+import { INDEX_PATTERN_ELASTICSEARCH } from '../../../../../common/constants';
export function esOverviewRoute(server) {
server.route({
@@ -36,7 +37,7 @@ export function esOverviewRoute(server) {
const config = server.config();
const ccs = req.payload.ccs;
const clusterUuid = req.params.clusterUuid;
- const esIndexPattern = prefixIndexPattern(config, 'xpack.monitoring.elasticsearch.index_pattern', ccs);
+ const esIndexPattern = prefixIndexPattern(config, INDEX_PATTERN_ELASTICSEARCH, ccs);
try {
const [ clusterStats, metrics, shardActivity ] = await Promise.all([
diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/kibana/instance.js b/x-pack/plugins/monitoring/server/routes/api/v1/kibana/instance.js
index 6486ea530d53f..39d16c4e6fa97 100644
--- a/x-pack/plugins/monitoring/server/routes/api/v1/kibana/instance.js
+++ b/x-pack/plugins/monitoring/server/routes/api/v1/kibana/instance.js
@@ -10,6 +10,7 @@ import { handleError } from '../../../../lib/errors';
import { getMetrics } from '../../../../lib/details/get_metrics';
import { prefixIndexPattern } from '../../../../lib/ccs_utils';
import { metricSet } from './metric_set_instance';
+import { INDEX_PATTERN_KIBANA } from '../../../../../common/constants';
/**
* Kibana instance: This will fetch all data required to display a Kibana
@@ -41,7 +42,7 @@ export function kibanaInstanceRoute(server) {
const ccs = req.payload.ccs;
const clusterUuid = req.params.clusterUuid;
const kibanaUuid = req.params.kibanaUuid;
- const kbnIndexPattern = prefixIndexPattern(config, 'xpack.monitoring.kibana.index_pattern', ccs);
+ const kbnIndexPattern = prefixIndexPattern(config, INDEX_PATTERN_KIBANA, ccs);
try {
const [ metrics, kibanaSummary ] = await Promise.all([
diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/kibana/instances.js b/x-pack/plugins/monitoring/server/routes/api/v1/kibana/instances.js
index 580172ecd7ece..ca076fd8aec64 100644
--- a/x-pack/plugins/monitoring/server/routes/api/v1/kibana/instances.js
+++ b/x-pack/plugins/monitoring/server/routes/api/v1/kibana/instances.js
@@ -9,6 +9,7 @@ import { prefixIndexPattern } from '../../../../lib/ccs_utils';
import { getKibanaClusterStatus } from './_get_kibana_cluster_status';
import { getKibanas } from '../../../../lib/kibana/get_kibanas';
import { handleError } from '../../../../lib/errors';
+import { INDEX_PATTERN_KIBANA } from '../../../../../common/constants';
export function kibanaInstancesRoute(server) {
/**
@@ -35,7 +36,7 @@ export function kibanaInstancesRoute(server) {
const config = server.config();
const ccs = req.payload.ccs;
const clusterUuid = req.params.clusterUuid;
- const kbnIndexPattern = prefixIndexPattern(config, 'xpack.monitoring.kibana.index_pattern', ccs);
+ const kbnIndexPattern = prefixIndexPattern(config, INDEX_PATTERN_KIBANA, ccs);
try {
const [ clusterStatus, kibanas ] = await Promise.all([
diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/kibana/overview.js b/x-pack/plugins/monitoring/server/routes/api/v1/kibana/overview.js
index b7f396eef138f..275ac81127b97 100644
--- a/x-pack/plugins/monitoring/server/routes/api/v1/kibana/overview.js
+++ b/x-pack/plugins/monitoring/server/routes/api/v1/kibana/overview.js
@@ -10,6 +10,7 @@ import { getKibanaClusterStatus } from './_get_kibana_cluster_status';
import { getMetrics } from '../../../../lib/details/get_metrics';
import { metricSet } from './metric_set_overview';
import { handleError } from '../../../../lib/errors';
+import { INDEX_PATTERN_KIBANA } from '../../../../../common/constants';
export function kibanaOverviewRoute(server) {
/**
@@ -36,7 +37,7 @@ export function kibanaOverviewRoute(server) {
const config = server.config();
const ccs = req.payload.ccs;
const clusterUuid = req.params.clusterUuid;
- const kbnIndexPattern = prefixIndexPattern(config, 'xpack.monitoring.kibana.index_pattern', ccs);
+ const kbnIndexPattern = prefixIndexPattern(config, INDEX_PATTERN_KIBANA, ccs);
try {
const [ clusterStatus, metrics ] = await Promise.all([
diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/logstash/node.js b/x-pack/plugins/monitoring/server/routes/api/v1/logstash/node.js
index 6916fa871e810..28755903c82b8 100644
--- a/x-pack/plugins/monitoring/server/routes/api/v1/logstash/node.js
+++ b/x-pack/plugins/monitoring/server/routes/api/v1/logstash/node.js
@@ -10,6 +10,7 @@ import { handleError } from '../../../../lib/errors';
import { getMetrics } from '../../../../lib/details/get_metrics';
import { prefixIndexPattern } from '../../../../lib/ccs_utils';
import { metricSets } from './metric_set_node';
+import { INDEX_PATTERN_LOGSTASH } from '../../../../../common/constants';
const { advanced: metricSetAdvanced, overview: metricSetOverview } = metricSets;
@@ -50,7 +51,7 @@ export function logstashNodeRoute(server) {
const config = server.config();
const ccs = req.payload.ccs;
const clusterUuid = req.params.clusterUuid;
- const lsIndexPattern = prefixIndexPattern(config, 'xpack.monitoring.logstash.index_pattern', ccs);
+ const lsIndexPattern = prefixIndexPattern(config, INDEX_PATTERN_LOGSTASH, ccs);
const logstashUuid = req.params.logstashUuid;
let metricSet;
diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/logstash/nodes.js b/x-pack/plugins/monitoring/server/routes/api/v1/logstash/nodes.js
index 34e3b6cb2a4cc..f0af65bccaff5 100644
--- a/x-pack/plugins/monitoring/server/routes/api/v1/logstash/nodes.js
+++ b/x-pack/plugins/monitoring/server/routes/api/v1/logstash/nodes.js
@@ -9,6 +9,7 @@ import { getClusterStatus } from '../../../../lib/logstash/get_cluster_status';
import { getNodes } from '../../../../lib/logstash/get_nodes';
import { handleError } from '../../../../lib/errors';
import { prefixIndexPattern } from '../../../../lib/ccs_utils';
+import { INDEX_PATTERN_LOGSTASH } from '../../../../../common/constants';
/*
* Logstash Nodes route.
@@ -45,7 +46,7 @@ export function logstashNodesRoute(server) {
const config = server.config();
const ccs = req.payload.ccs;
const clusterUuid = req.params.clusterUuid;
- const lsIndexPattern = prefixIndexPattern(config, 'xpack.monitoring.logstash.index_pattern', ccs);
+ const lsIndexPattern = prefixIndexPattern(config, INDEX_PATTERN_LOGSTASH, ccs);
try {
const [ clusterStatus, nodes ] = await Promise.all([
diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/logstash/overview.js b/x-pack/plugins/monitoring/server/routes/api/v1/logstash/overview.js
index 35fe0271a1885..c8cfc5b74c9fc 100644
--- a/x-pack/plugins/monitoring/server/routes/api/v1/logstash/overview.js
+++ b/x-pack/plugins/monitoring/server/routes/api/v1/logstash/overview.js
@@ -10,6 +10,7 @@ import { getMetrics } from '../../../../lib/details/get_metrics';
import { handleError } from '../../../../lib/errors';
import { prefixIndexPattern } from '../../../../lib/ccs_utils';
import { metricSet } from './metric_set_overview';
+import { INDEX_PATTERN_LOGSTASH } from '../../../../../common/constants';
/*
* Logstash Overview route.
@@ -46,7 +47,7 @@ export function logstashOverviewRoute(server) {
const config = server.config();
const ccs = req.payload.ccs;
const clusterUuid = req.params.clusterUuid;
- const lsIndexPattern = prefixIndexPattern(config, 'xpack.monitoring.logstash.index_pattern', ccs);
+ const lsIndexPattern = prefixIndexPattern(config, INDEX_PATTERN_LOGSTASH, ccs);
try {
const [ metrics, clusterStatus ] = await Promise.all([
diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/logstash/pipeline.js b/x-pack/plugins/monitoring/server/routes/api/v1/logstash/pipeline.js
index 3a93dd57a9818..433c48f02b3ea 100644
--- a/x-pack/plugins/monitoring/server/routes/api/v1/logstash/pipeline.js
+++ b/x-pack/plugins/monitoring/server/routes/api/v1/logstash/pipeline.js
@@ -8,6 +8,7 @@ import Joi from 'joi';
import { handleError } from '../../../../lib/errors';
import { getPipeline } from '../../../../lib/logstash/get_pipeline';
import { prefixIndexPattern } from '../../../../lib/ccs_utils';
+import { INDEX_PATTERN_LOGSTASH } from '../../../../../common/constants';
/*
* Logstash Pipeline route.
@@ -41,7 +42,7 @@ export function logstashPipelineRoute(server) {
const config = server.config();
const ccs = req.payload.ccs;
const clusterUuid = req.params.clusterUuid;
- const lsIndexPattern = prefixIndexPattern(config, 'xpack.monitoring.logstash.index_pattern', ccs);
+ const lsIndexPattern = prefixIndexPattern(config, INDEX_PATTERN_LOGSTASH, ccs);
const pipelineId = req.params.pipelineId;
// Optional params default to empty string, set to null to be more explicit.
diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/logstash/pipelines/cluster_pipelines.js b/x-pack/plugins/monitoring/server/routes/api/v1/logstash/pipelines/cluster_pipelines.js
index 5a90e4ec9e9dc..247e734360dc9 100644
--- a/x-pack/plugins/monitoring/server/routes/api/v1/logstash/pipelines/cluster_pipelines.js
+++ b/x-pack/plugins/monitoring/server/routes/api/v1/logstash/pipelines/cluster_pipelines.js
@@ -9,6 +9,7 @@ import { getClusterStatus } from '../../../../../lib/logstash/get_cluster_status
import { getPipelines, processPipelinesAPIResponse } from '../../../../../lib/logstash/get_pipelines';
import { handleError } from '../../../../../lib/errors';
import { prefixIndexPattern } from '../../../../../lib/ccs_utils';
+import { INDEX_PATTERN_LOGSTASH } from '../../../../../../common/constants';
/**
* Retrieve pipelines for a cluster
@@ -35,7 +36,7 @@ export function logstashClusterPipelinesRoute(server) {
const config = server.config();
const { ccs } = req.payload;
const clusterUuid = req.params.clusterUuid;
- const lsIndexPattern = prefixIndexPattern(config, 'xpack.monitoring.logstash.index_pattern', ccs);
+ const lsIndexPattern = prefixIndexPattern(config, INDEX_PATTERN_LOGSTASH, ccs);
const throughputMetric = 'logstash_cluster_pipeline_throughput';
const nodesCountMetric = 'logstash_cluster_pipeline_nodes_count';
diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/logstash/pipelines/node_pipelines.js b/x-pack/plugins/monitoring/server/routes/api/v1/logstash/pipelines/node_pipelines.js
index 8aace30bb61f3..faec0791d7c32 100644
--- a/x-pack/plugins/monitoring/server/routes/api/v1/logstash/pipelines/node_pipelines.js
+++ b/x-pack/plugins/monitoring/server/routes/api/v1/logstash/pipelines/node_pipelines.js
@@ -9,6 +9,7 @@ import { getNodeInfo } from '../../../../../lib/logstash/get_node_info';
import { getPipelines, processPipelinesAPIResponse } from '../../../../../lib/logstash/get_pipelines';
import { handleError } from '../../../../../lib/errors';
import { prefixIndexPattern } from '../../../../../lib/ccs_utils';
+import { INDEX_PATTERN_LOGSTASH } from '../../../../../../common/constants';
/**
* Retrieve pipelines for a node
@@ -36,7 +37,7 @@ export function logstashNodePipelinesRoute(server) {
const config = server.config();
const { ccs } = req.payload;
const { clusterUuid, logstashUuid } = req.params;
- const lsIndexPattern = prefixIndexPattern(config, 'xpack.monitoring.logstash.index_pattern', ccs);
+ const lsIndexPattern = prefixIndexPattern(config, INDEX_PATTERN_LOGSTASH, ccs);
const throughputMetric = 'logstash_node_pipeline_throughput';
const nodesCountMetric = 'logstash_node_pipeline_nodes_count';
const metricSet = [
diff --git a/x-pack/plugins/rollup/public/extend_index_management/index.js b/x-pack/plugins/rollup/public/extend_index_management/index.js
index aa376736786e2..b0d94b94029d2 100644
--- a/x-pack/plugins/rollup/public/extend_index_management/index.js
+++ b/x-pack/plugins/rollup/public/extend_index_management/index.js
@@ -27,7 +27,8 @@ export const rollupBadgeExtension = {
label: i18n.translate('xpack.rollupJobs.indexMgmtBadge.rollupLabel', {
defaultMessage: 'Rollup',
}),
- color: 'secondary'
+ color: 'secondary',
+ filterExpression: 'isRollupIndex:true'
};
addBadgeExtension(rollupBadgeExtension);
diff --git a/x-pack/plugins/rollup/server/usage/collector.js b/x-pack/plugins/rollup/server/usage/collector.js
index 4cb9fba66ca67..d017740def9e3 100644
--- a/x-pack/plugins/rollup/server/usage/collector.js
+++ b/x-pack/plugins/rollup/server/usage/collector.js
@@ -102,8 +102,9 @@ async function fetchRollupVisualizations(kibanaIndex, callCluster, rollupIndexPa
index: kibanaIndex,
ignoreUnavailable: true,
filterPath: [
- 'hits.hits._source.visualization.savedSearchId',
+ 'hits.hits._source.visualization.savedSearchRefName',
'hits.hits._source.visualization.kibanaSavedObjectMeta',
+ 'hits.hits._source.references',
],
body: {
query: {
@@ -128,19 +129,21 @@ async function fetchRollupVisualizations(kibanaIndex, callCluster, rollupIndexPa
const {
_source: {
visualization: {
- savedSearchId,
+ savedSearchRefName,
kibanaSavedObjectMeta: {
searchSourceJSON,
},
},
+ references = [],
},
} = visualization;
const searchSource = JSON.parse(searchSourceJSON);
- if (savedSearchId) {
+ if (savedSearchRefName) {
// This visualization depends upon a saved search.
- if (rollupSavedSearchesToFlagMap[savedSearchId]) {
+ const savedSearch = references.find(ref => ref.name === savedSearchRefName);
+ if (rollupSavedSearchesToFlagMap[savedSearch.id]) {
rollupVisualizations++;
rollupVisualizationsFromSavedSearches++;
}
diff --git a/x-pack/plugins/spaces/server/lib/saved_objects_client/spaces_saved_objects_client.ts b/x-pack/plugins/spaces/server/lib/saved_objects_client/spaces_saved_objects_client.ts
index 5e86cd4f08c5e..9a3203305b59d 100644
--- a/x-pack/plugins/spaces/server/lib/saved_objects_client/spaces_saved_objects_client.ts
+++ b/x-pack/plugins/spaces/server/lib/saved_objects_client/spaces_saved_objects_client.ts
@@ -149,6 +149,7 @@ export class SpacesSavedObjectsClient implements SavedObjectsClient {
* @property {string} [options.sortOrder]
* @property {Array } [options.fields]
* @property {string} [options.namespace]
+ * @property {object} [options.hasReference] - { type, id }
* @returns {promise} - { saved_objects: [{ id, type, version, attributes }], total, per_page, page }
*/
public async find(options: FindOptions = {}) {
diff --git a/x-pack/plugins/spaces/server/lib/space_request_interceptors.test.ts b/x-pack/plugins/spaces/server/lib/space_request_interceptors.test.ts
index 9d9ad1417a3e9..7604cbc06f712 100644
--- a/x-pack/plugins/spaces/server/lib/space_request_interceptors.test.ts
+++ b/x-pack/plugins/spaces/server/lib/space_request_interceptors.test.ts
@@ -229,6 +229,7 @@ describe('interceptors', () => {
attributes: {
name: 'a space',
},
+ references: [],
},
];
@@ -265,6 +266,7 @@ describe('interceptors', () => {
attributes: {
name: 'a space',
},
+ references: [],
},
];
@@ -302,6 +304,7 @@ describe('interceptors', () => {
attributes: {
name: 'a space',
},
+ references: [],
},
];
@@ -348,6 +351,7 @@ describe('interceptors', () => {
attributes: {
name: 'Default Space',
},
+ references: [],
},
];
@@ -379,6 +383,7 @@ describe('interceptors', () => {
attributes: {
name: 'a space',
},
+ references: [],
},
{
id: 'b-space',
@@ -386,6 +391,7 @@ describe('interceptors', () => {
attributes: {
name: 'b space',
},
+ references: [],
},
];
diff --git a/x-pack/plugins/uptime/index.ts b/x-pack/plugins/uptime/index.ts
index f369c3d73681d..ac9322e7bd141 100644
--- a/x-pack/plugins/uptime/index.ts
+++ b/x-pack/plugins/uptime/index.ts
@@ -23,7 +23,7 @@ export const uptime = (kibana: any) =>
description: 'The description text that will be shown to users in Kibana',
}),
icon: 'plugins/uptime/icons/heartbeat_white.svg',
- euiIconType: 'heartbeatApp',
+ euiIconType: 'uptimeApp',
title: 'Uptime',
main: 'plugins/uptime/app',
order: 8900,
diff --git a/x-pack/plugins/xpack_main/common/constants.js b/x-pack/plugins/xpack_main/common/constants.js
index 5f0b956fb1da6..1dec1a2264ea0 100644
--- a/x-pack/plugins/xpack_main/common/constants.js
+++ b/x-pack/plugins/xpack_main/common/constants.js
@@ -34,6 +34,12 @@ export const KIBANA_SYSTEM_ID = 'kibana';
*/
export const BEATS_SYSTEM_ID = 'beats';
+/**
+ * The name of the Apm System ID used to publish and look up Apm stats through the Monitoring system.
+ * @type {string}
+ */
+export const APM_SYSTEM_ID = 'beats';
+
/**
* The name of the Kibana System ID used to look up Logstash stats through the Monitoring system.
* @type {string}
diff --git a/x-pack/plugins/xpack_main/server/lib/telemetry/monitoring/get_beats_stats.js b/x-pack/plugins/xpack_main/server/lib/telemetry/monitoring/get_beats_stats.js
index 321e2ebdad642..d38d8f519c047 100644
--- a/x-pack/plugins/xpack_main/server/lib/telemetry/monitoring/get_beats_stats.js
+++ b/x-pack/plugins/xpack_main/server/lib/telemetry/monitoring/get_beats_stats.js
@@ -6,6 +6,7 @@
import { get } from 'lodash';
import { createQuery } from './create_query';
+import { INDEX_PATTERN_BEATS } from '../../../../../monitoring/common/constants';
const HITS_SIZE = 10000; // maximum hits to receive from ES with each search
@@ -173,10 +174,8 @@ export function processResults(results = [], { clusters, clusterHostSets, cluste
* @return {Promise}
*/
async function fetchBeatsByType(server, callCluster, clusterUuids, start, end, { page = 0, ...options } = {}, type) {
- const config = server.config();
-
const params = {
- index: config.get('xpack.monitoring.beats.index_pattern'),
+ index: INDEX_PATTERN_BEATS,
ignoreUnavailable: true,
filterPath: [
'hits.hits._source.cluster_uuid',
diff --git a/x-pack/plugins/xpack_main/server/lib/telemetry/monitoring/get_cluster_uuids.js b/x-pack/plugins/xpack_main/server/lib/telemetry/monitoring/get_cluster_uuids.js
index f573a71b77d5e..9f8aac44a4728 100644
--- a/x-pack/plugins/xpack_main/server/lib/telemetry/monitoring/get_cluster_uuids.js
+++ b/x-pack/plugins/xpack_main/server/lib/telemetry/monitoring/get_cluster_uuids.js
@@ -6,6 +6,7 @@
import { get } from 'lodash';
import { createQuery } from './create_query';
+import { INDEX_PATTERN_ELASTICSEARCH } from '../../../../../monitoring/common/constants';
/**
* Get a list of Cluster UUIDs that exist within the specified timespan.
@@ -33,7 +34,7 @@ export function getClusterUuids(server, callCluster, start, end) {
export function fetchClusterUuids(server, callCluster, start, end) {
const config = server.config();
const params = {
- index: config.get('xpack.monitoring.elasticsearch.index_pattern'),
+ index: INDEX_PATTERN_ELASTICSEARCH,
size: 0,
ignoreUnavailable: true,
filterPath: 'aggregations.cluster_uuids.buckets.key',
diff --git a/x-pack/plugins/xpack_main/server/lib/telemetry/monitoring/get_es_stats.js b/x-pack/plugins/xpack_main/server/lib/telemetry/monitoring/get_es_stats.js
index 377ce8160f2b4..55198a5ec85d4 100644
--- a/x-pack/plugins/xpack_main/server/lib/telemetry/monitoring/get_es_stats.js
+++ b/x-pack/plugins/xpack_main/server/lib/telemetry/monitoring/get_es_stats.js
@@ -5,6 +5,7 @@
*/
import { get } from 'lodash';
+import { INDEX_PATTERN_ELASTICSEARCH } from '../../../../../monitoring/common/constants';
/**
* Get statistics for all selected Elasticsearch clusters.
@@ -30,7 +31,7 @@ export function getElasticsearchStats(server, callCluster, clusterUuids) {
export function fetchElasticsearchStats(server, callCluster, clusterUuids) {
const config = server.config();
const params = {
- index: config.get('xpack.monitoring.elasticsearch.index_pattern'),
+ index: INDEX_PATTERN_ELASTICSEARCH,
size: config.get('xpack.monitoring.max_bucket_size'),
ignoreUnavailable: true,
filterPath: [
diff --git a/x-pack/plugins/xpack_main/server/lib/telemetry/monitoring/get_high_level_stats.js b/x-pack/plugins/xpack_main/server/lib/telemetry/monitoring/get_high_level_stats.js
index b845fb5115492..fbbb81d6fd89e 100644
--- a/x-pack/plugins/xpack_main/server/lib/telemetry/monitoring/get_high_level_stats.js
+++ b/x-pack/plugins/xpack_main/server/lib/telemetry/monitoring/get_high_level_stats.js
@@ -6,6 +6,8 @@
import { get } from 'lodash';
import { createQuery } from './create_query';
+import { INDEX_PATTERN_KIBANA, INDEX_PATTERN_BEATS, INDEX_PATTERN_LOGSTASH } from '../../../../../monitoring/common/constants';
+import { KIBANA_SYSTEM_ID, BEATS_SYSTEM_ID, APM_SYSTEM_ID, LOGSTASH_SYSTEM_ID } from '../../../../common/constants';
/**
* Update a counter associated with the {@code key}.
@@ -139,6 +141,24 @@ function mapToList(map, keyName) {
return list;
}
+/**
+ * Returns the right index pattern to find monitoring documents based on the product id
+ *
+ * @param {*} product The product id, which should be in the constants file
+ */
+function getIndexPatternForStackProduct(product) {
+ switch (product) {
+ case KIBANA_SYSTEM_ID:
+ return INDEX_PATTERN_KIBANA;
+ case BEATS_SYSTEM_ID:
+ case APM_SYSTEM_ID:
+ return INDEX_PATTERN_BEATS;
+ case LOGSTASH_SYSTEM_ID:
+ return INDEX_PATTERN_LOGSTASH;
+ }
+ return null;
+}
+
/**
* Get statistics about selected Elasticsearch clusters, for the selected {@code product}.
*
@@ -170,7 +190,7 @@ export function getHighLevelStats(server, callCluster, clusterUuids, start, end,
export function fetchHighLevelStats(server, callCluster, clusterUuids, start, end, product) {
const config = server.config();
const params = {
- index: config.get(`xpack.monitoring.${product}.index_pattern`),
+ index: getIndexPatternForStackProduct(product),
size: config.get('xpack.monitoring.max_bucket_size'),
ignoreUnavailable: true,
filterPath: [
diff --git a/x-pack/test/api_integration/apis/infra/index.js b/x-pack/test/api_integration/apis/infra/index.js
index 595f931a1e8fc..1471e4fe8084a 100644
--- a/x-pack/test/api_integration/apis/infra/index.js
+++ b/x-pack/test/api_integration/apis/infra/index.js
@@ -14,5 +14,6 @@ export default function ({ loadTestFile }) {
loadTestFile(require.resolve('./metrics'));
loadTestFile(require.resolve('./sources'));
loadTestFile(require.resolve('./waffle'));
+ loadTestFile(require.resolve('./log_item'));
});
}
diff --git a/x-pack/test/api_integration/apis/infra/log_item.ts b/x-pack/test/api_integration/apis/infra/log_item.ts
new file mode 100644
index 0000000000000..bfdde32fa57ae
--- /dev/null
+++ b/x-pack/test/api_integration/apis/infra/log_item.ts
@@ -0,0 +1,175 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import expect from 'expect.js';
+import { flyoutItemQuery } from '../../../../plugins/infra/public/containers/logs/flyout_item.gql_query';
+import { FlyoutItemQuery } from '../../../../plugins/infra/public/graphql/types';
+import { KbnTestProvider } from './types';
+
+const logItemTests: KbnTestProvider = ({ getService }) => {
+ const esArchiver = getService('esArchiver');
+ const client = getService('infraOpsGraphQLClient');
+ describe('Log Item GraphQL Endpoint', () => {
+ before(() => esArchiver.load('infra/metrics_and_logs'));
+ after(() => esArchiver.unload('infra/metrics_and_logs'));
+
+ it('should basically work', () => {
+ return client
+ .query({
+ query: flyoutItemQuery,
+ variables: {
+ sourceId: 'default',
+ itemId: 'yT2Mg2YBh-opCxJv8Vqj',
+ },
+ })
+ .then(resp => {
+ expect(resp.data.source).to.have.property('logItem');
+ const { logItem } = resp.data.source;
+ if (!logItem) {
+ throw new Error('Log item should not be falsey');
+ }
+ expect(logItem).to.have.property('id', 'yT2Mg2YBh-opCxJv8Vqj');
+ expect(logItem).to.have.property('index', 'filebeat-7.0.0-alpha1-2018.10.17');
+ expect(logItem).to.have.property('fields');
+ expect(logItem.fields).to.eql([
+ {
+ field: '@timestamp',
+ value: '2018-10-17T19:42:22.000Z',
+ __typename: 'InfraLogItemField',
+ },
+ {
+ field: '_id',
+ value: 'yT2Mg2YBh-opCxJv8Vqj',
+ __typename: 'InfraLogItemField',
+ },
+ {
+ field: '_index',
+ value: 'filebeat-7.0.0-alpha1-2018.10.17',
+ __typename: 'InfraLogItemField',
+ },
+ {
+ field: 'apache2.access.body_sent.bytes',
+ value: '1336',
+ __typename: 'InfraLogItemField',
+ },
+ {
+ field: 'apache2.access.http_version',
+ value: '1.1',
+ __typename: 'InfraLogItemField',
+ },
+ {
+ field: 'apache2.access.method',
+ value: 'GET',
+ __typename: 'InfraLogItemField',
+ },
+ {
+ field: 'apache2.access.referrer',
+ value: '-',
+ __typename: 'InfraLogItemField',
+ },
+ {
+ field: 'apache2.access.remote_ip',
+ value: '10.128.0.11',
+ __typename: 'InfraLogItemField',
+ },
+ {
+ field: 'apache2.access.response_code',
+ value: '200',
+ __typename: 'InfraLogItemField',
+ },
+ {
+ field: 'apache2.access.url',
+ value: '/a-fresh-start-will-put-you-on-your-way',
+ __typename: 'InfraLogItemField',
+ },
+ {
+ field: 'apache2.access.user_agent.device',
+ value: 'Other',
+ __typename: 'InfraLogItemField',
+ },
+ {
+ field: 'apache2.access.user_agent.name',
+ value: 'Other',
+ __typename: 'InfraLogItemField',
+ },
+ {
+ field: 'apache2.access.user_agent.os',
+ value: 'Other',
+ __typename: 'InfraLogItemField',
+ },
+ {
+ field: 'apache2.access.user_agent.os_name',
+ value: 'Other',
+ __typename: 'InfraLogItemField',
+ },
+ {
+ field: 'apache2.access.user_name',
+ value: '-',
+ __typename: 'InfraLogItemField',
+ },
+ {
+ field: 'beat.hostname',
+ value: 'demo-stack-apache-01',
+ __typename: 'InfraLogItemField',
+ },
+ {
+ field: 'beat.name',
+ value: 'demo-stack-apache-01',
+ __typename: 'InfraLogItemField',
+ },
+ {
+ field: 'beat.version',
+ value: '7.0.0-alpha1',
+ __typename: 'InfraLogItemField',
+ },
+ {
+ field: 'fileset.module',
+ value: 'apache2',
+ __typename: 'InfraLogItemField',
+ },
+ {
+ field: 'fileset.name',
+ value: 'access',
+ __typename: 'InfraLogItemField',
+ },
+ {
+ field: 'host.name',
+ value: 'demo-stack-apache-01',
+ __typename: 'InfraLogItemField',
+ },
+ {
+ field: 'input.type',
+ value: 'log',
+ __typename: 'InfraLogItemField',
+ },
+ {
+ field: 'offset',
+ value: '5497614',
+ __typename: 'InfraLogItemField',
+ },
+ {
+ field: 'prospector.type',
+ value: 'log',
+ __typename: 'InfraLogItemField',
+ },
+ {
+ field: 'read_timestamp',
+ value: '2018-10-17T19:42:23.160Z',
+ __typename: 'InfraLogItemField',
+ },
+ {
+ field: 'source',
+ value: '/var/log/apache2/access.log',
+ __typename: 'InfraLogItemField',
+ },
+ ]);
+ });
+ });
+ });
+};
+
+// tslint:disable-next-line no-default-export
+export default logItemTests;
diff --git a/x-pack/test/api_integration/apis/infra/waffle.ts b/x-pack/test/api_integration/apis/infra/waffle.ts
index 742e980230430..9efdbfdde119a 100644
--- a/x-pack/test/api_integration/apis/infra/waffle.ts
+++ b/x-pack/test/api_integration/apis/infra/waffle.ts
@@ -48,6 +48,8 @@ const waffleTests: KbnTestProvider = ({ getService }) => {
expect(firstNode.metric).to.eql({
name: 'cpu',
value: 0.011,
+ avg: 0.012215686274509805,
+ max: 0.020999999999999998,
__typename: 'InfraNodeMetric',
});
}
diff --git a/x-pack/test/functional/apps/canvas/smoke_test.js b/x-pack/test/functional/apps/canvas/smoke_test.js
index e94001a6e0508..45552e1a4067d 100644
--- a/x-pack/test/functional/apps/canvas/smoke_test.js
+++ b/x-pack/test/functional/apps/canvas/smoke_test.js
@@ -46,8 +46,10 @@ export default function canvasSmokeTest({ getService, getPageObjects }) {
await retry.waitFor('workpad page', () => testSubjects.exists('canvasWorkpadPage'));
// check that workpad loaded in url
- const url = await browser.getCurrentUrl();
- expect(parse(url).hash).to.equal(`#/workpad/${testWorkpadId}/page/1`);
+ await retry.try(async () => {
+ const url = await browser.getCurrentUrl();
+ expect(parse(url).hash).to.equal(`#/workpad/${testWorkpadId}/page/1`);
+ });
});
it('renders elements on workpad', async () => {
diff --git a/x-pack/test/functional/apps/gis/saved_object_management.js b/x-pack/test/functional/apps/gis/saved_object_management.js
index bbfb6c7a2dd24..6ad4415bb423d 100644
--- a/x-pack/test/functional/apps/gis/saved_object_management.js
+++ b/x-pack/test/functional/apps/gis/saved_object_management.js
@@ -8,7 +8,7 @@ import expect from 'expect.js';
export default function ({ getPageObjects, getService }) {
- const PageObjects = getPageObjects(['gis', 'header']);
+ const PageObjects = getPageObjects(['gis', 'header', 'timePicker']);
const queryBar = getService('queryBar');
const browser = getService('browser');
const inspector = getService('inspector');
@@ -25,13 +25,16 @@ export default function ({ getPageObjects, getService }) {
});
it('should update global Kibana time to value stored with map', async () => {
- const kibanaTime = await PageObjects.header.getPrettyDuration();
- expect(kibanaTime).to.equal('Last 17m');
+ const timeConfig = await PageObjects.timePicker.getTimeConfig();
+ expect(timeConfig.start).to.equal('~ 17 minutes ago');
+ expect(timeConfig.end).to.equal('now');
});
it('should update global Kibana refresh config to value stored with map', async () => {
- const kibanaRefreshConfig = await PageObjects.header.getRefreshConfig();
- expect(kibanaRefreshConfig).to.equal('inactive 1 second');
+ const kibanaRefreshConfig = await PageObjects.timePicker.getRefreshConfig();
+ expect(kibanaRefreshConfig.interval).to.equal('0.02');
+ expect(kibanaRefreshConfig.units).to.equal('minutes');
+ expect(kibanaRefreshConfig.isPaused).to.equal(true);
});
it('should set map location to value stored with map', async () => {
diff --git a/x-pack/test/functional/apps/spaces/spaces_selection.ts b/x-pack/test/functional/apps/spaces/spaces_selection.ts
index be2b59d69d864..ddd98890c46b3 100644
--- a/x-pack/test/functional/apps/spaces/spaces_selection.ts
+++ b/x-pack/test/functional/apps/spaces/spaces_selection.ts
@@ -7,8 +7,16 @@ import { TestInvoker } from './lib/types';
// tslint:disable:no-default-export
export default function spaceSelectorFunctonalTests({ getService, getPageObjects }: TestInvoker) {
+ const config = getService('config');
const esArchiver = getService('esArchiver');
- const PageObjects = getPageObjects(['security', 'spaceSelector', 'home']);
+ const PageObjects = getPageObjects([
+ 'common',
+ 'dashboard',
+ 'header',
+ 'home',
+ 'security',
+ 'spaceSelector',
+ ]);
describe('Spaces', () => {
describe('Space Selector', () => {
@@ -39,5 +47,74 @@ export default function spaceSelectorFunctonalTests({ getService, getPageObjects
await PageObjects.spaceSelector.expectHomePage('default');
});
});
+
+ describe('Spaces Data', () => {
+ const spaceId = 'another-space';
+ const dashboardPath = config.get(['apps', 'dashboard']).pathname;
+ const homePath = config.get(['apps', 'home']).pathname;
+ const sampleDataHash = '/home/tutorial_directory/sampleData';
+
+ const expectDashboardRenders = async (dashName: string) => {
+ await PageObjects.dashboard.searchForDashboardWithName(dashName);
+ await PageObjects.dashboard.selectDashboard(dashName);
+ await PageObjects.header.waitUntilLoadingHasFinished();
+ await PageObjects.dashboard.waitForRenderComplete(); // throws if all items are not rendered
+ };
+
+ before(async () => {
+ await esArchiver.load('spaces');
+ await PageObjects.security.login(null, null, {
+ expectSpaceSelector: true,
+ });
+ await PageObjects.spaceSelector.clickSpaceCard('default');
+ await PageObjects.common.navigateToApp('home', {
+ appConfig: {
+ hash: sampleDataHash,
+ },
+ });
+ await PageObjects.home.addSampleDataSet('logs');
+ await PageObjects.common.navigateToApp('home', {
+ appConfig: {
+ hash: sampleDataHash,
+ pathname: `/s/${spaceId}${homePath}`,
+ },
+ });
+ await PageObjects.home.addSampleDataSet('flights');
+ });
+
+ after(async () => {
+ await PageObjects.common.navigateToApp('home', {
+ appConfig: {
+ hash: sampleDataHash,
+ },
+ });
+ await PageObjects.home.removeSampleDataSet('logs');
+ await PageObjects.common.navigateToApp('home', {
+ appConfig: {
+ hash: sampleDataHash,
+ pathname: `/s/${spaceId}${homePath}`,
+ },
+ });
+ await PageObjects.home.removeSampleDataSet('flights');
+ await PageObjects.security.logout();
+ await esArchiver.unload('spaces');
+ });
+
+ describe('displays separate data for each space', async () => {
+ it('in the default space', async () => {
+ await PageObjects.common.navigateToApp('dashboard');
+ await expectDashboardRenders('[Logs] Web Traffic');
+ });
+
+ it('in a custom space', async () => {
+ await PageObjects.common.navigateToApp('dashboard', {
+ appConfig: {
+ pathname: `/s/${spaceId}${dashboardPath}`,
+ },
+ });
+ await expectDashboardRenders('[Flights] Global Flight Dashboard');
+ });
+ });
+ });
});
}
diff --git a/x-pack/test/functional/es_archives/empty_kibana/data.json.gz b/x-pack/test/functional/es_archives/empty_kibana/data.json.gz
index 2aa6460986df4..1fd039ebc7c64 100644
Binary files a/x-pack/test/functional/es_archives/empty_kibana/data.json.gz and b/x-pack/test/functional/es_archives/empty_kibana/data.json.gz differ
diff --git a/x-pack/test/functional/es_archives/infra/logs_without_epoch_millis/data.json.gz b/x-pack/test/functional/es_archives/infra/logs_without_epoch_millis/data.json.gz
index b07c21c155075..80eb707ec1aa7 100644
Binary files a/x-pack/test/functional/es_archives/infra/logs_without_epoch_millis/data.json.gz and b/x-pack/test/functional/es_archives/infra/logs_without_epoch_millis/data.json.gz differ
diff --git a/x-pack/test/functional/es_archives/infra/logs_without_epoch_millis/mappings.json b/x-pack/test/functional/es_archives/infra/logs_without_epoch_millis/mappings.json
index 7b3c6e167437e..185d1d72b361b 100644
--- a/x-pack/test/functional/es_archives/infra/logs_without_epoch_millis/mappings.json
+++ b/x-pack/test/functional/es_archives/infra/logs_without_epoch_millis/mappings.json
@@ -1708,4 +1708,4 @@
},
"aliases": {}
}
-}
\ No newline at end of file
+}
diff --git a/x-pack/test/functional/es_archives/infra/metrics_and_logs/data.json.gz b/x-pack/test/functional/es_archives/infra/metrics_and_logs/data.json.gz
index f212df30f74ba..a124024b2d100 100644
Binary files a/x-pack/test/functional/es_archives/infra/metrics_and_logs/data.json.gz and b/x-pack/test/functional/es_archives/infra/metrics_and_logs/data.json.gz differ
diff --git a/x-pack/test/functional/es_archives/infra/metrics_and_logs/mappings.json b/x-pack/test/functional/es_archives/infra/metrics_and_logs/mappings.json
index 353c8102faf28..25169a6fcb56c 100644
--- a/x-pack/test/functional/es_archives/infra/metrics_and_logs/mappings.json
+++ b/x-pack/test/functional/es_archives/infra/metrics_and_logs/mappings.json
@@ -10745,4 +10745,4 @@
},
"aliases": {}
}
-}
\ No newline at end of file
+}
diff --git a/x-pack/test/functional/page_objects/gis_page.js b/x-pack/test/functional/page_objects/gis_page.js
index 0ee327e984c87..75a5bf22b800b 100644
--- a/x-pack/test/functional/page_objects/gis_page.js
+++ b/x-pack/test/functional/page_objects/gis_page.js
@@ -5,7 +5,7 @@
*/
export function GisPageProvider({ getService, getPageObjects }) {
- const PageObjects = getPageObjects(['common', 'header']);
+ const PageObjects = getPageObjects(['common', 'header', 'timePicker']);
const log = getService('log');
const testSubjects = getService('testSubjects');
@@ -204,10 +204,10 @@ export function GisPageProvider({ getService, getPageObjects }) {
async triggerSingleRefresh(refreshInterval) {
log.debug(`triggerSingleRefresh, refreshInterval: ${refreshInterval}`);
- await PageObjects.header.resumeAutoRefresh();
+ await PageObjects.timePicker.resumeAutoRefresh();
log.debug('waiting to give time for refresh timer to fire');
await PageObjects.common.sleep(refreshInterval + (refreshInterval / 2));
- await PageObjects.header.pauseAutoRefresh();
+ await PageObjects.timePicker.pauseAutoRefresh();
await PageObjects.header.waitUntilLoadingHasFinished();
}
}
diff --git a/x-pack/test/functional/page_objects/space_selector_page.js b/x-pack/test/functional/page_objects/space_selector_page.js
index f04902c240a1c..9f7ff9ced6b6d 100644
--- a/x-pack/test/functional/page_objects/space_selector_page.js
+++ b/x-pack/test/functional/page_objects/space_selector_page.js
@@ -12,7 +12,7 @@ export function SpaceSelectorPageProvider({ getService, getPageObjects }) {
const testSubjects = getService('testSubjects');
const browser = getService('browser');
const find = getService('find');
- const PageObjects = getPageObjects(['common', 'home', 'security']);
+ const PageObjects = getPageObjects(['common', 'header', 'security']);
class SpaceSelectorPage {
async initTests() {
diff --git a/x-pack/test/saved_object_api_integration/common/fixtures/es_archiver/saved_objects/spaces/data.json b/x-pack/test/saved_object_api_integration/common/fixtures/es_archiver/saved_objects/spaces/data.json
index 6bf3413f3797d..368384479bc30 100644
--- a/x-pack/test/saved_object_api_integration/common/fixtures/es_archiver/saved_objects/spaces/data.json
+++ b/x-pack/test/saved_object_api_integration/common/fixtures/es_archiver/saved_objects/spaces/data.json
@@ -195,7 +195,7 @@
"description": "",
"version": 1,
"kibanaSavedObjectMeta": {
- "searchSourceJSON": "{\"index\":\"91200a00-9efd-11e7-acb3-3dab96693fab\",\"filter\":[],\"query\":{\"query\":\"\",\"language\":\"lucene\"}}"
+ "searchSourceJSON": "{\"index\":\"space_1-91200a00-9efd-11e7-acb3-3dab96693fab\",\"filter\":[],\"query\":{\"query\":\"\",\"language\":\"lucene\"}}"
}
}
}
@@ -216,7 +216,7 @@
"title": "Requests",
"hits": 0,
"description": "",
- "panelsJSON": "[{\"size_x\":6,\"size_y\":3,\"panelIndex\":1,\"type\":\"visualization\",\"id\":\"dd7caf20-9efd-11e7-acb3-3dab96693fab\",\"col\":1,\"row\":1}]",
+ "panelsJSON": "[{\"size_x\":6,\"size_y\":3,\"panelIndex\":1,\"type\":\"visualization\",\"id\":\"space_1-dd7caf20-9efd-11e7-acb3-3dab96693fab\",\"col\":1,\"row\":1}]",
"optionsJSON": "{}",
"uiStateJSON": "{}",
"version": 1,
@@ -291,7 +291,7 @@
"description": "",
"version": 1,
"kibanaSavedObjectMeta": {
- "searchSourceJSON": "{\"index\":\"91200a00-9efd-11e7-acb3-3dab96693fab\",\"filter\":[],\"query\":{\"query\":\"\",\"language\":\"lucene\"}}"
+ "searchSourceJSON": "{\"index\":\"space_2-91200a00-9efd-11e7-acb3-3dab96693fab\",\"filter\":[],\"query\":{\"query\":\"\",\"language\":\"lucene\"}}"
}
}
}
@@ -312,7 +312,7 @@
"title": "Requests",
"hits": 0,
"description": "",
- "panelsJSON": "[{\"size_x\":6,\"size_y\":3,\"panelIndex\":1,\"type\":\"visualization\",\"id\":\"dd7caf20-9efd-11e7-acb3-3dab96693fab\",\"col\":1,\"row\":1}]",
+ "panelsJSON": "[{\"size_x\":6,\"size_y\":3,\"panelIndex\":1,\"type\":\"visualization\",\"id\":\"space_2-dd7caf20-9efd-11e7-acb3-3dab96693fab\",\"col\":1,\"row\":1}]",
"optionsJSON": "{}",
"uiStateJSON": "{}",
"version": 1,
diff --git a/x-pack/test/saved_object_api_integration/common/suites/bulk_create.ts b/x-pack/test/saved_object_api_integration/common/suites/bulk_create.ts
index 0d9e800c64003..6dcaae760a58d 100644
--- a/x-pack/test/saved_object_api_integration/common/suites/bulk_create.ts
+++ b/x-pack/test/saved_object_api_integration/common/suites/bulk_create.ts
@@ -88,6 +88,7 @@ export function bulkCreateTestSuiteFactory(es: any, esArchiver: any, supertest:
attributes: {
title: 'A great new dashboard',
},
+ references: [],
},
{
type: 'globaltype',
@@ -97,6 +98,7 @@ export function bulkCreateTestSuiteFactory(es: any, esArchiver: any, supertest:
attributes: {
name: 'A new globaltype object',
},
+ references: [],
},
{
type: 'globaltype',
diff --git a/x-pack/test/saved_object_api_integration/common/suites/bulk_get.ts b/x-pack/test/saved_object_api_integration/common/suites/bulk_get.ts
index fdffe545f3416..e82ea7b856a8c 100644
--- a/x-pack/test/saved_object_api_integration/common/suites/bulk_get.ts
+++ b/x-pack/test/saved_object_api_integration/common/suites/bulk_get.ts
@@ -69,6 +69,7 @@ export function bulkGetTestSuiteFactory(esArchiver: any, supertest: SuperTest)
attributes: {
name: 'My favorite global object',
},
+ references: [],
},
],
});
@@ -99,6 +100,7 @@ export function findTestSuiteFactory(esArchiver: any, supertest: SuperTest)
attributes: {
title: 'Count of requests',
},
+ references: [],
},
],
});
diff --git a/x-pack/test/saved_object_api_integration/common/suites/get.ts b/x-pack/test/saved_object_api_integration/common/suites/get.ts
index 5bf2385544a7d..1cc36b411c61a 100644
--- a/x-pack/test/saved_object_api_integration/common/suites/get.ts
+++ b/x-pack/test/saved_object_api_integration/common/suites/get.ts
@@ -69,6 +69,7 @@ export function getTestSuiteFactory(esArchiver: any, supertest: SuperTest)
attributes: {
name: 'My favorite global object',
},
+ references: [],
});
};
@@ -108,6 +109,13 @@ export function getTestSuiteFactory(esArchiver: any, supertest: SuperTest)
uiStateJSON: resp.body.attributes.uiStateJSON,
kibanaSavedObjectMeta: resp.body.attributes.kibanaSavedObjectMeta,
},
+ references: [
+ {
+ name: 'kibanaSavedObjectMeta.searchSourceJSON.index',
+ type: 'index-pattern',
+ id: `${getIdPrefix(spaceId)}91200a00-9efd-11e7-acb3-3dab96693fab`,
+ },
+ ],
});
};
diff --git a/x-pack/test/saved_object_api_integration/common/suites/update.ts b/x-pack/test/saved_object_api_integration/common/suites/update.ts
index f936567200f54..5d496ba58bbba 100644
--- a/x-pack/test/saved_object_api_integration/common/suites/update.ts
+++ b/x-pack/test/saved_object_api_integration/common/suites/update.ts
@@ -78,6 +78,7 @@ export function updateTestSuiteFactory(esArchiver: any, supertest: SuperTest |