diff --git a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/edit_index_pattern/edit_index_pattern.html b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/edit_index_pattern/edit_index_pattern.html index 644ed335e92f2..d576243028624 100644 --- a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/edit_index_pattern/edit_index_pattern.html +++ b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/edit_index_pattern/edit_index_pattern.html @@ -74,8 +74,20 @@
+ i18n-default-message="Support for time-interval based index patterns has been removed! In the next major version of Kibana these index patterns will stop working. Migrate this index pattern to a wildcard pattern by specifying the new pattern below.">
+
+ +
+
diff --git a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/edit_index_pattern/edit_index_pattern.js b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/edit_index_pattern/edit_index_pattern.js index 9fe6df00caa28..8aa281f16572a 100644 --- a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/edit_index_pattern/edit_index_pattern.js +++ b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/edit_index_pattern/edit_index_pattern.js @@ -198,6 +198,16 @@ uiModules.get('apps/management') updateScriptedFieldsTable($scope, $state); }); + $scope.migration = { + isMigrating: false, + newTitle: $scope.indexPattern.getIndex() + }; + $scope.migrate = async function () { + $scope.migration.isMigrating = true; + await $scope.indexPattern.migrate($scope.migration.newTitle); + $scope.migration.isMigrating = false; + }; + $scope.refreshFilters = function () { const indexedFieldTypes = []; const scriptedFieldLanguages = []; diff --git a/src/legacy/core_plugins/kibana/ui_setting_defaults.js b/src/legacy/core_plugins/kibana/ui_setting_defaults.js index e2756d3cf1094..4b02c27f3f66b 100644 --- a/src/legacy/core_plugins/kibana/ui_setting_defaults.js +++ b/src/legacy/core_plugins/kibana/ui_setting_defaults.js @@ -600,17 +600,6 @@ export function getUiSettingDefaults() { 'patterns from which to query the field mapping', }), }, - 'indexPatterns:warnAboutUnsupportedTimePatterns': { - name: i18n.translate('kbn.advancedSettings.indexPattern.unsupportedTimePatternWarningTitle', { - defaultMessage: 'Time pattern warning', - }), - value: false, - description: i18n.translate('kbn.advancedSettings.indexPattern.unsupportedTimePatternWarningText', { - defaultMessage: - 'When an index pattern is using the now unsupported "time pattern" format, a warning will ' + - 'be displayed once per session that is using this pattern. Set this to false to disable that warning.', - }), - }, 'format:defaultTypeMap': { name: i18n.translate('kbn.advancedSettings.format.defaultTypeMapTitle', { defaultMessage: 'Field type format name', diff --git a/src/legacy/ui/public/courier/fetch/request/serialize_fetch_params/__tests__/serialize_fetch_params.js b/src/legacy/ui/public/courier/fetch/request/serialize_fetch_params/__tests__/serialize_fetch_params.js deleted file mode 100644 index 47c50d726c9fc..0000000000000 --- a/src/legacy/ui/public/courier/fetch/request/serialize_fetch_params/__tests__/serialize_fetch_params.js +++ /dev/null @@ -1,73 +0,0 @@ -/* - * 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 ngMock from 'ng_mock'; -import expect from '@kbn/expect'; - -import StubIndexPatternProvider from 'test_utils/stub_index_pattern'; - -import { SerializeFetchParamsProvider } from '../serialize_fetch_params_provider'; - -describe('SerializeFetchParamsProvider', () => { - let serializeFetchParams; - let IndexPattern; - - require('test_utils/no_digest_promises').activateForSuite(); - - beforeEach(ngMock.module('kibana')); - beforeEach(ngMock.inject((Private) => { - serializeFetchParams = Private(SerializeFetchParamsProvider); - IndexPattern = Private(StubIndexPatternProvider); - })); - - describe('when passed IndexPatterns', () => { - it(' that are out of range, queries .kibana', () => { - // Check out https://github.com/elastic/kibana/issues/10905 for the reasons behind this - // test. When an IndexPattern is out of time range, it returns an array that is then stored in a cache. This - // cached object was being modified in a following function, which was a subtle side affect - it looked like - // only a local change. - const indexPattern = new IndexPattern('logstash-*', null, []); - // Stub the call so it looks like the request returns an empty list, which will happen if the time range - // selected doesn't contain any data for the particular index. - indexPattern.toIndexList = () => Promise.resolve([]); - const reqsFetchParams = [ - { - index: indexPattern, - type: 'planet', - search_type: 'water', - body: { foo: 'earth' } - }, - { - index: indexPattern, - type: 'planet', - search_type: 'rings', - body: { foo: 'saturn' } - } - ]; - return serializeFetchParams(reqsFetchParams).then(value => { - const indexLineMatch = value.match(/"index":\[".kibana"\]/g); - expect(indexLineMatch).to.not.be(null); - expect(indexLineMatch.length).to.be(2); - const queryLineMatch = value.match(/"query":\{"bool":\{"must_not":\[\{"match_all":\{\}\}\]\}\}/g); - expect(queryLineMatch).to.not.be(null); - expect(queryLineMatch.length).to.be(2); - }); - }); - }); -}); diff --git a/src/legacy/ui/public/courier/fetch/request/serialize_fetch_params/serialize_fetch_params.js b/src/legacy/ui/public/courier/fetch/request/serialize_fetch_params/serialize_fetch_params.js index 612bbf10aa06c..bafa4f83a2011 100644 --- a/src/legacy/ui/public/courier/fetch/request/serialize_fetch_params/serialize_fetch_params.js +++ b/src/legacy/ui/public/courier/fetch/request/serialize_fetch_params/serialize_fetch_params.js @@ -17,81 +17,30 @@ * under the License. */ -import _ from 'lodash'; - -function emptySearch() { - return { - query: { - bool: { - must_not: [ - { match_all: {} } - ] - } - } - }; -} - /** * * @param requestsFetchParams {Array.} * @param Promise - * @param timeFilter - Only needed for time based interval indexes, which support has been removed from in 6.0. Come - * 7.0 we can completely rip this code out and break them completely. See - * https://github.com/elastic/kibana/issues/12242 and - * https://github.com/elastic/kibana/pull/12158 for more background - * @param kbnIndex * @param sessionId * @return {Promise.} */ export function serializeFetchParams( requestsFetchParams, Promise, - timeFilter, - kbnIndex, sessionId, config, esShardTimeout) { - const indexToListMapping = {}; - const timeBounds = timeFilter.getActiveBounds(); const promises = requestsFetchParams.map(function (fetchParams) { return Promise.resolve(fetchParams.index) - .then(function (indexList) { - if (!_.isFunction(_.get(indexList, 'toIndexList'))) { - return indexList; - } - - if (!indexToListMapping[indexList.id]) { - indexToListMapping[indexList.id] = timeBounds - ? indexList.toIndexList(timeBounds.min, timeBounds.max) - : indexList.toIndexList(); - } - return indexToListMapping[indexList.id].then(indexList => { - // Make sure the index list in the cache can't be subsequently updated. - return _.clone(indexList); - }); - }) - .then(function (indexList) { - let body = { + .then(function (indexPattern) { + const body = { ...fetchParams.body || {}, }; if (esShardTimeout > 0) { body.timeout = `${esShardTimeout}ms`; } - let index = []; - // If we've reached this point and there are no indexes in the - // index list at all, it means that we shouldn't expect any indexes - // to contain the documents we're looking for, so we instead - // perform a request for an index pattern that we know will always - // return an empty result (ie. -*). If instead we had gone ahead - // with an msearch without any index patterns, elasticsearch would - // handle that request by querying *all* indexes, which is the - // opposite of what we want in this case. - if (Array.isArray(indexList) && indexList.length === 0) { - index.push(kbnIndex); - body = emptySearch(); - } else { - index = indexList; - } + + const index = (indexPattern && indexPattern.getIndex) ? indexPattern.getIndex() : indexPattern; const header = { index, diff --git a/src/legacy/ui/public/courier/fetch/request/serialize_fetch_params/serialize_fetch_params.test.js b/src/legacy/ui/public/courier/fetch/request/serialize_fetch_params/serialize_fetch_params.test.js index ef75700ae9ad7..56a2eb93e0416 100644 --- a/src/legacy/ui/public/courier/fetch/request/serialize_fetch_params/serialize_fetch_params.test.js +++ b/src/legacy/ui/public/courier/fetch/request/serialize_fetch_params/serialize_fetch_params.test.js @@ -26,10 +26,6 @@ function serializeFetchParamsWithDefaults(paramOverrides) { const paramDefaults = { requestFetchParams: [], Promise, - timeFilter: { - getActiveBounds: () => undefined, - }, - kbnIndex: '.kibana', sessionId: DEFAULT_SESSION_ID, config: { get: () => { @@ -43,8 +39,6 @@ function serializeFetchParamsWithDefaults(paramOverrides) { return serializeFetchParams( params.requestFetchParams, Promise, - params.timeFilter, - params.kbnIndex, params.sessionId, params.config, params.timeout, @@ -67,34 +61,6 @@ describe('when indexList is not empty', () => { }); }); -describe('when indexList is empty', () => { - const emptyMustNotQuery = JSON.stringify({ - query: { - bool: { - must_not: [ - { match_all: {} } - ] - } - } - }); - - const requestFetchParams = [ - { - index: [], - type: 'blah', - search_type: 'blah2', - body: { foo: 'bar', $foo: 'bar' } - } - ]; - - test('queries the kibana index (.kibana) with a must_not match_all boolean', () => { - return serializeFetchParamsWithDefaults({ requestFetchParams }).then(value => { - expect(_.includes(value, '"index":[".kibana"]')).toBe(true); - expect(_.includes(value, emptyMustNotQuery)).toBe(true); - }); - }); -}); - describe('headers', () => { const requestFetchParams = [ diff --git a/src/legacy/ui/public/courier/fetch/request/serialize_fetch_params/serialize_fetch_params_provider.js b/src/legacy/ui/public/courier/fetch/request/serialize_fetch_params/serialize_fetch_params_provider.js index 956c46c6d947d..4ddcc05b927ff 100644 --- a/src/legacy/ui/public/courier/fetch/request/serialize_fetch_params/serialize_fetch_params_provider.js +++ b/src/legacy/ui/public/courier/fetch/request/serialize_fetch_params/serialize_fetch_params_provider.js @@ -18,15 +18,12 @@ */ import { serializeFetchParams } from './serialize_fetch_params'; -import { timefilter } from 'ui/timefilter'; -export function SerializeFetchParamsProvider(Promise, kbnIndex, sessionId, config, esShardTimeout) { +export function SerializeFetchParamsProvider(Promise, sessionId, config, esShardTimeout) { return (fetchParams) => ( serializeFetchParams( fetchParams, Promise, - timefilter, - kbnIndex, sessionId, config, esShardTimeout) diff --git a/src/legacy/ui/public/courier/search_source/search_source.js b/src/legacy/ui/public/courier/search_source/search_source.js index c10150a30ec3e..fbb5bcb91ce94 100644 --- a/src/legacy/ui/public/courier/search_source/search_source.js +++ b/src/legacy/ui/public/courier/search_source/search_source.js @@ -110,7 +110,7 @@ function parseInitialFields(initialFields) { } function isIndexPattern(val) { - return Boolean(val && typeof val.toIndexList === 'function'); + return Boolean(val && typeof val.getIndex === 'function'); } export function SearchSourceProvider(Promise, Private, config) { diff --git a/src/legacy/ui/public/index_patterns/__tests__/_index_pattern.js b/src/legacy/ui/public/index_patterns/__tests__/_index_pattern.js index bf1234e95f9fc..6b647c88ee86b 100644 --- a/src/legacy/ui/public/index_patterns/__tests__/_index_pattern.js +++ b/src/legacy/ui/public/index_patterns/__tests__/_index_pattern.js @@ -26,15 +26,12 @@ import { DuplicateField } from '../../errors'; import { IndexedArray } from '../../indexed_array'; import FixturesLogstashFieldsProvider from 'fixtures/logstash_fields'; import { FixturesStubbedSavedObjectIndexPatternProvider } from 'fixtures/stubbed_saved_object_index_pattern'; -import { IndexPatternsIntervalsProvider } from '../_intervals'; import { IndexPatternProvider } from '../_index_pattern'; import NoDigestPromises from 'test_utils/no_digest_promises'; -import { toastNotifications } from '../../notify'; import { FieldsFetcherProvider } from '../fields_fetcher_provider'; import { StubIndexPatternsApiClientModule } from './stub_index_patterns_api_client'; import { IndexPatternsApiClientProvider } from '../index_patterns_api_client_provider'; -import { IsUserAwareOfUnsupportedTimePatternProvider } from '../unsupported_time_patterns'; import { SavedObjectsClientProvider } from '../../saved_objects'; describe('index pattern', function () { @@ -47,21 +44,12 @@ describe('index pattern', function () { let savedObjectsResponse; const indexPatternId = 'test-pattern'; let indexPattern; - let intervals; let indexPatternsApiClient; - let defaultTimeField; - let isUserAwareOfUnsupportedTimePattern; - beforeEach(ngMock.module('kibana', StubIndexPatternsApiClientModule, (PrivateProvider) => { - isUserAwareOfUnsupportedTimePattern = sinon.stub().returns(false); - PrivateProvider.swap(IsUserAwareOfUnsupportedTimePatternProvider, () => { - return isUserAwareOfUnsupportedTimePattern; - }); - })); + beforeEach(ngMock.module('kibana', StubIndexPatternsApiClientModule)); beforeEach(ngMock.inject(function (Private) { mockLogstashFields = Private(FixturesLogstashFieldsProvider); - defaultTimeField = mockLogstashFields.find(f => f.type === 'date'); savedObjectsResponse = Private(FixturesStubbedSavedObjectIndexPatternProvider); savedObjectsClient = Private(SavedObjectsClientProvider); @@ -69,13 +57,6 @@ describe('index pattern', function () { sinon.stub(savedObjectsClient, 'get'); sinon.stub(savedObjectsClient, 'update'); - // spy on intervals - intervals = Private(IndexPatternsIntervalsProvider); - sinon.stub(intervals, 'toIndexList').returns([ - { index: 'foo', max: Infinity, min: -Infinity }, - { index: 'bar', max: Infinity, min: -Infinity } - ]); - IndexPattern = Private(IndexPatternProvider); fieldsFetcher = Private(FieldsFetcherProvider); indexPatternsApiClient = Private(IndexPatternsApiClientProvider); @@ -112,7 +93,6 @@ describe('index pattern', function () { expect(indexPattern).to.have.property('popularizeField'); expect(indexPattern).to.have.property('getScriptedFields'); expect(indexPattern).to.have.property('getNonScriptedFields'); - expect(indexPattern).to.have.property('getInterval'); expect(indexPattern).to.have.property('addScriptedField'); expect(indexPattern).to.have.property('removeScriptedField'); expect(indexPattern).to.have.property('toString'); @@ -283,205 +263,38 @@ describe('index pattern', function () { }); }); - describe('#toDetailedIndexList', function () { - describe('when index pattern is an interval', function () { - let interval; - beforeEach(function () { - interval = 'result:getInterval'; - sinon.stub(indexPattern, 'getInterval').returns(interval); - sinon.stub(indexPattern, 'isTimeBasedInterval').returns(true); - }); - - it('invokes interval toDetailedIndexList with given start/stop times', async function () { - await indexPattern.toDetailedIndexList(1, 2); - sinon.assert.calledWith(intervals.toIndexList, indexPattern.title, interval, 1, 2); - }); - - it('is fulfilled by the result of interval toDetailedIndexList', async function () { - const indexList = await indexPattern.toDetailedIndexList(); - expect(indexList.map(i => i.index)).to.eql(['foo', 'bar']); - }); - - describe('with sort order', function () { - it('passes the sort order to the intervals module', async function () { - await indexPattern.toDetailedIndexList(1, 2, 'SORT_DIRECTION'); - sinon.assert.calledOnce(intervals.toIndexList); - expect(intervals.toIndexList.getCall(0).args[4]).to.be('SORT_DIRECTION'); - }); - }); + describe('getIndex', () => { + it('should return the title when there is no intervalName', () => { + expect(indexPattern.getIndex()).to.be(indexPattern.title); }); - describe('when index pattern is a time-base wildcard', function () { - beforeEach(function () { - indexPattern.id = 'randomID'; - indexPattern.title = 'logstash-*'; - indexPattern.timeFieldName = defaultTimeField.name; - indexPattern.intervalName = null; - indexPattern.notExpandable = true; - }); - - it('is fulfilled by title', async function () { - const indexList = await indexPattern.toDetailedIndexList(); - expect(indexList.map(i => i.index)).to.eql([indexPattern.title]); - }); - }); + it('should convert time-based intervals to wildcards', () => { + const oldTitle = indexPattern.title; + indexPattern.intervalName = 'daily'; - describe('when index pattern is neither an interval nor a time-based wildcard', function () { - beforeEach(function () { - indexPattern.id = 'randomID'; - indexPattern.title = 'logstash-0'; - indexPattern.timeFieldName = null; - indexPattern.intervalName = null; - indexPattern.notExpandable = true; - }); - - it('is fulfilled by title', async function () { - const indexList = await indexPattern.toDetailedIndexList(); - expect(indexList.map(i => i.index)).to.eql([indexPattern.title]); - }); - }); - }); - - describe('#toIndexList', function () { - describe('when index pattern is an interval', function () { - - let interval; - beforeEach(function () { - indexPattern.id = 'randomID'; - indexPattern.title = '[logstash-]YYYY'; - indexPattern.timeFieldName = defaultTimeField.name; - interval = intervals.byName.years; - indexPattern.intervalName = interval.name; - indexPattern.notExpandable = true; - }); - - it('invokes interval toIndexList with given start/stop times', async function () { - await indexPattern.toIndexList(1, 2); - const { title } = indexPattern; - sinon.assert.calledWith(intervals.toIndexList, title, interval, 1, 2); - }); - - it('is fulfilled by the result of interval toIndexList', async function () { - const indexList = await indexPattern.toIndexList(); - expect(indexList).to.equal('foo,bar'); - }); - - describe('with sort order', function () { - it('passes the sort order to the intervals module', function () { - return indexPattern.toIndexList(1, 2, 'SORT_DIRECTION') - .then(function () { - expect(intervals.toIndexList.callCount).to.be(1); - expect(intervals.toIndexList.getCall(0).args[4]).to.be('SORT_DIRECTION'); - }); - }); - }); - }); + indexPattern.title = '[logstash-]YYYY.MM.DD'; + expect(indexPattern.getIndex()).to.be('logstash-*'); - describe('when index pattern is a time-base wildcard', function () { - beforeEach(function () { - indexPattern.id = 'randomID'; - indexPattern.title = 'logstash-*'; - indexPattern.timeFieldName = defaultTimeField.name; - indexPattern.intervalName = null; - indexPattern.notExpandable = true; - }); + indexPattern.title = 'YYYY.MM.DD[-logstash]'; + expect(indexPattern.getIndex()).to.be('*-logstash'); - it('is fulfilled using the id', async function () { - const indexList = await indexPattern.toIndexList(); - expect(indexList).to.eql(indexPattern.title); - }); - }); + indexPattern.title = 'YYYY[-logstash-]YYYY.MM.DD'; + expect(indexPattern.getIndex()).to.be('*-logstash-*'); - describe('when index pattern is neither an interval nor a time-based wildcard', function () { - beforeEach(function () { - indexPattern.id = 'randomID'; - indexPattern.title = 'logstash-0'; - indexPattern.timeFieldName = null; - indexPattern.intervalName = null; - indexPattern.notExpandable = true; - }); + indexPattern.title = 'YYYY[-logstash-]YYYY[-foo-]MM.DD'; + expect(indexPattern.getIndex()).to.be('*-logstash-*-foo-*'); - it('is fulfilled by id', async function () { - const indexList = await indexPattern.toIndexList(); - expect(indexList).to.eql(indexPattern.title); - }); - }); - }); + indexPattern.title = 'YYYY[-logstash-]YYYY[-foo-]MM.DD[-bar]'; + expect(indexPattern.getIndex()).to.be('*-logstash-*-foo-*-bar'); - describe('#isTimeBased()', function () { - beforeEach(function () { - // for the sake of these tests, it doesn't much matter what type of field - // this is so long as it exists - indexPattern.timeFieldName = 'bytes'; - }); - it('returns false if no time field', function () { - delete indexPattern.timeFieldName; - expect(indexPattern.isTimeBased()).to.be(false); - }); - it('returns false if time field does not actually exist in fields', function () { - indexPattern.timeFieldName = 'does not exist'; - expect(indexPattern.isTimeBased()).to.be(false); - }); - it('returns true if fields are not loaded yet', () => { - indexPattern.fields = null; - expect(indexPattern.isTimeBased()).to.be(true); - }); - it('returns true if valid time field is configured', function () { - expect(indexPattern.isTimeBased()).to.be(true); - }); - }); + indexPattern.title = '[logstash-]YYYY[-foo-]MM.DD[-bar]'; + expect(indexPattern.getIndex()).to.be('logstash-*-foo-*-bar'); - describe('#isWildcard()', function () { - it('returns true if id has an *', function () { - indexPattern.title = 'foo*'; - expect(indexPattern.isWildcard()).to.be(true); - }); - it('returns false if id has no *', function () { - indexPattern.title = 'foo'; - expect(indexPattern.isWildcard()).to.be(false); - }); - }); + indexPattern.title = '[logstash]'; + expect(indexPattern.getIndex()).to.be('logstash'); - describe('#isUnsupportedTimePattern()', () => { - it('returns true when intervalName is set', () => { - indexPattern.intervalName = 'something'; - expect(indexPattern.isUnsupportedTimePattern()).to.be(true); - }); - it('returns false otherwise', () => { + indexPattern.title = oldTitle; delete indexPattern.intervalName; - expect(indexPattern.isUnsupportedTimePattern()).to.be(false); - }); - }); - - describe('unsupported time pattern warning', () => { - async function createUnsupportedTimePattern() { - return await create('randomID', { - attributes: { - title: 'pattern-id', - timeFieldName: '@timestamp', - intervalName: 'days', - fields: '[]' - } - }); - } - - it('logs a warning when the index pattern source includes `intervalName`', async () => { - await createUnsupportedTimePattern(); - expect(toastNotifications.list).to.have.length(1); - }); - - it('does not notify if isUserAwareOfUnsupportedTimePattern() returns true', async () => { - // Ideally, _index_pattern.js shouldn't be tightly coupled to toastNotifications. Instead, it - // should notify its consumer of this state and the consumer should be responsible for - // notifying the user. This test verifies the side effect of the state until we can remove - // this coupling. - - // Clear existing toasts. - toastNotifications.list.splice(0); - - isUserAwareOfUnsupportedTimePattern.returns(true); - await createUnsupportedTimePattern(); - expect(toastNotifications.list).to.have.length(0); }); }); }); diff --git a/src/legacy/ui/public/index_patterns/__tests__/_index_pattern.test.js b/src/legacy/ui/public/index_patterns/__tests__/_index_pattern.test.js index 64f39634770b9..f06fbfca1c37b 100644 --- a/src/legacy/ui/public/index_patterns/__tests__/_index_pattern.test.js +++ b/src/legacy/ui/public/index_patterns/__tests__/_index_pattern.test.js @@ -59,10 +59,6 @@ jest.mock('../_get', () => ({ })) })); -jest.mock('../_intervals', () => ({ - IndexPatternsIntervalsProvider: jest.fn(), -})); - jest.mock('../_flatten_hit', () => ({ IndexPatternsFlattenHitProvider: jest.fn(), })); @@ -79,10 +75,6 @@ jest.mock('../fields_fetcher_provider', () => ({ } })); -jest.mock('../unsupported_time_patterns', () => ({ - IsUserAwareOfUnsupportedTimePatternProvider: jest.fn(), -})); - jest.mock('../../saved_objects', () => { const object = { diff --git a/src/legacy/ui/public/index_patterns/__tests__/intervals.js b/src/legacy/ui/public/index_patterns/__tests__/intervals.js deleted file mode 100644 index cc2ba5d5f4745..0000000000000 --- a/src/legacy/ui/public/index_patterns/__tests__/intervals.js +++ /dev/null @@ -1,187 +0,0 @@ -/* - * 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 moment from 'moment'; -import expect from '@kbn/expect'; -import ngMock from 'ng_mock'; -import { IndexPatternsIntervalsProvider } from '../_intervals'; - -describe('Index Patterns', function () { - describe('interval.toIndexList()', function () { - - let intervals; - beforeEach(ngMock.module('kibana')); - beforeEach(ngMock.inject(function (Private) { - intervals = Private(IndexPatternsIntervalsProvider); - })); - - it('should return correct indices for hourly [logstash-]YYYY.MM.DD.HH', function () { - const start = moment.utc('2014-01-01T07:00:00Z'); - const end = moment.utc('2014-01-01T08:30:00Z'); - const interval = { name: 'hours', startOf: 'hour', display: 'Hourly' }; - const list = intervals.toIndexList('[logstash-]YYYY.MM.DD.HH', interval, start, end); - expect(list).to.eql([ - { - index: 'logstash-2014.01.01.07', - min: moment.utc('2014-01-01T07:00:00').valueOf(), - max: moment.utc('2014-01-01T07:59:59.999').valueOf(), - }, - { - index: 'logstash-2014.01.01.08', - min: moment.utc('2014-01-01T08:00:00').valueOf(), - max: moment.utc('2014-01-01T08:59:59.999').valueOf(), - } - ]); - }); - - it('should return correct indices for daily [logstash-]YYYY.MM.DD', function () { - const start = moment(1418244231248); - const end = moment(1418849261281); - const interval = { name: 'days', startOf: 'day', display: 'Daily' }; - const list = intervals.toIndexList('[logstash-]YYYY.MM.DD', interval, start, end); - expect(list).to.eql([ - { - index: 'logstash-2014.12.10', - min: moment.utc('2014-12-10T00:00:00').valueOf(), - max: moment.utc('2014-12-10T23:59:59.999').valueOf(), - }, - { - index: 'logstash-2014.12.11', - min: moment.utc('2014-12-11T00:00:00').valueOf(), - max: moment.utc('2014-12-11T23:59:59.999').valueOf(), - }, - { - index: 'logstash-2014.12.12', - min: moment.utc('2014-12-12T00:00:00').valueOf(), - max: moment.utc('2014-12-12T23:59:59.999').valueOf(), - }, - { - index: 'logstash-2014.12.13', - min: moment.utc('2014-12-13T00:00:00').valueOf(), - max: moment.utc('2014-12-13T23:59:59.999').valueOf(), - }, - { - index: 'logstash-2014.12.14', - min: moment.utc('2014-12-14T00:00:00').valueOf(), - max: moment.utc('2014-12-14T23:59:59.999').valueOf(), - }, - { - index: 'logstash-2014.12.15', - min: moment.utc('2014-12-15T00:00:00').valueOf(), - max: moment.utc('2014-12-15T23:59:59.999').valueOf(), - }, - { - index: 'logstash-2014.12.16', - min: moment.utc('2014-12-16T00:00:00').valueOf(), - max: moment.utc('2014-12-16T23:59:59.999').valueOf(), - }, - { - index: 'logstash-2014.12.17', - min: moment.utc('2014-12-17T00:00:00').valueOf(), - max: moment.utc('2014-12-17T23:59:59.999').valueOf(), - }, - ]); - }); - - it('should return correct indices for monthly [logstash-]YYYY.MM', function () { - const start = moment.utc('2014-12-01'); - const end = moment.utc('2015-02-01'); - const interval = { name: 'months', startOf: 'month', display: 'Monthly' }; - const list = intervals.toIndexList('[logstash-]YYYY.MM', interval, start, end); - expect(list).to.eql([ - { - index: 'logstash-2014.12', - min: moment.utc(0).year(2014).month(11).valueOf(), - max: moment.utc(0).year(2015).month(0).subtract(1, 'ms').valueOf(), - }, - { - index: 'logstash-2015.01', - min: moment.utc(0).year(2015).month(0).valueOf(), - max: moment.utc(0).year(2015).month(1).subtract(1, 'ms').valueOf(), - }, - { - index: 'logstash-2015.02', - min: moment.utc(0).year(2015).month(1).valueOf(), - max: moment.utc(0).year(2015).month(2).subtract(1, 'ms').valueOf(), - }, - ]); - }); - - it('should return correct indices for yearly [logstash-]YYYY', function () { - const start = moment.utc('2014-12-01'); - const end = moment.utc('2015-02-01'); - const interval = { name: 'years', startOf: 'year', display: 'Yearly' }; - const list = intervals.toIndexList('[logstash-]YYYY', interval, start, end); - expect(list).to.eql([ - { - index: 'logstash-2014', - min: moment.utc(0).year(2014).valueOf(), - max: moment.utc(0).year(2015).subtract(1, 'ms').valueOf(), - }, - { - index: 'logstash-2015', - min: moment.utc(0).year(2015).valueOf(), - max: moment.utc(0).year(2016).subtract(1, 'ms').valueOf(), - }, - ]); - }); - - describe('with sortDirection=asc', function () { - it('returns values in ascending order', function () { - const start = moment.utc('2014-12-01'); - const end = moment.utc('2015-02-01'); - const interval = { name: 'years', startOf: 'year', display: 'Yearly' }; - const list = intervals.toIndexList('[logstash-]YYYY', interval, start, end, 'asc'); - expect(list).to.eql([ - { - index: 'logstash-2014', - min: moment.utc(0).year(2014).valueOf(), - max: moment.utc(0).year(2015).subtract(1, 'ms').valueOf(), - }, - { - index: 'logstash-2015', - min: moment.utc(0).year(2015).valueOf(), - max: moment.utc(0).year(2016).subtract(1, 'ms').valueOf(), - }, - ]); - }); - }); - - describe('with sortDirection=desc', function () { - it('returns values in descending order', function () { - const start = moment.utc('2014-12-01'); - const end = moment.utc('2015-02-01'); - const interval = { name: 'years', startOf: 'year', display: 'Yearly' }; - const list = intervals.toIndexList('[logstash-]YYYY', interval, start, end, 'desc'); - expect(list).to.eql([ - { - index: 'logstash-2015', - min: moment.utc(0).year(2015).valueOf(), - max: moment.utc(0).year(2016).subtract(1, 'ms').valueOf(), - }, - { - index: 'logstash-2014', - min: moment.utc(0).year(2014).valueOf(), - max: moment.utc(0).year(2015).subtract(1, 'ms').valueOf(), - }, - ]); - }); - }); - }); -}); diff --git a/src/legacy/ui/public/index_patterns/__tests__/unsupported_time_patterns.js b/src/legacy/ui/public/index_patterns/__tests__/unsupported_time_patterns.js deleted file mode 100644 index a3af1332136a8..0000000000000 --- a/src/legacy/ui/public/index_patterns/__tests__/unsupported_time_patterns.js +++ /dev/null @@ -1,95 +0,0 @@ -/* - * 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 ngMock from 'ng_mock'; -import expect from '@kbn/expect'; -import Chance from 'chance'; - -import { Storage } from '../../storage'; -import { StubBrowserStorage } from 'test_utils/stub_browser_storage'; -import StubIndexPatternProvider from 'test_utils/stub_index_pattern'; -import { IsUserAwareOfUnsupportedTimePatternProvider } from '../unsupported_time_patterns'; - -const chance = new Chance(); -const CONFIG_KEY = 'indexPatterns:warnAboutUnsupportedTimePatterns'; - -describe('isUserAwareOfUnsupportedTimePattern()', () => { - let setup; - - beforeEach(function () { - setup = () => { - const store = new StubBrowserStorage(); - const sessionStorage = new Storage(store); - - // stub some core services - ngMock.module('kibana', $provide => { - $provide.value('sessionStorage', sessionStorage); - }); - // trigger creation of the injector - ngMock.inject(); - - const { $injector } = this; - const Private = $injector.get('Private'); - const StubIndexPattern = Private(StubIndexPatternProvider); - const isUserAwareOfUnsupportedTimePattern = Private(IsUserAwareOfUnsupportedTimePatternProvider); - - const config = $injector.get('config'); - config.set(CONFIG_KEY, true); // enable warnings - - return { - config, - createIndexPattern: () => new StubIndexPattern(chance.word(), null, []), - isUserAwareOfUnsupportedTimePattern, - }; - }; - }); - - it('only warns once per index pattern', () => { - const { - createIndexPattern, - isUserAwareOfUnsupportedTimePattern, - } = setup(); - - const indexPattern1 = createIndexPattern(); - const indexPattern2 = createIndexPattern(); - - expect(isUserAwareOfUnsupportedTimePattern(indexPattern1)).to.be(false); - expect(isUserAwareOfUnsupportedTimePattern(indexPattern1)).to.be(true); - expect(isUserAwareOfUnsupportedTimePattern(indexPattern2)).to.be(false); - expect(isUserAwareOfUnsupportedTimePattern(indexPattern1)).to.be(true); - expect(isUserAwareOfUnsupportedTimePattern(indexPattern2)).to.be(true); - expect(isUserAwareOfUnsupportedTimePattern(indexPattern1)).to.be(true); - }); - - describe('ui config', () => { - it('respects setting', () => { - const { - config, - isUserAwareOfUnsupportedTimePattern, - createIndexPattern, - } = setup(); - - config.set(CONFIG_KEY, false); - expect(isUserAwareOfUnsupportedTimePattern(createIndexPattern())).to.be(true); - - config.set(CONFIG_KEY, true); - expect(isUserAwareOfUnsupportedTimePattern(createIndexPattern())).to.be(false); - }); - }); -}); diff --git a/src/legacy/ui/public/index_patterns/_index_pattern.js b/src/legacy/ui/public/index_patterns/_index_pattern.js index 434c5a96f584f..def22982495ca 100644 --- a/src/legacy/ui/public/index_patterns/_index_pattern.js +++ b/src/legacy/ui/public/index_patterns/_index_pattern.js @@ -23,18 +23,19 @@ import angular from 'angular'; import { fieldFormats } from '../registry/field_formats'; import UtilsMappingSetupProvider from '../utils/mapping_setup'; import { Notifier, toastNotifications } from '../notify'; +import { EuiButton, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; +import React from 'react'; import { getComputedFields } from './_get_computed_fields'; import { formatHit } from './_format_hit'; import { IndexPatternsGetProvider } from './_get'; -import { IndexPatternsIntervalsProvider } from './_intervals'; import { FieldList } from './_field_list'; import { IndexPatternsFlattenHitProvider } from './_flatten_hit'; import { IndexPatternsPatternCacheProvider } from './_pattern_cache'; import { FieldsFetcherProvider } from './fields_fetcher_provider'; -import { IsUserAwareOfUnsupportedTimePatternProvider } from './unsupported_time_patterns'; import { SavedObjectsClientProvider, findObjectByTitle } from '../saved_objects'; import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n/react'; export function getRoutes() { return { @@ -52,11 +53,9 @@ export function IndexPatternProvider(Private, config, Promise, confirmModalPromi const getConfig = (...args) => config.get(...args); const getIds = Private(IndexPatternsGetProvider)('id'); const fieldsFetcher = Private(FieldsFetcherProvider); - const intervals = Private(IndexPatternsIntervalsProvider); const mappingSetup = Private(UtilsMappingSetupProvider); const flattenHit = Private(IndexPatternsFlattenHitProvider); const patternCache = Private(IndexPatternsPatternCacheProvider); - const isUserAwareOfUnsupportedTimePattern = Private(IsUserAwareOfUnsupportedTimePatternProvider); const savedObjectsClient = Private(SavedObjectsClientProvider); const fieldformats = fieldFormats; @@ -119,24 +118,33 @@ export function IndexPatternProvider(Private, config, Promise, confirmModalPromi } if (indexPattern.isUnsupportedTimePattern()) { - if (!isUserAwareOfUnsupportedTimePattern(indexPattern)) { - const warningTitle = i18n.translate('common.ui.indexPattern.warningTitle', { - defaultMessage: 'Support for time intervals was removed', - }); + const warningTitle = i18n.translate('common.ui.indexPattern.warningTitle', { + defaultMessage: 'Support for time interval index patterns removed', + }); - const warningText = i18n.translate('common.ui.indexPattern.warningText', { - defaultMessage: 'For more information, view the ["{title}" index pattern in management]({link})', - values: { - title: indexPattern.title, - link: kbnUrl.getRouteHref(indexPattern, 'edit'), - }, - }); + const warningText = i18n.translate('common.ui.indexPattern.warningText', { + defaultMessage: 'Currently querying all indices matching {index}. {title} should be migrated to a wildcard-based index pattern.', + values: { + title: indexPattern.title, + index: indexPattern.getIndex() + } + }); - toastNotifications.addWarning({ - title: warningTitle, - text: warningText, - }); - } + toastNotifications.addWarning({ + title: warningTitle, + text: ( +
+

{warningText}

+ + + + + + + +
+ ), + }); } return indexFields(indexPattern, forceFieldRefresh); @@ -269,6 +277,16 @@ export function IndexPatternProvider(Private, config, Promise, confirmModalPromi .then(() => this); } + migrate(newTitle) { + return savedObjectsClient.update(type, this.id, { + title: newTitle, + intervalName: null + }).then(({ attributes: { title, intervalName } }) => { + this.title = title; + this.intervalName = intervalName; + }).then(() => this); + } + // Get the source filtering configuration for that index. getSourceFiltering() { return { @@ -329,47 +347,27 @@ export function IndexPatternProvider(Private, config, Promise, confirmModalPromi return _.where(this.fields, { scripted: true }); } - getInterval() { - return this.intervalName && _.find(intervals, { name: this.intervalName }); - } - - toIndexList(start, stop, sortDirection) { - return this - .toDetailedIndexList(start, stop, sortDirection) - .then(detailedIndices => { - if (!Array.isArray(detailedIndices)) { - return detailedIndices.index; - } - return detailedIndices.map(({ index }) => index).join(','); - }); - } - - toDetailedIndexList(start, stop, sortDirection) { - return Promise.resolve().then(() => { - if (this.isTimeBasedInterval()) { - return intervals.toIndexList( - this.title, this.getInterval(), start, stop, sortDirection - ); - } + getIndex() { + if (!this.isUnsupportedTimePattern()) { + return this.title; + } - return [ - { - index: this.title, - min: -Infinity, - max: Infinity - } - ]; - }); + // Take a time-based interval index pattern title (like [foo-]YYYY.MM.DD[-bar]) and turn it + // into the actual index (like foo-*-bar) by replacing anything not inside square brackets + // with a *. + const regex = /\[[^\]]*]/g; // Matches text inside brackets + const splits = this.title.split(regex); // e.g. ['', 'YYYY.MM.DD', ''] from the above example + const matches = this.title.match(regex); // e.g. ['[foo-]', '[-bar]'] from the above example + return splits.map((split, i) => { + const match = i >= matches.length ? '' : matches[i].replace(/[\[\]]/g, ''); + return `${split.length ? '*' : ''}${match}`; + }).join(''); } isTimeBased() { return !!this.timeFieldName && (!this.fields || !!this.getTimeField()); } - isTimeBasedInterval() { - return this.isTimeBased() && !!this.getInterval(); - } - isUnsupportedTimePattern() { return !!this.intervalName; } diff --git a/src/legacy/ui/public/index_patterns/_intervals.js b/src/legacy/ui/public/index_patterns/_intervals.js deleted file mode 100644 index 2afd22276f976..0000000000000 --- a/src/legacy/ui/public/index_patterns/_intervals.js +++ /dev/null @@ -1,122 +0,0 @@ -/* - * 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 _ from 'lodash'; -import moment from 'moment'; -import { IndexedArray } from '../indexed_array'; -import { isNumeric } from '../utils/numeric'; -import { timefilter } from 'ui/timefilter'; -import { i18n } from '@kbn/i18n'; - -export function IndexPatternsIntervalsProvider() { - - const intervals = new IndexedArray({ - index: ['name'], - initialSet: [ - { - name: 'hours', - startOf: 'hour', - display: i18n.translate('common.ui.indexPattern.intervals.hourlyHeader', { defaultMessage: 'Hourly' }) - }, - { - name: 'days', - startOf: 'day', - display: i18n.translate('common.ui.indexPattern.intervals.dailyHeader', { defaultMessage: 'Daily' }) - }, - { - name: 'weeks', - startOf: 'isoWeek', - display: i18n.translate('common.ui.indexPattern.intervals.weeklyHeader', { defaultMessage: 'Weekly' }) - }, - { - name: 'months', - startOf: 'month', - display: i18n.translate('common.ui.indexPattern.intervals.monthlyHeader', { defaultMessage: 'Monthly' }) - }, - { - name: 'years', - startOf: 'year', - display: i18n.translate('common.ui.indexPattern.intervals.yearlyHeader', { defaultMessage: 'Yearly' }) - } - ] - }); - - intervals.toIndexList = function (format, interval, a, b, sortDirection) { - let bounds; - - // setup the range that the list will span, return two moment objects that - // are in proper order. a and b can be numbers to specify to go before or after now (respectively) - // a certain number of times, based on the interval - const range = [[a, 'min', 'startOf'], [b, 'max', 'startOf']].map(function (v) { - let val = v[0]; - const bound = v[1]; - const extend = v[2]; - - // grab a bound from the time filter - if (val == null) { - bounds = bounds || timefilter.getBounds(); - val = bounds[bound]; - } - - if (isNumeric(val)) val = moment().add(val, interval.name); - else if (!moment.isMoment(val)) val = moment(val); - - return val.clone().utc()[extend](interval.startOf); - }).sort(function (a, b) { - return a - b; - }); - - if (typeof interval === 'string') { - interval = _.find(intervals, { name: interval }); - if (!interval) { - const errorMessage = i18n.translate('common.ui.indexPattern.intervalsErrorMessage', - { values: { intervals: _.pluck(intervals, 'name') }, defaultMessage: 'Interval must be one of {intervals}' }); - - throw new Error(errorMessage); - } - } - - const indexList = []; - let start = range.shift(); - // turn stop into milliseconds to that it's not constantly converted by the while condition - const stop = range.shift().valueOf(); - - const add = sortDirection === 'desc' ? 'unshift' : 'push'; - - while (start <= stop) { - const index = start.format(format); - const next = moment(start).add(1, interval.name); - const bound = moment(next).subtract(1, 'ms'); - - const min = start.valueOf(); - const max = bound.valueOf(); - indexList[add]({ - index: index, - min: min, - max: max - }); - - start = next; - } - - return indexList; - }; - - return intervals; -} diff --git a/src/legacy/ui/public/index_patterns/fields_fetcher.js b/src/legacy/ui/public/index_patterns/fields_fetcher.js index 9319aaff1b35b..7d25328f29232 100644 --- a/src/legacy/ui/public/index_patterns/fields_fetcher.js +++ b/src/legacy/ui/public/index_patterns/fields_fetcher.js @@ -20,25 +20,12 @@ export function createFieldsFetcher(apiClient, config) { class FieldsFetcher { fetch(indexPattern) { - if (indexPattern.isTimeBasedInterval()) { - const interval = indexPattern.getInterval().name; - return this.fetchForTimePattern(indexPattern.title, interval); - } - - return this.fetchForWildcard(indexPattern.title, { + return this.fetchForWildcard(indexPattern.getIndex(), { type: indexPattern.type, params: indexPattern.typeMeta && indexPattern.typeMeta.params, }); } - fetchForTimePattern(indexPatternId) { - return apiClient.getFieldsForTimePattern({ - pattern: indexPatternId, - lookBack: config.get('indexPattern:fieldMapping:lookBack'), - metaFields: config.get('metaFields'), - }); - } - fetchForWildcard(indexPatternId, options = {}) { return apiClient.getFieldsForWildcard({ pattern: indexPatternId, diff --git a/src/legacy/ui/public/index_patterns/index_patterns.js b/src/legacy/ui/public/index_patterns/index_patterns.js index afaa4a44b0510..7c03c79b336a1 100644 --- a/src/legacy/ui/public/index_patterns/index_patterns.js +++ b/src/legacy/ui/public/index_patterns/index_patterns.js @@ -21,7 +21,6 @@ import { IndexPatternMissingIndices } from '../errors'; import { IndexPatternProvider } from './_index_pattern'; import { IndexPatternsPatternCacheProvider } from './_pattern_cache'; import { IndexPatternsGetProvider } from './_get'; -import { IndexPatternsIntervalsProvider } from './_intervals'; import { FieldsFetcherProvider } from './fields_fetcher_provider'; import { fieldFormats } from '../registry/field_formats'; import { uiModules } from '../modules'; @@ -68,7 +67,6 @@ export function IndexPatternsProvider(Private, config) { self.getIds = getProvider('id'); self.getTitles = getProvider('attributes.title'); self.getFields = getProvider.multiple; - self.intervals = Private(IndexPatternsIntervalsProvider); self.fieldsFetcher = Private(FieldsFetcherProvider); self.fieldFormats = fieldFormats; self.IndexPattern = IndexPattern; diff --git a/src/legacy/ui/public/index_patterns/unsupported_time_patterns.js b/src/legacy/ui/public/index_patterns/unsupported_time_patterns.js deleted file mode 100644 index 44681aaf8035f..0000000000000 --- a/src/legacy/ui/public/index_patterns/unsupported_time_patterns.js +++ /dev/null @@ -1,47 +0,0 @@ -/* - * 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 { BoundToConfigObjProvider } from '../bound_to_config_obj'; - -export function IsUserAwareOfUnsupportedTimePatternProvider(Private, $injector) { - const BoundToConfigObj = Private(BoundToConfigObjProvider); - const sessionStorage = $injector.get('sessionStorage'); - - const HISTORY_STORAGE_KEY = 'indexPatterns:warnAboutUnsupportedTimePatterns:history'; - const FLAGS = new BoundToConfigObj({ - enabled: '=indexPatterns:warnAboutUnsupportedTimePatterns' - }); - - return function isUserAwareOfUnsupportedTimePattern(indexPattern) { - // The user's disabled the notification. They know about it. - if (!FLAGS.enabled) { - return true; - } - - // We've already told the user. - const previousIds = sessionStorage.get(HISTORY_STORAGE_KEY) || []; - if (previousIds.includes(indexPattern.id)) { - return true; - } - - // Let's store this for later, so we don't tell the user multiple times. - sessionStorage.set(HISTORY_STORAGE_KEY, [...previousIds, indexPattern.id]); - return false; - }; -} diff --git a/src/test_utils/public/stub_index_pattern.js b/src/test_utils/public/stub_index_pattern.js index 16b1239c4dfec..281012eddd916 100644 --- a/src/test_utils/public/stub_index_pattern.js +++ b/src/test_utils/public/stub_index_pattern.js @@ -17,9 +17,7 @@ * under the License. */ -import _ from 'lodash'; import sinon from 'sinon'; -import Promise from 'bluebird'; import { IndexPatternProvider, getRoutes } from 'ui/index_patterns/_index_pattern'; import { formatHit } from 'ui/index_patterns/_format_hit'; import { getComputedFields } from 'ui/index_patterns/_get_computed_fields'; @@ -45,12 +43,7 @@ export default function (Private) { this.fieldFormatMap = {}; this.routes = getRoutes(); - this.toIndexList = _.constant(Promise.resolve(pattern.split(','))); - this.toDetailedIndexList = _.constant(Promise.resolve(pattern.split(',').map(index => ({ - index, - min: 0, - max: 1 - })))); + this.getIndex = () => pattern; this.getComputedFields = getComputedFields.bind(this); this.flattenHit = flattenHit(this); this.formatHit = formatHit(this, fieldFormats.getDefaultInstance('string')); diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index d01e53d64eebc..3c675e7f108fa 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -465,18 +465,10 @@ "common.ui.indexPattern.confirmOverwriteButton": "覆盖", "common.ui.indexPattern.confirmOverwriteLabel": "确定要覆盖 “{title}”?", "common.ui.indexPattern.confirmOverwriteTitle": "覆盖 {type}?", - "common.ui.indexPattern.intervals.dailyHeader": "每日", - "common.ui.indexPattern.intervals.hourlyHeader": "每小时", - "common.ui.indexPattern.intervals.monthlyHeader": "每月", - "common.ui.indexPattern.intervals.weeklyHeader": "每周", - "common.ui.indexPattern.intervals.yearlyHeader": "每年", - "common.ui.indexPattern.intervalsErrorMessage": "时间间隔必须是 {intervals} 之一", "common.ui.indexPattern.titleExistsLabel": "具有标题 “{title}” 的索引模式已存在。", "common.ui.indexPattern.unableWriteLabel": "无法写入索引模式!请刷新页面以获取此索引模式的最新更改。", "common.ui.indexPattern.unknownFieldErrorMessage": "indexPattern “{title}” 中的字段 “{name}” 使用未知字段类型。", "common.ui.indexPattern.unknownFieldHeader": "未知字段类型 {type}", - "common.ui.indexPattern.warningText": "有关详细信息,请查看[“管理”中的 “{title}” 索引模式]({link})", - "common.ui.indexPattern.warningTitle": "对时间间隔的支持已移除", "common.ui.inspector.closeButton": "关闭检查器", "common.ui.inspector.reqTimestampDescription": "记录请求启动的时间", "common.ui.inspector.reqTimestampKey": "请求时间戳", @@ -832,8 +824,6 @@ "kbn.advancedSettings.historyLimitTitle": "历史记录限制", "kbn.advancedSettings.indexPattern.recentMatchingText": "对于名称中包含时间戳的索引模式,寻找此数目的最近匹配模式,以从其中查询字段映射", "kbn.advancedSettings.indexPattern.recentMatchingTitle": "最近匹配模式", - "kbn.advancedSettings.indexPattern.unsupportedTimePatternWarningText": "索引模式使用当前不受支持的“时间模式”格式时,使用此模式的每个会话会显示一次警告。将其设置为 false 可禁用该警告。", - "kbn.advancedSettings.indexPattern.unsupportedTimePatternWarningTitle": "时间模式警告", "kbn.advancedSettings.indexPatternPlaceholderText": "在“管理 > 索引模式 > 创建索引模式”中“索引模式名称”的占位符。", "kbn.advancedSettings.indexPatternPlaceholderTitle": "索引模式占位符", "kbn.advancedSettings.maxBucketsText": "单个数据源可以返回的最大存储桶数目", @@ -1521,8 +1511,6 @@ "kbn.management.editIndexPattern.timeFilterHeader": "时间筛选字段名称:{timeFieldName}", "kbn.management.editIndexPattern.timeFilterLabel.mappingAPILink": "映射 API", "kbn.management.editIndexPattern.timeFilterLabel.timeFilterDetail": "此页根据 Elasticsearch 的记录列出“{indexPatternTitle}”索引中的每个字段以及字段的关联核心类型。要更改字段类型,请使用 Elasticsearch", - "kbn.management.editIndexPattern.unsupportedTimePatternHeader": "对重复索引模式的支持已移除", - "kbn.management.editIndexPattern.unsupportedTimePatternLabel": "对基于时间间隔的索引模式的支持已移除!在 Kibana 下一主要版本中,此索引模式将不再有效。将使用此索引模式的已保存对象迁移到通配符模式,并删除此模式。", "kbn.management.editIndexPatternLiveRegionAriaLabel": "索引模式", "kbn.management.indexPattern.sectionsHeader": "索引模式", "kbn.management.indexPatternHeader": "索引模式",