-
-
+
+
+
+
+
+
+
+
+
+ {{tag.name}}
+
,
@@ -184,11 +186,14 @@ uiModules.get('apps/management')
$scope, $location, $route, config, indexPatterns, Private, AppState, docTitle, confirmModal) {
const $state = $scope.state = new AppState();
const { fieldWildcardMatcher } = Private(FieldWildcardProvider);
+ const indexPatternListProvider = Private(IndexPatternListFactory)();
$scope.fieldWildcardMatcher = fieldWildcardMatcher;
$scope.editSectionsProvider = Private(IndicesEditSectionsProvider);
$scope.kbnUrl = Private(KbnUrlProvider);
$scope.indexPattern = $route.current.locals.indexPattern;
+ $scope.indexPattern.tags = indexPatternListProvider.getIndexPatternTags($scope.indexPattern);
+ $scope.getFieldInfo = indexPatternListProvider.getFieldInfo;
docTitle.change($scope.indexPattern.title);
const otherPatterns = _.filter($route.current.locals.indexPatterns, pattern => {
@@ -196,7 +201,7 @@ uiModules.get('apps/management')
});
$scope.$watch('indexPattern.fields', function () {
- $scope.editSections = $scope.editSectionsProvider($scope.indexPattern);
+ $scope.editSections = $scope.editSectionsProvider($scope.indexPattern, indexPatternListProvider);
$scope.refreshFilters();
$scope.fields = $scope.indexPattern.getNonScriptedFields();
updateIndexedFieldsTable($scope, $state);
diff --git a/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/edit_sections.js b/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/edit_sections.js
index 20a8e49c7eee2..c7f53096bfa6e 100644
--- a/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/edit_sections.js
+++ b/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/edit_sections.js
@@ -22,7 +22,7 @@ import { i18n } from '@kbn/i18n';
export function IndicesEditSectionsProvider() {
- return function (indexPattern) {
+ return function (indexPattern, indexPatternListProvider) {
const fieldCount = _.countBy(indexPattern.fields, function (field) {
return (field.scripted) ? 'scripted' : 'indexed';
});
@@ -33,22 +33,28 @@ export function IndicesEditSectionsProvider() {
sourceFilters: indexPattern.sourceFilters ? indexPattern.sourceFilters.length : 0,
});
- return [
- {
- title: i18n.translate('kbn.management.editIndexPattern.tabs.fieldsHeader', { defaultMessage: 'Fields' }),
- index: 'indexedFields',
- count: fieldCount.indexed
- },
- {
+ const editSections = [];
+
+ editSections.push({
+ title: i18n.translate('kbn.management.editIndexPattern.tabs.fieldsHeader', { defaultMessage: 'Fields' }),
+ index: 'indexedFields',
+ count: fieldCount.indexed
+ });
+
+ if(indexPatternListProvider.areScriptedFieldsEnabled(indexPattern)) {
+ editSections.push({
title: i18n.translate('kbn.management.editIndexPattern.tabs.scriptedHeader', { defaultMessage: 'Scripted fields' }),
index: 'scriptedFields',
count: fieldCount.scripted
- },
- {
- title: i18n.translate('kbn.management.editIndexPattern.tabs.sourceHeader', { defaultMessage: 'Source filters' }),
- index: 'sourceFilters',
- count: fieldCount.sourceFilters
- }
- ];
+ });
+ }
+
+ editSections.push({
+ title: i18n.translate('kbn.management.editIndexPattern.tabs.sourceHeader', { defaultMessage: 'Source filters' }),
+ index: 'sourceFilters',
+ count: fieldCount.sourceFilters
+ });
+
+ return editSections;
};
}
diff --git a/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/indexed_fields_table/__tests__/__snapshots__/indexed_fields_table.test.js.snap b/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/indexed_fields_table/__tests__/__snapshots__/indexed_fields_table.test.js.snap
index 45f8b04cbf712..277ad1248ff3e 100644
--- a/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/indexed_fields_table/__tests__/__snapshots__/indexed_fields_table.test.js.snap
+++ b/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/indexed_fields_table/__tests__/__snapshots__/indexed_fields_table.test.js.snap
@@ -17,6 +17,7 @@ exports[`IndexedFieldsTable should filter based on the query bar 1`] = `
"excluded": false,
"format": undefined,
"indexPattern": undefined,
+ "info": undefined,
"name": "Elastic",
"routes": undefined,
"searchable": true,
@@ -45,6 +46,7 @@ exports[`IndexedFieldsTable should filter based on the type filter 1`] = `
"excluded": false,
"format": undefined,
"indexPattern": undefined,
+ "info": undefined,
"name": "timestamp",
"routes": undefined,
"type": "date",
@@ -73,6 +75,7 @@ exports[`IndexedFieldsTable should render normally 1`] = `
"excluded": false,
"format": undefined,
"indexPattern": undefined,
+ "info": undefined,
"name": "Elastic",
"routes": undefined,
"searchable": true,
@@ -82,6 +85,7 @@ exports[`IndexedFieldsTable should render normally 1`] = `
"excluded": false,
"format": undefined,
"indexPattern": undefined,
+ "info": undefined,
"name": "timestamp",
"routes": undefined,
"type": "date",
@@ -91,6 +95,7 @@ exports[`IndexedFieldsTable should render normally 1`] = `
"excluded": false,
"format": undefined,
"indexPattern": undefined,
+ "info": undefined,
"name": "conflictingField",
"routes": undefined,
"type": "conflict",
diff --git a/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/indexed_fields_table/components/table/__tests__/__snapshots__/table.test.js.snap b/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/indexed_fields_table/components/table/__tests__/__snapshots__/table.test.js.snap
index d000633a2caad..0ff7cbe0d6d0b 100644
--- a/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/indexed_fields_table/components/table/__tests__/__snapshots__/table.test.js.snap
+++ b/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/indexed_fields_table/components/table/__tests__/__snapshots__/table.test.js.snap
@@ -97,16 +97,19 @@ exports[`Table should render normally 1`] = `
Array [
Object {
"displayName": "Elastic",
+ "info": Object {},
"name": "Elastic",
"searchable": true,
},
Object {
"displayName": "timestamp",
+ "info": Object {},
"name": "timestamp",
"type": "date",
},
Object {
"displayName": "conflictingField",
+ "info": Object {},
"name": "conflictingField",
"type": "conflict",
},
diff --git a/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/indexed_fields_table/components/table/__tests__/table.test.js b/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/indexed_fields_table/components/table/__tests__/table.test.js
index 752d99267e330..c538bb5f24085 100644
--- a/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/indexed_fields_table/components/table/__tests__/table.test.js
+++ b/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/indexed_fields_table/components/table/__tests__/table.test.js
@@ -28,9 +28,9 @@ const indexPattern = {
};
const items = [
- { name: 'Elastic', displayName: 'Elastic', searchable: true },
- { name: 'timestamp', displayName: 'timestamp', type: 'date' },
- { name: 'conflictingField', displayName: 'conflictingField', type: 'conflict' },
+ { name: 'Elastic', displayName: 'Elastic', searchable: true, info: {} },
+ { name: 'timestamp', displayName: 'timestamp', type: 'date', info: {} },
+ { name: 'conflictingField', displayName: 'conflictingField', type: 'conflict', info: {} },
];
describe('Table', () => {
@@ -55,7 +55,7 @@ describe('Table', () => {
/>
);
- const tableCell = shallow(component.prop('columns')[0].render('Elastic'));
+ const tableCell = shallow(component.prop('columns')[0].render('Elastic', items[0]));
expect(tableCell).toMatchSnapshot();
});
@@ -68,7 +68,7 @@ describe('Table', () => {
/>
);
- const tableCell = shallow(component.prop('columns')[0].render('timestamp', true));
+ const tableCell = shallow(component.prop('columns')[0].render('timestamp', items[1]));
expect(tableCell).toMatchSnapshot();
});
@@ -94,7 +94,7 @@ describe('Table', () => {
/>
);
- const tableCell = shallow(component.prop('columns')[3].render(false));
+ const tableCell = shallow(component.prop('columns')[3].render(false, items[2]));
expect(tableCell).toMatchSnapshot();
});
diff --git a/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/indexed_fields_table/components/table/table.js b/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/indexed_fields_table/components/table/table.js
index 628e42e9e9653..71c648d77a43e 100644
--- a/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/indexed_fields_table/components/table/table.js
+++ b/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/indexed_fields_table/components/table/table.js
@@ -39,13 +39,19 @@ export class TableComponent extends PureComponent {
return value ? : ;
}
- renderFieldName(name, isTimeField) {
+ renderFieldName(name, field) {
+ const { indexPattern } = this.props;
const { intl } = this.props;
- const label = intl.formatMessage({
- id: 'kbn.management.editIndexPattern.fields.table.primaryTimeAria',
+
+ const infoLabel = intl.formatMessage({
+ id: 'kbn.management.editIndexPattern.fields.table.additionalInfoAriaLabel',
+ defaultMessage: 'Additional field information'
+ });
+ const timeLabel = intl.formatMessage({
+ id: 'kbn.management.editIndexPattern.fields.table.primaryTimeAriaLabel',
defaultMessage: 'Primary time field'
});
- const content = intl.formatMessage({
+ const timeContent = intl.formatMessage({
id: 'kbn.management.editIndexPattern.fields.table.primaryTimeTooltip',
defaultMessage: 'This field represents the time that events occurred.'
});
@@ -53,17 +59,28 @@ export class TableComponent extends PureComponent {
return (
{name}
- {isTimeField ? (
+ {field.info && field.info.length ? (
+
+
+ {info}
)}
+ />
+
+ ) : null}
+ {indexPattern.timeFieldName === name ? (
- ) : ''}
+ ) : null}
);
}
@@ -98,7 +115,7 @@ export class TableComponent extends PureComponent {
}
render() {
- const { indexPattern, items, editField, intl } = this.props;
+ const { items, editField, intl } = this.props;
const pagination = {
initialPageSize: 10,
@@ -111,8 +128,8 @@ export class TableComponent extends PureComponent {
name: intl.formatMessage({ id: 'kbn.management.editIndexPattern.fields.table.nameHeader', defaultMessage: 'Name' }),
dataType: 'string',
sortable: true,
- render: (value) => {
- return this.renderFieldName(value, indexPattern.timeFieldName === value);
+ render: (value, field) => {
+ return this.renderFieldName(value, field);
},
width: '38%',
'data-test-subj': 'indexedFieldName',
diff --git a/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/indexed_fields_table/indexed_fields_table.js b/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/indexed_fields_table/indexed_fields_table.js
index 646abf6798756..607e7fa66242c 100644
--- a/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/indexed_fields_table/indexed_fields_table.js
+++ b/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/indexed_fields_table/indexed_fields_table.js
@@ -36,6 +36,7 @@ export class IndexedFieldsTable extends Component {
indexedFieldTypeFilter: PropTypes.string,
helpers: PropTypes.shape({
redirectToRoute: PropTypes.func.isRequired,
+ getFieldInfo: PropTypes.func,
}),
fieldWildcardMatcher: PropTypes.func.isRequired,
}
@@ -57,7 +58,7 @@ export class IndexedFieldsTable extends Component {
}
mapFields(fields) {
- const { indexPattern, fieldWildcardMatcher } = this.props;
+ const { indexPattern, fieldWildcardMatcher, helpers } = this.props;
const sourceFilters = indexPattern.sourceFilters && indexPattern.sourceFilters.map(f => f.value);
const fieldWildcardMatch = fieldWildcardMatcher(sourceFilters || []);
@@ -70,6 +71,7 @@ export class IndexedFieldsTable extends Component {
indexPattern: field.indexPattern,
format: getFieldFormat(indexPattern, field.name),
excluded: fieldWildcardMatch ? fieldWildcardMatch(field.name) : false,
+ info: helpers.getFieldInfo && helpers.getFieldInfo(indexPattern, field.name),
};
}) || [];
}
diff --git a/src/core_plugins/kibana/public/management/sections/indices/index.html b/src/core_plugins/kibana/public/management/sections/indices/index.html
index 26dee3efa77b8..1c2c5faa6aea8 100644
--- a/src/core_plugins/kibana/public/management/sections/indices/index.html
+++ b/src/core_plugins/kibana/public/management/sections/indices/index.html
@@ -1,52 +1,7 @@
diff --git a/src/core_plugins/kibana/public/management/sections/indices/index.js b/src/core_plugins/kibana/public/management/sections/indices/index.js
index 69416c56e5c39..fbe715c6f0f07 100644
--- a/src/core_plugins/kibana/public/management/sections/indices/index.js
+++ b/src/core_plugins/kibana/public/management/sections/indices/index.js
@@ -18,6 +18,8 @@
*/
import { management } from 'ui/management';
+import { IndexPatternListFactory } from 'ui/management/index_pattern_list';
+import { IndexPatternCreationFactory } from 'ui/management/index_pattern_creation';
import './create_index_pattern_wizard';
import './edit_index_pattern';
import uiRoutes from 'ui/routes';
@@ -27,13 +29,45 @@ import { SavedObjectsClientProvider } from 'ui/saved_objects';
import { FeatureCatalogueRegistryProvider, FeatureCatalogueCategory } from 'ui/registry/feature_catalogue';
import { i18n } from '@kbn/i18n';
+import React from 'react';
+import { render, unmountComponentAtNode } from 'react-dom';
+import { IndexPatternList } from './index_pattern_list';
+
+const INDEX_PATTERN_LIST_DOM_ELEMENT_ID = 'indexPatternListReact';
+
+export function updateIndexPatternList(
+ $scope,
+ indexPatternCreationOptions,
+ defaultIndex,
+ indexPatterns,
+) {
+ const node = document.getElementById(INDEX_PATTERN_LIST_DOM_ELEMENT_ID);
+ if (!node) {
+ return;
+ }
+
+ render(
+
,
+ node,
+ );
+}
+
+export const destroyIndexPatternList = () => {
+ const node = document.getElementById(INDEX_PATTERN_LIST_DOM_ELEMENT_ID);
+ node && unmountComponentAtNode(node);
+};
+
const indexPatternsResolutions = {
indexPatterns: function (Private) {
const savedObjectsClient = Private(SavedObjectsClientProvider);
return savedObjectsClient.find({
type: 'index-pattern',
- fields: ['title'],
+ fields: ['title', 'type'],
perPage: 10000
}).then(response => response.savedObjects);
}
@@ -52,28 +86,55 @@ uiRoutes
// wrapper directive, which sets some global stuff up like the left nav
uiModules.get('apps/management')
- .directive('kbnManagementIndices', function ($route, config, kbnUrl) {
+ .directive('kbnManagementIndices', function ($route, config, kbnUrl, Private) {
return {
restrict: 'E',
transclude: true,
template: indexTemplate,
- link: function ($scope) {
- $scope.editingId = $route.current.params.indexPatternId;
- config.bindToScope($scope, 'defaultIndex');
+ link: async function ($scope) {
+ const indexPatternListProvider = Private(IndexPatternListFactory)();
+ const indexPatternCreationProvider = Private(IndexPatternCreationFactory)();
+ const indexPatternCreationOptions = await indexPatternCreationProvider.getIndexPatternCreationOptions((url) => {
+ $scope.$evalAsync(() => kbnUrl.change(url));
+ });
- $scope.$watch('defaultIndex', function () {
+ const renderList = () => {
$scope.indexPatternList = $route.current.locals.indexPatterns.map(pattern => {
const id = pattern.id;
+ const tags = indexPatternListProvider.getIndexPatternTags(pattern, $scope.defaultIndex === id);
return {
id: id,
title: pattern.get('title'),
url: kbnUrl.eval('#/management/kibana/indices/{{id}}', { id: id }),
- class: 'sidebar-item-title ' + ($scope.editingId === id ? 'active' : ''),
- default: $scope.defaultIndex === id
+ active: $scope.editingId === id,
+ default: $scope.defaultIndex === id,
+ tag: tags && tags.length ? tags[0] : null,
};
- });
- });
+ }).sort((a, b) => {
+ if(a.default) {
+ return -1;
+ }
+ if(b.default) {
+ return 1;
+ }
+ if(a.title < b.title) {
+ return -1;
+ }
+ if(a.title > b.title) {
+ return 1;
+ }
+ return 0;
+ }) || [];
+
+ updateIndexPatternList($scope, indexPatternCreationOptions, $scope.defaultIndex, $scope.indexPatternList);
+ };
+
+ $scope.$on('$destroy', destroyIndexPatternList);
+ $scope.editingId = $route.current.params.indexPatternId;
+ $scope.$watch('defaultIndex', () => renderList());
+ config.bindToScope($scope, 'defaultIndex');
+ $scope.$apply();
}
};
});
diff --git a/src/core_plugins/kibana/public/management/sections/indices/index.scss b/src/core_plugins/kibana/public/management/sections/indices/index.scss
new file mode 100644
index 0000000000000..2a4aadf0d4fd6
--- /dev/null
+++ b/src/core_plugins/kibana/public/management/sections/indices/index.scss
@@ -0,0 +1,15 @@
+#indexPatternListReact {
+ .indexPatternList__headerWrapper {
+ padding-bottom: $euiSizeS;
+ }
+
+ .euiButtonEmpty__content {
+ justify-content: left;
+ padding: 0;
+
+ span {
+ text-overflow: ellipsis;
+ overflow: hidden;
+ }
+ }
+}
diff --git a/src/core_plugins/kibana/public/management/sections/indices/index_pattern_list/components/create_button/create_button.js b/src/core_plugins/kibana/public/management/sections/indices/index_pattern_list/components/create_button/create_button.js
new file mode 100644
index 0000000000000..176ba0da03229
--- /dev/null
+++ b/src/core_plugins/kibana/public/management/sections/indices/index_pattern_list/components/create_button/create_button.js
@@ -0,0 +1,129 @@
+/*
+ * 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.
+ */
+
+import React, { Component } from 'react';
+import PropTypes from 'prop-types';
+
+import {
+ EuiButton,
+ EuiPopover,
+ EuiContextMenuPanel,
+ EuiContextMenuItem,
+ EuiDescriptionList,
+ EuiDescriptionListTitle,
+ EuiDescriptionListDescription,
+} from '@elastic/eui';
+
+export class CreateButton extends Component {
+ constructor(props) {
+ super(props);
+ this.state = {
+ isPopoverOpen: false,
+ };
+ }
+
+ static propTypes = {
+ options: PropTypes.arrayOf(PropTypes.shape({
+ text: PropTypes.string.isRequired,
+ description: PropTypes.string,
+ onClick: PropTypes.func.isRequired,
+ })),
+ }
+
+ togglePopover = () => {
+ this.setState({
+ isPopoverOpen: !this.state.isPopoverOpen,
+ });
+ }
+
+ closePopover = () => {
+ this.setState({
+ isPopoverOpen: false,
+ });
+ }
+
+ render() {
+ const { options, children } = this.props;
+ const { isPopoverOpen } = this.state;
+
+ if(!options || !options.length) {
+ return null;
+ }
+
+ if(options.length === 1) {
+ return (
+
+ {children}
+
+ );
+ }
+
+ const button = (
+
+ {children}
+
+ );
+
+ if(options.length > 1) {
+ return (
+
+ {
+ return (
+
+
+
+ {option.text}
+
+
+ {option.description}
+
+
+
+ );
+ })}
+ />
+
+ );
+ }
+ }
+}
diff --git a/src/core_plugins/kibana/public/management/sections/indices/index_pattern_list/components/create_button/index.js b/src/core_plugins/kibana/public/management/sections/indices/index_pattern_list/components/create_button/index.js
new file mode 100644
index 0000000000000..caf956479ad99
--- /dev/null
+++ b/src/core_plugins/kibana/public/management/sections/indices/index_pattern_list/components/create_button/index.js
@@ -0,0 +1,20 @@
+/*
+ * 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 { CreateButton } from './create_button';
diff --git a/src/core_plugins/kibana/public/management/sections/indices/index_pattern_list/components/header/header.js b/src/core_plugins/kibana/public/management/sections/indices/index_pattern_list/components/header/header.js
new file mode 100644
index 0000000000000..5e16c641e039e
--- /dev/null
+++ b/src/core_plugins/kibana/public/management/sections/indices/index_pattern_list/components/header/header.js
@@ -0,0 +1,35 @@
+/*
+ * 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.
+ */
+
+import React from 'react';
+import { CreateButton } from '../create_button';
+import { I18nProvider, FormattedMessage } from '@kbn/i18n/react';
+
+export const Header = ({
+ indexPatternCreationOptions
+}) => (
+
+
+
+
+
+);
diff --git a/src/core_plugins/kibana/public/management/sections/indices/index_pattern_list/components/header/index.js b/src/core_plugins/kibana/public/management/sections/indices/index_pattern_list/components/header/index.js
new file mode 100644
index 0000000000000..ac1e7bac06c87
--- /dev/null
+++ b/src/core_plugins/kibana/public/management/sections/indices/index_pattern_list/components/header/index.js
@@ -0,0 +1,20 @@
+/*
+ * 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 { Header } from './header';
diff --git a/src/core_plugins/kibana/public/management/sections/indices/index_pattern_list/components/list/index.js b/src/core_plugins/kibana/public/management/sections/indices/index_pattern_list/components/list/index.js
new file mode 100644
index 0000000000000..501bca9658d8e
--- /dev/null
+++ b/src/core_plugins/kibana/public/management/sections/indices/index_pattern_list/components/list/index.js
@@ -0,0 +1,20 @@
+/*
+ * 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 { List } from './list';
diff --git a/src/core_plugins/kibana/public/management/sections/indices/index_pattern_list/components/list/list.js b/src/core_plugins/kibana/public/management/sections/indices/index_pattern_list/components/list/list.js
new file mode 100644
index 0000000000000..07dd4efbfbcb6
--- /dev/null
+++ b/src/core_plugins/kibana/public/management/sections/indices/index_pattern_list/components/list/list.js
@@ -0,0 +1,83 @@
+/*
+ * 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.
+ */
+
+import React, { Component, Fragment } from 'react';
+import PropTypes from 'prop-types';
+
+import {
+ EuiButtonEmpty,
+ EuiBadge,
+ EuiCallOut,
+ EuiSpacer,
+} from '@elastic/eui';
+
+export class List extends Component {
+ static propTypes = {
+ indexPatterns: PropTypes.array,
+ defaultIndex: PropTypes.string,
+ }
+
+ renderList() {
+ const { indexPatterns } = this.props;
+ return indexPatterns && indexPatterns.length ? (
+
+ {
+ indexPatterns.map(pattern => {
+ return (
+
+
+ {pattern.default ? : ''}
+ {pattern.active ? {pattern.title} : pattern.title} {pattern.tag ? (
+
+ {{pattern.tag.name} }
+
+ ) : null}
+
+
+
+ );
+ })
+ }
+
+ ) : null;
+ }
+
+ renderNoDefaultMessage() {
+ const { defaultIndex } = this.props;
+ return !defaultIndex ? (
+
+
+
+ ) : null;
+ }
+
+ render() {
+ return (
+
+ {this.renderNoDefaultMessage()}
+ {this.renderList()}
+
+ );
+ }
+}
diff --git a/src/core_plugins/kibana/public/management/sections/indices/index_pattern_list/index.js b/src/core_plugins/kibana/public/management/sections/indices/index_pattern_list/index.js
new file mode 100644
index 0000000000000..6a030202731c1
--- /dev/null
+++ b/src/core_plugins/kibana/public/management/sections/indices/index_pattern_list/index.js
@@ -0,0 +1,20 @@
+/*
+ * 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 { IndexPatternList } from './index_pattern_list';
diff --git a/src/core_plugins/kibana/public/management/sections/indices/index_pattern_list/index_pattern_list.js b/src/core_plugins/kibana/public/management/sections/indices/index_pattern_list/index_pattern_list.js
new file mode 100644
index 0000000000000..73351d73bd912
--- /dev/null
+++ b/src/core_plugins/kibana/public/management/sections/indices/index_pattern_list/index_pattern_list.js
@@ -0,0 +1,36 @@
+/*
+ * 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.
+ */
+
+import React, { Fragment } from 'react';
+
+import { Header } from './components/header';
+import { List } from './components/list';
+
+export const IndexPatternList = ({
+ indexPatternCreationOptions,
+ defaultIndex,
+ indexPatterns
+}) => (
+
+
+
+
+
+
+);
diff --git a/src/core_plugins/kibana/public/management/sections/objects/lib/resolve_saved_objects.js b/src/core_plugins/kibana/public/management/sections/objects/lib/resolve_saved_objects.js
index 24c59142e75fb..be332b0780249 100644
--- a/src/core_plugins/kibana/public/management/sections/objects/lib/resolve_saved_objects.js
+++ b/src/core_plugins/kibana/public/management/sections/objects/lib/resolve_saved_objects.js
@@ -53,15 +53,27 @@ function addJsonFieldToIndexPattern(target, sourceString, fieldName, indexName)
async function importIndexPattern(doc, indexPatterns, overwriteAll) {
// TODO: consolidate this is the code in create_index_pattern_wizard.js
const emptyPattern = await indexPatterns.get();
- const { title, timeFieldName, fields, fieldFormatMap, sourceFilters } = doc._source;
+ const {
+ title,
+ timeFieldName,
+ fields,
+ fieldFormatMap,
+ sourceFilters,
+ type,
+ typeMeta,
+ } = doc._source;
const importedIndexPattern = {
id: doc._id,
title,
- timeFieldName
+ timeFieldName,
};
+ if (type) {
+ importedIndexPattern.type = type;
+ }
addJsonFieldToIndexPattern(importedIndexPattern, fields, 'fields', title);
addJsonFieldToIndexPattern(importedIndexPattern, fieldFormatMap, 'fieldFormatMap', title);
addJsonFieldToIndexPattern(importedIndexPattern, sourceFilters, 'sourceFilters', title);
+ addJsonFieldToIndexPattern(importedIndexPattern, typeMeta, 'typeMeta', title);
Object.assign(emptyPattern, importedIndexPattern);
const newId = await emptyPattern.create(true, !overwriteAll);
@@ -128,14 +140,11 @@ export async function resolveIndexPatternConflicts(
export async function saveObjects(objs, overwriteAll) {
let importCount = 0;
- await awaitEachItemInParallel(
- objs,
- async obj => {
- if (await saveObject(obj, overwriteAll)) {
- importCount++;
- }
+ await awaitEachItemInParallel(objs, async obj => {
+ if (await saveObject(obj, overwriteAll)) {
+ importCount++;
}
- );
+ });
return importCount;
}
@@ -143,12 +152,7 @@ export async function saveObject(obj, overwriteAll) {
return await obj.save({ confirmOverwrite: !overwriteAll });
}
-export async function resolveSavedSearches(
- savedSearches,
- services,
- indexPatterns,
- overwriteAll
-) {
+export async function resolveSavedSearches(savedSearches, services, indexPatterns, overwriteAll) {
let importCount = 0;
await awaitEachItemInParallel(savedSearches, async searchDoc => {
const obj = await getSavedObject(searchDoc, services);
@@ -163,12 +167,7 @@ export async function resolveSavedSearches(
return importCount;
}
-export async function resolveSavedObjects(
- savedObjects,
- overwriteAll,
- services,
- indexPatterns
-) {
+export async function resolveSavedObjects(savedObjects, overwriteAll, services, indexPatterns) {
const docTypes = groupByType(savedObjects);
// Keep track of how many we actually import because the user
@@ -177,19 +176,20 @@ export async function resolveSavedObjects(
// Keep a record of any objects which fail to import for unknown reasons.
const failedImports = [];
// Start with the index patterns since everything is dependent on them
- await awaitEachItemInParallel(
- docTypes.indexPatterns,
- async indexPatternDoc => {
- try {
- const importedIndexPatternId = await importIndexPattern(indexPatternDoc, indexPatterns, overwriteAll);
- if (importedIndexPatternId) {
- importedObjectCount++;
- }
- } catch (error) {
- failedImports.push({ indexPatternDoc, error });
+ await awaitEachItemInParallel(docTypes.indexPatterns, async indexPatternDoc => {
+ try {
+ const importedIndexPatternId = await importIndexPattern(
+ indexPatternDoc,
+ indexPatterns,
+ overwriteAll
+ );
+ if (importedIndexPatternId) {
+ importedObjectCount++;
}
+ } catch (error) {
+ failedImports.push({ indexPatternDoc, error });
}
- );
+ });
// We want to do the same for saved searches, but we want to keep them separate because they need
// to be applied _first_ because other saved objects can be dependent on those saved searches existing
diff --git a/src/core_plugins/timelion/public/directives/timelion_expression_suggestions/arg_value_suggestions.js b/src/core_plugins/timelion/public/directives/timelion_expression_suggestions/arg_value_suggestions.js
index 1874ab1487b53..81d459f70a5e1 100644
--- a/src/core_plugins/timelion/public/directives/timelion_expression_suggestions/arg_value_suggestions.js
+++ b/src/core_plugins/timelion/public/directives/timelion_expression_suggestions/arg_value_suggestions.js
@@ -67,14 +67,16 @@ export function ArgValueSuggestionsProvider(Private, indexPatterns) {
const search = partial ? `${partial}*` : '*';
const resp = await savedObjectsClient.find({
type: 'index-pattern',
- fields: ['title'],
+ fields: ['title', 'type'],
search: `${search}`,
search_fields: ['title'],
perPage: 25
});
- return resp.savedObjects.map(savedObject => {
- return { name: savedObject.attributes.title };
- });
+ return resp.savedObjects
+ .filter(savedObject => !savedObject.get('type'))
+ .map(savedObject => {
+ return { name: savedObject.attributes.title };
+ });
},
metric: async function (partial, functionArgs) {
if (!partial || !partial.includes(':')) {
diff --git a/src/server/index_patterns/routes/fields_for_wildcard_route.js b/src/server/index_patterns/routes/fields_for_wildcard_route.js
index f92c01328c980..2ca6a007bd182 100644
--- a/src/server/index_patterns/routes/fields_for_wildcard_route.js
+++ b/src/server/index_patterns/routes/fields_for_wildcard_route.js
@@ -27,7 +27,7 @@ export const createFieldsForWildcardRoute = pre => ({
validate: {
query: Joi.object().keys({
pattern: Joi.string().required(),
- meta_fields: Joi.array().items(Joi.string()).default([])
+ meta_fields: Joi.array().items(Joi.string()).default([]),
}).default()
},
handler(req, reply) {
diff --git a/src/server/index_patterns/service/index_patterns_service.js b/src/server/index_patterns/service/index_patterns_service.js
index 68e800e4277f3..62b99b26ed7e4 100644
--- a/src/server/index_patterns/service/index_patterns_service.js
+++ b/src/server/index_patterns/service/index_patterns_service.js
@@ -32,7 +32,7 @@ export class IndexPatternsService {
* Get a list of field objects for an index pattern that may contain wildcards
*
* @param {Object} [options={}]
- * @property {String} options.pattern The moment compatible time pattern
+ * @property {String} options.pattern The index pattern
* @property {Number} options.metaFields The list of underscore prefixed fields that should
* be left in the field list (all others are removed).
* @return {Promise
>}
diff --git a/src/ui/public/agg_types/buckets/date_histogram.js b/src/ui/public/agg_types/buckets/date_histogram.js
index 925e9a5ab4883..78c926e9cdfcf 100644
--- a/src/ui/public/agg_types/buckets/date_histogram.js
+++ b/src/ui/public/agg_types/buckets/date_histogram.js
@@ -104,6 +104,11 @@ export const dateHistogramBucketAgg = new BucketAggType({
default: null,
write: _.noop,
},
+ {
+ name: 'useNormalizedEsInterval',
+ default: true,
+ write: _.noop,
+ },
{
name: 'interval',
type: 'optioned',
@@ -124,8 +129,8 @@ export const dateHistogramBucketAgg = new BucketAggType({
write: function (agg, output, aggs) {
setBounds(agg, true);
agg.buckets.setInterval(getInterval(agg));
-
- const interval = agg.buckets.getInterval();
+ const { useNormalizedEsInterval } = agg.params;
+ const interval = agg.buckets.getInterval(useNormalizedEsInterval);
output.bucketInterval = interval;
output.params.interval = interval.expression;
diff --git a/src/ui/public/agg_types/buckets/histogram.js b/src/ui/public/agg_types/buckets/histogram.js
index 40502ced08343..4e6448068f584 100644
--- a/src/ui/public/agg_types/buckets/histogram.js
+++ b/src/ui/public/agg_types/buckets/histogram.js
@@ -19,6 +19,8 @@
import _ from 'lodash';
+import { i18n } from '@kbn/i18n';
+import { toastNotifications } from 'ui/notify';
import '../../validate_date_interval';
import chrome from 'ui/chrome';
import { BucketAggType } from './_bucket_agg_type';
@@ -95,6 +97,12 @@ export const histogramBucketAgg = new BucketAggType({
min: _.get(resp, 'aggregations.minAgg.value'),
max: _.get(resp, 'aggregations.maxAgg.value')
});
+ })
+ .catch(() => {
+ toastNotifications.addWarning(i18n.translate('common.ui.aggTypes.histogram.missingMaxMinValuesWarning', {
+ // eslint-disable-next-line max-len
+ defaultMessage: 'Unable to retrieve max and min values to auto-scale histogram buckets. This may lead to poor visualization performance.'
+ }));
});
},
write: function (aggConfig, output) {
diff --git a/src/ui/public/agg_types/controls/order_and_size.html b/src/ui/public/agg_types/controls/order_and_size.html
index 6a5626b3e140e..0daee545ea149 100644
--- a/src/ui/public/agg_types/controls/order_and_size.html
+++ b/src/ui/public/agg_types/controls/order_and_size.html
@@ -1,6 +1,6 @@