diff --git a/src/core_plugins/kibana/index.js b/src/core_plugins/kibana/index.js
index 9c8ed813cd84d..c7a44ac2b04bd 100644
--- a/src/core_plugins/kibana/index.js
+++ b/src/core_plugins/kibana/index.js
@@ -30,6 +30,7 @@ import { managementApi } from './server/routes/api/management';
import { scriptsApi } from './server/routes/api/scripts';
import { registerSuggestionsApi } from './server/routes/api/suggestions';
import { registerKqlTelemetryApi } from './server/routes/api/kql_telemetry';
+import { registerClustersRoute } from './server/routes/api/remote_info';
import { registerFieldFormats } from './server/field_formats/register';
import { registerTutorials } from './server/tutorials/register';
import * as systemApi from './server/lib/system_api';
@@ -167,6 +168,7 @@ export default function (kibana) {
registerFieldFormats(server);
registerTutorials(server);
makeKQLUsageCollector(server);
+ registerClustersRoute(server);
server.expose('systemApi', systemApi);
server.expose('handleEsError', handleEsError);
server.injectUiAppVars('kibana', () => injectVars(server));
diff --git a/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/__jest__/__snapshots__/create_index_pattern_wizard.test.js.snap b/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/__jest__/__snapshots__/create_index_pattern_wizard.test.js.snap
index d7378e58d42bf..8c7018bf35f6e 100644
--- a/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/__jest__/__snapshots__/create_index_pattern_wizard.test.js.snap
+++ b/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/__jest__/__snapshots__/create_index_pattern_wizard.test.js.snap
@@ -1,132 +1,205 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`CreateIndexPatternWizard defaults to the loading state 1`] = `
-
+
`;
exports[`CreateIndexPatternWizard renders index pattern step when there are indices 1`] = `
-
+
`;
exports[`CreateIndexPatternWizard renders the empty state when there are no indices 1`] = `
-
+
`;
exports[`CreateIndexPatternWizard renders time field step when step is set to 2 1`] = `
-
-
+
+
+
+
+
-
+`;
+
+exports[`CreateIndexPatternWizard renders when there are no indices but there are remote clusters 1`] = `
+
+
+
+
+
+
-
+
`;
exports[`CreateIndexPatternWizard shows system indices even if there are no other indices if the include system indices is toggled 1`] = `
-
+
`;
diff --git a/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/__jest__/create_index_pattern_wizard.test.js b/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/__jest__/create_index_pattern_wizard.test.js
index d8ca11f04ae80..e95a5c7fa8448 100644
--- a/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/__jest__/create_index_pattern_wizard.test.js
+++ b/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/__jest__/create_index_pattern_wizard.test.js
@@ -42,6 +42,9 @@ jest.mock('../lib/get_indices', () => ({
];
},
}));
+jest.mock('ui/chrome', () => ({
+ addBasePath: () => { },
+}));
const loadingDataDocUrl = '';
const initialQuery = '';
@@ -80,6 +83,26 @@ describe('CreateIndexPatternWizard', () => {
component.setState({
isInitiallyLoadingIndices: false,
allIndices: [],
+ remoteClustersExist: false
+ });
+
+ await component.update();
+ expect(component).toMatchSnapshot();
+ });
+
+ it('renders when there are no indices but there are remote clusters', async () => {
+ const component = shallow(
+
+ );
+
+ component.setState({
+ isInitiallyLoadingIndices: false,
+ allIndices: [],
+ remoteClustersExist: true
});
await component.update();
diff --git a/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/__jest__/render.test.js b/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/__jest__/render.test.js
index 7c499401bf2fd..dd9ac07c5199e 100644
--- a/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/__jest__/render.test.js
+++ b/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/__jest__/render.test.js
@@ -32,6 +32,7 @@ jest.mock('ui/chrome', () => ({
getUiSettingsClient: () => ({
get: () => '',
}),
+ addBasePath: () => { },
}));
const { renderCreateIndexPatternWizard, destroyCreateIndexPatternWizard } = require('../render');
diff --git a/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/components/step_index_pattern/__jest__/step_index_pattern.test.js b/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/components/step_index_pattern/__jest__/step_index_pattern.test.js
index 89abe1121e706..6c7deefcc0a45 100644
--- a/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/components/step_index_pattern/__jest__/step_index_pattern.test.js
+++ b/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/components/step_index_pattern/__jest__/step_index_pattern.test.js
@@ -41,6 +41,7 @@ jest.mock('ui/chrome', () => ({
getUiSettingsClient: () => ({
get: () => '',
}),
+ addBasePath: () => { },
}));
jest.mock('../../../lib/get_indices', () => ({
@@ -62,7 +63,7 @@ const esService = {};
const savedObjectsClient = {
find: () => ({ savedObjects: [] })
};
-const goToNextStep = () => {};
+const goToNextStep = () => { };
const createComponent = props => {
return shallowWithIntl(
diff --git a/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/components/step_time_field/__jest__/step_time_field.test.js b/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/components/step_time_field/__jest__/step_time_field.test.js
index a2448c2fc11fe..f066a36c24a02 100644
--- a/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/components/step_time_field/__jest__/step_time_field.test.js
+++ b/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/components/step_time_field/__jest__/step_time_field.test.js
@@ -29,6 +29,9 @@ jest.mock('../components/action_buttons', () => ({ ActionButtons: 'ActionButtons
jest.mock('../../../lib/extract_time_fields', () => ({
extractTimeFields: fields => fields,
}));
+jest.mock('ui/chrome', () => ({
+ addBasePath: () => { },
+}));
const mockIndexPatternCreationType = {
getIndexPatternType: () => 'default',
diff --git a/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/create_index_pattern_wizard.js b/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/create_index_pattern_wizard.js
index dc0568b85e00e..e48551a335aaf 100644
--- a/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/create_index_pattern_wizard.js
+++ b/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/create_index_pattern_wizard.js
@@ -20,6 +20,11 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
+import {
+ EuiGlobalToastList
+} from '@elastic/eui';
+import { FormattedMessage } from '@kbn/i18n/react';
+
import { StepIndexPattern } from './components/step_index_pattern';
import { StepTimeField } from './components/step_time_field';
import { Header } from './components/header';
@@ -30,6 +35,7 @@ import { MAX_SEARCH_SIZE } from './constants';
import {
ensureMinimumTime,
getIndices,
+ getRemoteClusters
} from './lib';
export class CreateIndexPatternWizard extends Component {
@@ -52,20 +58,62 @@ export class CreateIndexPatternWizard extends Component {
step: 1,
indexPattern: '',
allIndices: [],
+ remoteClustersExist: false,
isInitiallyLoadingIndices: true,
isIncludingSystemIndices: false,
+ toasts: []
};
}
async componentWillMount() {
- this.fetchIndices();
+ this.fetchData();
}
- fetchIndices = async () => {
- this.setState({ allIndices: [], isInitiallyLoadingIndices: true });
+ catchAndWarn = async (asyncFn, errorValue, errorMsg) => {
+ try {
+ return await asyncFn;
+ } catch (errors) {
+ this.setState(prevState => ({
+ toasts: prevState.toasts.concat([{
+ title: errorMsg,
+ id: errorMsg,
+ color: 'warning',
+ iconType: 'alert',
+ }])
+ }));
+ return errorValue;
+ }
+ };
+
+ fetchData = async () => {
const { services } = this.props;
- const allIndices = await ensureMinimumTime(getIndices(services.es, this.indexPatternCreationType, `*`, MAX_SEARCH_SIZE)); //
- this.setState({ allIndices, isInitiallyLoadingIndices: false });
+
+ this.setState({
+ allIndices: [],
+ isInitiallyLoadingIndices: true,
+ remoteClustersExist: false
+ });
+
+ const indicesFailMsg = ();
+
+ const clustersFailMsg = ();
+
+ const [allIndices, remoteClusters] = await ensureMinimumTime([
+ this.catchAndWarn(getIndices(services.es, this.indexPatternCreationType, `*`, MAX_SEARCH_SIZE), [], indicesFailMsg),
+ this.catchAndWarn(getRemoteClusters(services.$http), [], clustersFailMsg)
+ ]);
+
+ this.setState({
+ allIndices,
+ isInitiallyLoadingIndices: false,
+ remoteClustersExist: remoteClusters.length !== 0
+ });
}
createIndexPattern = async (timeFieldName, indexPatternId) => {
@@ -127,6 +175,7 @@ export class CreateIndexPatternWizard extends Component {
isIncludingSystemIndices,
step,
indexPattern,
+ remoteClustersExist
} = this.state;
if (isInitiallyLoadingIndices) {
@@ -134,8 +183,10 @@ export class CreateIndexPatternWizard extends Component {
}
const hasDataIndices = allIndices.some(({ name }) => !name.startsWith('.'));
- if (!hasDataIndices && !isIncludingSystemIndices) {
- return ;
+ if (!hasDataIndices &&
+ !isIncludingSystemIndices &&
+ !remoteClustersExist) {
+ return ;
}
if (step === 1) {
@@ -169,15 +220,28 @@ export class CreateIndexPatternWizard extends Component {
return null;
}
+ removeToast = (removedToast) => {
+ this.setState(prevState => ({
+ toasts: prevState.toasts.filter(toast => toast.id !== removedToast.id),
+ }));
+ };
+
render() {
const header = this.renderHeader();
const content = this.renderContent();
return (
-
- {header}
- {content}
-
+
+
+ {header}
+ {content}
+
+
+
);
}
}
diff --git a/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/index.js b/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/index.js
index 2db685ba85169..0fc80ee769b52 100644
--- a/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/index.js
+++ b/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/index.js
@@ -39,6 +39,7 @@ uiRoutes.when('/management/kibana/index', {
config: $injector.get('config'),
es: $injector.get('es'),
indexPatterns: $injector.get('indexPatterns'),
+ $http: $injector.get('$http'),
savedObjectsClient: Private(SavedObjectsClientProvider),
indexPatternCreationType,
changeUrl: url => {
diff --git a/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/lib/get_remote_clusters.js b/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/lib/get_remote_clusters.js
new file mode 100644
index 0000000000000..f1cbd48ac1116
--- /dev/null
+++ b/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/lib/get_remote_clusters.js
@@ -0,0 +1,26 @@
+/*
+ * 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 chrome from 'ui/chrome';
+const apiPrefix = chrome.addBasePath('/api/kibana');
+
+export async function getRemoteClusters($http) {
+ const response = await $http.get(`${apiPrefix}/clusters`);
+ return response.data;
+}
diff --git a/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/lib/index.js b/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/lib/index.js
index 0930eb82514e1..edbab7360b433 100644
--- a/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/lib/index.js
+++ b/src/core_plugins/kibana/public/management/sections/indices/create_index_pattern_wizard/lib/index.js
@@ -28,3 +28,5 @@ export { getMatchedIndices } from './get_matched_indices';
export { containsIllegalCharacters } from './contains_illegal_characters';
export { extractTimeFields } from './extract_time_fields';
+
+export { getRemoteClusters } from './get_remote_clusters';
diff --git a/src/core_plugins/kibana/server/routes/api/remote_info/call_with_request_factory.js b/src/core_plugins/kibana/server/routes/api/remote_info/call_with_request_factory.js
new file mode 100644
index 0000000000000..dc70072ffd285
--- /dev/null
+++ b/src/core_plugins/kibana/server/routes/api/remote_info/call_with_request_factory.js
@@ -0,0 +1,37 @@
+/*
+ * 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.
+ */
+
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import { once } from 'lodash';
+
+const callWithRequest = once(server => {
+ const cluster = server.plugins.elasticsearch.getCluster('data');
+ return cluster.callWithRequest;
+});
+
+export const callWithRequestFactory = (server, request) => {
+ return (...args) => {
+ return callWithRequest(server)(request, ...args);
+ };
+};
diff --git a/src/core_plugins/kibana/server/routes/api/remote_info/index.js b/src/core_plugins/kibana/server/routes/api/remote_info/index.js
new file mode 100644
index 0000000000000..2d1e57d432550
--- /dev/null
+++ b/src/core_plugins/kibana/server/routes/api/remote_info/index.js
@@ -0,0 +1,51 @@
+/*
+ * 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.
+ */
+
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import { callWithRequestFactory } from './call_with_request_factory';
+import handleEsError from '../../../lib/handle_es_error';
+
+async function fetchRemoteClusters(callWithRequest) {
+ const options = {
+ method: 'GET',
+ path: '_remote/info'
+ };
+ const remoteInfo = await callWithRequest('transport.request', options);
+ return Object.keys(remoteInfo);
+}
+
+export function registerClustersRoute(server) {
+ server.route({
+ path: '/api/kibana/clusters',
+ method: 'GET',
+ handler: async request => {
+ const callWithRequest = callWithRequestFactory(server, request);
+ try {
+ return await fetchRemoteClusters(callWithRequest);
+ } catch (error) {
+ throw handleEsError(error);
+ }
+ }
+ });
+}
diff --git a/x-pack/plugins/index_management/server/routes/api/indices/register_list_route.js b/x-pack/plugins/index_management/server/routes/api/indices/register_list_route.js
index cfa93c66f0a7c..fefb5fc91a843 100644
--- a/x-pack/plugins/index_management/server/routes/api/indices/register_list_route.js
+++ b/x-pack/plugins/index_management/server/routes/api/indices/register_list_route.js
@@ -7,7 +7,7 @@
import { callWithRequestFactory } from '../../../lib/call_with_request_factory';
import { isEsErrorFactory } from '../../../lib/is_es_error_factory';
import { wrapEsError, wrapUnknownError } from '../../../lib/error_wrappers';
-import { licensePreRoutingFactory } from'../../../lib/license_pre_routing_factory';
+import { licensePreRoutingFactory } from '../../../lib/license_pre_routing_factory';
import { fetchAliases } from './fetch_aliases';
function formatHits(hits, aliases) {
@@ -60,7 +60,7 @@ export function registerListRoute(server) {
}
},
config: {
- pre: [ licensePreRouting ]
+ pre: [licensePreRouting]
}
});
}