diff --git a/src/legacy/core_plugins/kibana/public/discover/kibana_services.ts b/src/legacy/core_plugins/kibana/public/discover/kibana_services.ts index 3aa552b1da07d..77664e87a3279 100644 --- a/src/legacy/core_plugins/kibana/public/discover/kibana_services.ts +++ b/src/legacy/core_plugins/kibana/public/discover/kibana_services.ts @@ -59,11 +59,7 @@ export const [getUrlTracker, setUrlTracker] = createGetterSetter<{ export const getHistory = _.once(() => createHashHistory()); export const { getRequestInspectorStats, getResponseInspectorStats, tabifyAggResponse } = search; -export { - unhashUrl, - redirectWhenMissing, - ensureDefaultIndexPattern, -} from '../../../../../plugins/kibana_utils/public'; +export { unhashUrl, redirectWhenMissing } from '../../../../../plugins/kibana_utils/public'; export { formatMsg, formatStack, diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/discover.js b/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/discover.js index 567cfda45cc0d..c1de704d1c00a 100644 --- a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/discover.js +++ b/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/discover.js @@ -49,7 +49,6 @@ import { subscribeWithScope, tabifyAggResponse, getAngularModule, - ensureDefaultIndexPattern, redirectWhenMissing, } from '../../kibana_services'; @@ -118,7 +117,7 @@ app.config($routeProvider => { savedObjects: function($route, Promise) { const history = getHistory(); const savedSearchId = $route.current.params.id; - return ensureDefaultIndexPattern(core, data, history).then(() => { + return data.indexPatterns.ensureDefaultIndexPattern(history).then(() => { const { appStateContainer } = getState({ history }); const { index } = appStateContainer.getState(); return Promise.props({ diff --git a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/__snapshots__/create_index_pattern_wizard.test.tsx.snap b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/__snapshots__/create_index_pattern_wizard.test.tsx.snap index 09a06bd8827ce..ed65db10e0acb 100644 --- a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/__snapshots__/create_index_pattern_wizard.test.tsx.snap +++ b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/__snapshots__/create_index_pattern_wizard.test.tsx.snap @@ -149,6 +149,7 @@ exports[`CreateIndexPatternWizard renders time field step when step is set to 2 indexPatternsService={ Object { "clearCache": [MockFunction], + "ensureDefaultIndexPattern": [MockFunction], "get": [MockFunction], "make": [Function], } diff --git a/src/plugins/dashboard/public/application/legacy_app.js b/src/plugins/dashboard/public/application/legacy_app.js index 10243dbf2f979..31225530b10b9 100644 --- a/src/plugins/dashboard/public/application/legacy_app.js +++ b/src/plugins/dashboard/public/application/legacy_app.js @@ -28,7 +28,6 @@ import { initDashboardAppDirective } from './dashboard_app'; import { createDashboardEditUrl, DashboardConstants } from '../dashboard_constants'; import { createKbnUrlStateStorage, - ensureDefaultIndexPattern, redirectWhenMissing, InvalidJSONProperty, SavedObjectNotFound, @@ -138,7 +137,7 @@ export function initDashboardApp(app, deps) { }, resolve: { dash: function($route, history) { - return ensureDefaultIndexPattern(deps.core, deps.data, history).then(() => { + return deps.data.indexPatterns.ensureDefaultIndexPattern(history).then(() => { const savedObjectsClient = deps.savedObjectsClient; const title = $route.current.params.title; if (title) { @@ -173,7 +172,8 @@ export function initDashboardApp(app, deps) { requireUICapability: 'dashboard.createNew', resolve: { dash: history => - ensureDefaultIndexPattern(deps.core, deps.data, history) + deps.data.indexPatterns + .ensureDefaultIndexPattern(history) .then(() => deps.savedDashboards.get()) .catch( redirectWhenMissing({ @@ -194,7 +194,8 @@ export function initDashboardApp(app, deps) { dash: function($route, history) { const id = $route.current.params.id; - return ensureDefaultIndexPattern(deps.core, deps.data, history) + return deps.data.indexPatterns + .ensureDefaultIndexPattern(history) .then(() => deps.savedDashboards.get(id)) .then(savedDashboard => { deps.chrome.recentlyAccessed.add( diff --git a/src/plugins/data/public/index_patterns/index_patterns/ensure_default_index_pattern.tsx b/src/plugins/data/public/index_patterns/index_patterns/ensure_default_index_pattern.tsx new file mode 100644 index 0000000000000..6b71739862f62 --- /dev/null +++ b/src/plugins/data/public/index_patterns/index_patterns/ensure_default_index_pattern.tsx @@ -0,0 +1,98 @@ +/* + * 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 { contains } from 'lodash'; +import React from 'react'; +import { History } from 'history'; +import { i18n } from '@kbn/i18n'; +import { EuiCallOut } from '@elastic/eui'; +import { CoreStart } from 'kibana/public'; +import { toMountPoint } from '../../../../kibana_react/public'; +import { IndexPatternsContract } from './index_patterns'; + +export type EnsureDefaultIndexPattern = (history: History) => Promise | undefined; + +export const createEnsureDefaultIndexPattern = (core: CoreStart) => { + let bannerId: string; + let timeoutId: NodeJS.Timeout | undefined; + + /** + * Checks whether a default index pattern is set and exists and defines + * one otherwise. + * + * If there are no index patterns, redirect to management page and show + * banner. In this case the promise returned from this function will never + * resolve to wait for the URL change to happen. + */ + return async function ensureDefaultIndexPattern(this: IndexPatternsContract, history: History) { + const patterns = await this.getIds(); + let defaultId = core.uiSettings.get('defaultIndex'); + let defined = !!defaultId; + const exists = contains(patterns, defaultId); + + if (defined && !exists) { + core.uiSettings.remove('defaultIndex'); + defaultId = defined = false; + } + + if (defined) { + return; + } + + // If there is any index pattern created, set the first as default + if (patterns.length >= 1) { + defaultId = patterns[0]; + core.uiSettings.set('defaultIndex', defaultId); + } else { + const canManageIndexPatterns = core.application.capabilities.management.kibana.index_patterns; + const redirectTarget = canManageIndexPatterns ? '/management/kibana/index_pattern' : '/home'; + + if (timeoutId) { + clearTimeout(timeoutId); + } + + // Avoid being hostile to new users who don't have an index pattern setup yet + // give them a friendly info message instead of a terse error message + bannerId = core.overlays.banners.replace( + bannerId, + toMountPoint( + + ) + ); + + // hide the message after the user has had a chance to acknowledge it -- so it doesn't permanently stick around + timeoutId = setTimeout(() => { + core.overlays.banners.remove(bannerId); + timeoutId = undefined; + }, 15000); + + history.push(redirectTarget); + + // return never-resolving promise to stop resolving and wait for the url change + return new Promise(() => {}); + } + }; +}; diff --git a/src/plugins/data/public/index_patterns/index_patterns/index_patterns.test.ts b/src/plugins/data/public/index_patterns/index_patterns/index_patterns.test.ts index c429431b632bd..cf1f83d0e28cb 100644 --- a/src/plugins/data/public/index_patterns/index_patterns/index_patterns.test.ts +++ b/src/plugins/data/public/index_patterns/index_patterns/index_patterns.test.ts @@ -21,9 +21,9 @@ import { IndexPatternsService } from './index_patterns'; import { SavedObjectsClientContract, - IUiSettingsClient, HttpSetup, SavedObjectsFindResponsePublic, + CoreStart, } from 'kibana/public'; jest.mock('./index_pattern', () => { @@ -61,10 +61,10 @@ describe('IndexPatterns', () => { }) as Promise> ); - const uiSettings = {} as IUiSettingsClient; + const core = {} as CoreStart; const http = {} as HttpSetup; - indexPatterns = new IndexPatternsService(uiSettings, savedObjectsClient, http); + indexPatterns = new IndexPatternsService(core, savedObjectsClient, http); }); test('does cache gets for the same id', async () => { diff --git a/src/plugins/data/public/index_patterns/index_patterns/index_patterns.ts b/src/plugins/data/public/index_patterns/index_patterns/index_patterns.ts index acce5ed57683c..b5d66a6aab60a 100644 --- a/src/plugins/data/public/index_patterns/index_patterns/index_patterns.ts +++ b/src/plugins/data/public/index_patterns/index_patterns/index_patterns.ts @@ -22,11 +22,16 @@ import { SimpleSavedObject, IUiSettingsClient, HttpStart, + CoreStart, } from 'src/core/public'; import { createIndexPatternCache } from './_pattern_cache'; import { IndexPattern } from './index_pattern'; import { IndexPatternsApiClient, GetFieldsOptions } from './index_patterns_api_client'; +import { + createEnsureDefaultIndexPattern, + EnsureDefaultIndexPattern, +} from './ensure_default_index_pattern'; const indexPatternCache = createIndexPatternCache(); @@ -37,15 +42,13 @@ export class IndexPatternsService { private savedObjectsClient: SavedObjectsClientContract; private savedObjectsCache?: Array>> | null; private apiClient: IndexPatternsApiClient; + ensureDefaultIndexPattern: EnsureDefaultIndexPattern; - constructor( - config: IUiSettingsClient, - savedObjectsClient: SavedObjectsClientContract, - http: HttpStart - ) { + constructor(core: CoreStart, savedObjectsClient: SavedObjectsClientContract, http: HttpStart) { this.apiClient = new IndexPatternsApiClient(http); - this.config = config; + this.config = core.uiSettings; this.savedObjectsClient = savedObjectsClient; + this.ensureDefaultIndexPattern = createEnsureDefaultIndexPattern(core); } private async refreshSavedObjectsCache() { diff --git a/src/plugins/data/public/mocks.ts b/src/plugins/data/public/mocks.ts index a2df754786a68..ba1df89c41358 100644 --- a/src/plugins/data/public/mocks.ts +++ b/src/plugins/data/public/mocks.ts @@ -57,6 +57,7 @@ const createStartContract = (): Start => { SearchBar: jest.fn(), }, indexPatterns: ({ + ensureDefaultIndexPattern: jest.fn(), make: () => ({ fieldsFetcher: { fetchForWildcard: jest.fn(), diff --git a/src/plugins/data/public/plugin.ts b/src/plugins/data/public/plugin.ts index 924fcd6730f93..f3a88287313a0 100644 --- a/src/plugins/data/public/plugin.ts +++ b/src/plugins/data/public/plugin.ts @@ -160,7 +160,7 @@ export class DataPublicPlugin implements Plugin= 1) { - defaultId = patterns[0]; - core.uiSettings.set('defaultIndex', defaultId); - } else { - const canManageIndexPatterns = core.application.capabilities.management.kibana.index_patterns; - const redirectTarget = canManageIndexPatterns ? '/management/kibana/index_pattern' : '/home'; - - if (timeoutId) { - clearTimeout(timeoutId); - } - - // Avoid being hostile to new users who don't have an index pattern setup yet - // give them a friendly info message instead of a terse error message - bannerId = core.overlays.banners.replace( - bannerId, - toMountPoint( - - ) - ); - - // hide the message after the user has had a chance to acknowledge it -- so it doesn't permanently stick around - timeoutId = setTimeout(() => { - core.overlays.banners.remove(bannerId); - timeoutId = undefined; - }, 15000); - - history.push(redirectTarget); - - // return never-resolving promise to stop resolving and wait for the url change - return new Promise(() => {}); - } -} diff --git a/src/plugins/kibana_utils/public/history/index.ts b/src/plugins/kibana_utils/public/history/index.ts index 1a73bbb6b04a1..bb13ea09f928a 100644 --- a/src/plugins/kibana_utils/public/history/index.ts +++ b/src/plugins/kibana_utils/public/history/index.ts @@ -19,4 +19,3 @@ export { removeQueryParam } from './remove_query_param'; export { redirectWhenMissing } from './redirect_when_missing'; -export { ensureDefaultIndexPattern } from './ensure_default_index_pattern'; diff --git a/src/plugins/kibana_utils/public/index.ts b/src/plugins/kibana_utils/public/index.ts index 2f139050e994a..c634322b23d0b 100644 --- a/src/plugins/kibana_utils/public/index.ts +++ b/src/plugins/kibana_utils/public/index.ts @@ -74,7 +74,7 @@ export { StartSyncStateFnType, StopSyncStateFnType, } from './state_sync'; -export { removeQueryParam, redirectWhenMissing, ensureDefaultIndexPattern } from './history'; +export { removeQueryParam, redirectWhenMissing } from './history'; export { applyDiff } from './state_management/utils/diff_object'; /** dummy plugin, we just want kibanaUtils to have its own bundle */ diff --git a/src/plugins/saved_objects_management/public/management_section/objects_table/__snapshots__/saved_objects_table.test.tsx.snap b/src/plugins/saved_objects_management/public/management_section/objects_table/__snapshots__/saved_objects_table.test.tsx.snap index 563ce87b82ae5..fb3d6efa63826 100644 --- a/src/plugins/saved_objects_management/public/management_section/objects_table/__snapshots__/saved_objects_table.test.tsx.snap +++ b/src/plugins/saved_objects_management/public/management_section/objects_table/__snapshots__/saved_objects_table.test.tsx.snap @@ -238,6 +238,7 @@ exports[`SavedObjectsTable import should show the flyout 1`] = ` indexPatterns={ Object { "clearCache": [MockFunction], + "ensureDefaultIndexPattern": [MockFunction], "get": [MockFunction], "make": [Function], } diff --git a/src/plugins/visualize/public/application/legacy_app.js b/src/plugins/visualize/public/application/legacy_app.js index 7c5e3ce9408f0..c7cc11c1f3ff5 100644 --- a/src/plugins/visualize/public/application/legacy_app.js +++ b/src/plugins/visualize/public/application/legacy_app.js @@ -21,11 +21,7 @@ import { find } from 'lodash'; import { i18n } from '@kbn/i18n'; import { createHashHistory } from 'history'; -import { - createKbnUrlStateStorage, - redirectWhenMissing, - ensureDefaultIndexPattern, -} from '../../../kibana_utils/public'; +import { createKbnUrlStateStorage, redirectWhenMissing } from '../../../kibana_utils/public'; import { createSavedSearchesLoader } from '../../../discover/public'; import editorTemplate from './editor/editor.html'; @@ -127,7 +123,7 @@ export function initVisualizeApp(app, deps) { controllerAs: 'listingController', resolve: { createNewVis: () => false, - hasDefaultIndex: history => ensureDefaultIndexPattern(deps.core, deps.data, history), + hasDefaultIndex: history => deps.data.indexPatterns.ensureDefaultIndexPattern(history), }, }) .when(VisualizeConstants.WIZARD_STEP_1_PAGE_PATH, { @@ -138,7 +134,7 @@ export function initVisualizeApp(app, deps) { controllerAs: 'listingController', resolve: { createNewVis: () => true, - hasDefaultIndex: history => ensureDefaultIndexPattern(deps.core, deps.data, history), + hasDefaultIndex: history => deps.data.indexPatterns.ensureDefaultIndexPattern(history), }, }) .when(VisualizeConstants.CREATE_PATH, { @@ -147,7 +143,7 @@ export function initVisualizeApp(app, deps) { k7Breadcrumbs: getCreateBreadcrumbs, resolve: { resolved: function($route, history) { - const { core, data, savedVisualizations, visualizations, toastNotifications } = deps; + const { data, savedVisualizations, visualizations, toastNotifications } = deps; const visTypes = visualizations.all(); const visType = find(visTypes, { name: $route.current.params.type }); const shouldHaveIndex = visType.requiresSearch && visType.options.showIndexSelection; @@ -164,7 +160,8 @@ export function initVisualizeApp(app, deps) { ); } - return ensureDefaultIndexPattern(core, data, history) + return data.indexPatterns + .ensureDefaultIndexPattern(history) .then(() => savedVisualizations.get($route.current.params)) .then(getResolvedResults(deps)) .catch( @@ -183,9 +180,10 @@ export function initVisualizeApp(app, deps) { k7Breadcrumbs: getEditBreadcrumbs, resolve: { resolved: function($route, history) { - const { chrome, core, data, savedVisualizations, toastNotifications } = deps; + const { chrome, data, savedVisualizations, toastNotifications } = deps; - return ensureDefaultIndexPattern(core, data, history) + return data.indexPatterns + .ensureDefaultIndexPattern(history) .then(() => savedVisualizations.get($route.current.params.id)) .then(savedVis => { chrome.recentlyAccessed.add(savedVis.getFullPath(), savedVis.title, savedVis.id); diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index deb3053d28658..197e104350d50 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -671,6 +671,7 @@ "data.functions.esaggs.inspector.dataRequest.description": "このリクエストは Elasticsearch にクエリし、ビジュアライゼーション用のデータを取得します。", "data.functions.esaggs.inspector.dataRequest.title": "データ", "data.indexPatterns.fetchFieldErrorTitle": "インデックスパターンのフィールド取得中にエラーが発生 {title} (ID: {id})", + "data.indexPatterns.ensureDefaultIndexPattern.bannerLabel": "Kibanaでデータの可視化と閲覧を行うには、Elasticsearchからデータを取得するためのインデックスパターンの作成が必要です。", "data.indexPatterns.unableWriteLabel": "インデックスパターンを書き込めません!このインデックスパターンへの最新の変更を取得するには、ページを更新してください。", "data.indexPatterns.unknownFieldErrorMessage": "インデックスパターン「{title}」のフィールド「{name}」が不明なフィールドタイプを使用しています。", "data.indexPatterns.unknownFieldHeader": "不明なフィールドタイプ {type}", @@ -2431,7 +2432,6 @@ "kibana_legacy.paginate.size.allDropDownOptionLabel": "すべて", "kibana_utils.defaultFeedbackMessage": "フィードバックがありますか?{link} で問題を報告してください。", "kibana_utils.history.savedObjectIsMissingNotificationMessage": "保存されたオブジェクトがありません", - "kibana_utils.indexPattern.bannerLabel": "Kibanaでデータの可視化と閲覧を行うには、Elasticsearchからデータを取得するためのインデックスパターンの作成が必要です。", "kibana_utils.stateManagement.stateHash.unableToRestoreUrlErrorMessage": "URL を完全に復元できません。共有機能を使用していることを確認してください。", "kibana_utils.stateManagement.stateHash.unableToStoreHistoryInSessionErrorMessage": "セッションがいっぱいで安全に削除できるアイテムが見つからないため、Kibana は履歴アイテムを保存できません。\n\nこれは大抵新規タブに移動することで解決されますが、より大きな問題が原因である可能性もあります。このメッセージが定期的に表示される場合は、{gitHubIssuesUrl} で問題を報告してください。", "kibana-react.dualRangeControl.mustSetBothErrorMessage": "下と上の値の両方を設定する必要があります", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 3b757f169828c..8acee453e899e 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -671,6 +671,7 @@ "data.functions.esaggs.inspector.dataRequest.description": "此请求将查询 Elasticsearch 以获取用于可视化的数据。", "data.functions.esaggs.inspector.dataRequest.title": "数据", "data.indexPatterns.fetchFieldErrorTitle": "提取索引模式 {title} (ID: {id}) 的字段时出错", + "data.indexPatterns.ensureDefaultIndexPattern.bannerLabel": "若要在 Kibana 中可视化和浏览数据,您需要创建索引模式,以从 Elasticsearch 检索数据。", "data.indexPatterns.unableWriteLabel": "无法写入索引模式!请刷新页面以获取此索引模式的最新更改。", "data.indexPatterns.unknownFieldErrorMessage": "indexPattern “{title}” 中的字段 “{name}” 使用未知字段类型。", "data.indexPatterns.unknownFieldHeader": "未知字段类型 {type}", @@ -2432,7 +2433,6 @@ "kibana_legacy.paginate.size.allDropDownOptionLabel": "全部", "kibana_utils.defaultFeedbackMessage": "想反馈?请在 {link} 中创建问题。", "kibana_utils.history.savedObjectIsMissingNotificationMessage": "已保存对象缺失", - "kibana_utils.indexPattern.bannerLabel": "若要在 Kibana 中可视化和浏览数据,您需要创建索引模式,以从 Elasticsearch 检索数据。", "kibana_utils.stateManagement.stateHash.unableToRestoreUrlErrorMessage": "无法完全还原 URL,请确保使用共享功能。", "kibana_utils.stateManagement.stateHash.unableToStoreHistoryInSessionErrorMessage": "Kibana 无法将历史记录项存储在您的会话中,因为其已满,另外,似乎没有任何可安全删除的项目。\n\n通常,这可以通过移到全新的选项卡来解决,但这种情况可能是由更大的问题造成。如果您定期看到这个消息,请在 {gitHubIssuesUrl} 报告问题。", "kibana-react.dualRangeControl.mustSetBothErrorMessage": "下限值和上限值都须设置",