diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/empty_states/empty_states.scss b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/empty_state.scss
similarity index 100%
rename from x-pack/plugins/enterprise_search/public/applications/app_search/components/empty_states/empty_states.scss
rename to x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/empty_state.scss
diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/empty_states/empty_states.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/empty_state.test.tsx
similarity index 55%
rename from x-pack/plugins/enterprise_search/public/applications/app_search/components/empty_states/empty_states.test.tsx
rename to x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/empty_state.test.tsx
index 25a9fa7430c40..7e6876bc9b3a4 100644
--- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/empty_states/empty_states.test.tsx
+++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/empty_state.test.tsx
@@ -4,28 +4,19 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import '../../../__mocks__/shallow_usecontext.mock';
+import '../../../../__mocks__/shallow_usecontext.mock';
import React from 'react';
import { shallow } from 'enzyme';
-import { EuiEmptyPrompt, EuiButton, EuiLoadingContent } from '@elastic/eui';
-import { ErrorStatePrompt } from '../../../shared/error_state';
+import { EuiEmptyPrompt, EuiButton } from '@elastic/eui';
-jest.mock('../../../shared/telemetry', () => ({
+jest.mock('../../../../shared/telemetry', () => ({
sendTelemetry: jest.fn(),
SendAppSearchTelemetry: jest.fn(),
}));
-import { sendTelemetry } from '../../../shared/telemetry';
+import { sendTelemetry } from '../../../../shared/telemetry';
-import { ErrorState, EmptyState, LoadingState } from './';
-
-describe('ErrorState', () => {
- it('renders', () => {
- const wrapper = shallow();
-
- expect(wrapper.find(ErrorStatePrompt)).toHaveLength(1);
- });
-});
+import { EmptyState } from './';
describe('EmptyState', () => {
it('renders', () => {
@@ -44,11 +35,3 @@ describe('EmptyState', () => {
(sendTelemetry as jest.Mock).mockClear();
});
});
-
-describe('LoadingState', () => {
- it('renders', () => {
- const wrapper = shallow();
-
- expect(wrapper.find(EuiLoadingContent)).toHaveLength(2);
- });
-});
diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/empty_states/empty_state.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/empty_state.tsx
similarity index 84%
rename from x-pack/plugins/enterprise_search/public/applications/app_search/components/empty_states/empty_state.tsx
rename to x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/empty_state.tsx
index 9b0edb423bc52..58691cf09b4a5 100644
--- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/empty_states/empty_state.tsx
+++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/empty_state.tsx
@@ -8,14 +8,14 @@ import React, { useContext } from 'react';
import { EuiPageContent, EuiEmptyPrompt, EuiButton } from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n/react';
-import { sendTelemetry } from '../../../shared/telemetry';
-import { SetAppSearchChrome as SetPageChrome } from '../../../shared/kibana_chrome';
-import { KibanaContext, IKibanaContext } from '../../../index';
-import { CREATE_ENGINES_PATH } from '../../routes';
+import { sendTelemetry } from '../../../../shared/telemetry';
+import { SetAppSearchChrome as SetPageChrome } from '../../../../shared/kibana_chrome';
+import { KibanaContext, IKibanaContext } from '../../../../index';
+import { CREATE_ENGINES_PATH } from '../../../routes';
-import { EngineOverviewHeader } from '../engine_overview_header';
+import { EngineOverviewHeader } from './header';
-import './empty_states.scss';
+import './empty_state.scss';
export const EmptyState: React.FC = () => {
const {
diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview_header/engine_overview_header.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/header.test.tsx
similarity index 77%
rename from x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview_header/engine_overview_header.test.tsx
rename to x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/header.test.tsx
index 7d2106f2a56f7..7f22ce132d405 100644
--- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview_header/engine_overview_header.test.tsx
+++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/header.test.tsx
@@ -4,15 +4,15 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import '../../../__mocks__/shallow_usecontext.mock';
+import '../../../../__mocks__/shallow_usecontext.mock';
import React from 'react';
import { shallow } from 'enzyme';
-jest.mock('../../../shared/telemetry', () => ({ sendTelemetry: jest.fn() }));
-import { sendTelemetry } from '../../../shared/telemetry';
+jest.mock('../../../../shared/telemetry', () => ({ sendTelemetry: jest.fn() }));
+import { sendTelemetry } from '../../../../shared/telemetry';
-import { EngineOverviewHeader } from '../engine_overview_header';
+import { EngineOverviewHeader } from './';
describe('EngineOverviewHeader', () => {
it('renders', () => {
diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview_header/engine_overview_header.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/header.tsx
similarity index 92%
rename from x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview_header/engine_overview_header.tsx
rename to x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/header.tsx
index 7f67d00f5df91..1a1ae295d4828 100644
--- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview_header/engine_overview_header.tsx
+++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/header.tsx
@@ -15,8 +15,8 @@ import {
} from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n/react';
-import { sendTelemetry } from '../../../shared/telemetry';
-import { KibanaContext, IKibanaContext } from '../../../index';
+import { sendTelemetry } from '../../../../shared/telemetry';
+import { KibanaContext, IKibanaContext } from '../../../../index';
export const EngineOverviewHeader: React.FC = () => {
const {
diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/empty_states/index.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/index.ts
similarity index 87%
rename from x-pack/plugins/enterprise_search/public/applications/app_search/components/empty_states/index.ts
rename to x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/index.ts
index e92bf214c4cc7..794053f184f8c 100644
--- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/empty_states/index.ts
+++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/index.ts
@@ -4,6 +4,6 @@
* you may not use this file except in compliance with the Elastic License.
*/
+export { EngineOverviewHeader } from './header';
export { LoadingState } from './loading_state';
export { EmptyState } from './empty_state';
-export { ErrorState } from './error_state';
diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/loading_state.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/loading_state.test.tsx
new file mode 100644
index 0000000000000..c894500550a0b
--- /dev/null
+++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/loading_state.test.tsx
@@ -0,0 +1,19 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import React from 'react';
+import { shallow } from 'enzyme';
+import { EuiLoadingContent } from '@elastic/eui';
+
+import { LoadingState } from './';
+
+describe('LoadingState', () => {
+ it('renders', () => {
+ const wrapper = shallow();
+
+ expect(wrapper.find(EuiLoadingContent)).toHaveLength(2);
+ });
+});
diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/empty_states/loading_state.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/loading_state.tsx
similarity index 73%
rename from x-pack/plugins/enterprise_search/public/applications/app_search/components/empty_states/loading_state.tsx
rename to x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/loading_state.tsx
index 221091b79dc54..07643560df3c7 100644
--- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/empty_states/loading_state.tsx
+++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/loading_state.tsx
@@ -7,17 +7,15 @@
import React from 'react';
import { EuiPageContent, EuiSpacer, EuiLoadingContent } from '@elastic/eui';
-import { SetAppSearchChrome as SetPageChrome } from '../../../shared/kibana_chrome';
-import { EngineOverviewHeader } from '../engine_overview_header';
-
-import './empty_states.scss';
+import { SetAppSearchChrome as SetPageChrome } from '../../../../shared/kibana_chrome';
+import { EngineOverviewHeader } from './header';
export const LoadingState: React.FC = () => {
return (
<>
-
+
diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/engine_overview.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/engine_overview.test.tsx
index 45ab5dc5b9ab1..c2379fb33bd71 100644
--- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/engine_overview.test.tsx
+++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/engine_overview.test.tsx
@@ -12,7 +12,7 @@ import { shallow, ReactWrapper } from 'enzyme';
import { mountWithAsyncContext, mockKibanaContext } from '../../../__mocks__';
-import { LoadingState, EmptyState, ErrorState } from '../empty_states';
+import { LoadingState, EmptyState } from './components';
import { EngineTable } from './engine_table';
import { EngineOverview } from './';
@@ -40,16 +40,6 @@ describe('EngineOverview', () => {
expect(wrapper.find(EmptyState)).toHaveLength(1);
});
-
- it('hasErrorConnecting', async () => {
- const wrapper = await mountWithAsyncContext(, {
- http: {
- ...mockHttp,
- get: () => ({ invalidPayload: true }),
- },
- });
- expect(wrapper.find(ErrorState)).toHaveLength(1);
- });
});
describe('happy-path states', () => {
diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/engine_overview.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/engine_overview.tsx
index acac5d17665b7..74bcd9aeafb28 100644
--- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/engine_overview.tsx
+++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/engine_overview.tsx
@@ -22,8 +22,7 @@ import { KibanaContext, IKibanaContext } from '../../../index';
import EnginesIcon from '../../assets/engine.svg';
import MetaEnginesIcon from '../../assets/meta_engine.svg';
-import { LoadingState, EmptyState, ErrorState } from '../empty_states';
-import { EngineOverviewHeader } from '../engine_overview_header';
+import { EngineOverviewHeader, LoadingState, EmptyState } from './components';
import { EngineTable } from './engine_table';
import './engine_overview.scss';
@@ -42,8 +41,6 @@ export const EngineOverview: React.FC = () => {
const { license } = useContext(LicenseContext) as ILicenseContext;
const [isLoading, setIsLoading] = useState(true);
- const [hasErrorConnecting, setHasErrorConnecting] = useState(false);
-
const [engines, setEngines] = useState([]);
const [enginesPage, setEnginesPage] = useState(1);
const [enginesTotal, setEnginesTotal] = useState(0);
@@ -57,16 +54,12 @@ export const EngineOverview: React.FC = () => {
});
};
const setEnginesData = async (params: IGetEnginesParams, callbacks: ISetEnginesCallbacks) => {
- try {
- const response = await getEnginesData(params);
+ const response = await getEnginesData(params);
- callbacks.setResults(response.results);
- callbacks.setResultsTotal(response.meta.page.total_results);
+ callbacks.setResults(response.results);
+ callbacks.setResultsTotal(response.meta.page.total_results);
- setIsLoading(false);
- } catch (error) {
- setHasErrorConnecting(true);
- }
+ setIsLoading(false);
};
useEffect(() => {
@@ -85,7 +78,6 @@ export const EngineOverview: React.FC = () => {
}
}, [license, metaEnginesPage]);
- if (hasErrorConnecting) return ;
if (isLoading) return ;
if (!engines.length) return ;
diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/error_connecting/error_connecting.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/error_connecting/error_connecting.test.tsx
new file mode 100644
index 0000000000000..8d48875a8e1f5
--- /dev/null
+++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/error_connecting/error_connecting.test.tsx
@@ -0,0 +1,19 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import React from 'react';
+import { shallow } from 'enzyme';
+
+import { ErrorStatePrompt } from '../../../shared/error_state';
+import { ErrorConnecting } from './';
+
+describe('ErrorConnecting', () => {
+ it('renders', () => {
+ const wrapper = shallow();
+
+ expect(wrapper.find(ErrorStatePrompt)).toHaveLength(1);
+ });
+});
diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/empty_states/error_state.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/error_connecting/error_connecting.tsx
similarity index 81%
rename from x-pack/plugins/enterprise_search/public/applications/app_search/components/empty_states/error_state.tsx
rename to x-pack/plugins/enterprise_search/public/applications/app_search/components/error_connecting/error_connecting.tsx
index c5a5f1fbb921f..34eb76d11a663 100644
--- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/empty_states/error_state.tsx
+++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/error_connecting/error_connecting.tsx
@@ -10,17 +10,13 @@ import { EuiPageContent } from '@elastic/eui';
import { ErrorStatePrompt } from '../../../shared/error_state';
import { SetAppSearchChrome as SetPageChrome } from '../../../shared/kibana_chrome';
import { SendAppSearchTelemetry as SendTelemetry } from '../../../shared/telemetry';
-import { EngineOverviewHeader } from '../engine_overview_header';
-import './empty_states.scss';
-
-export const ErrorState: React.FC = () => {
+export const ErrorConnecting: React.FC = () => {
return (
<>
-
diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview_header/index.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/error_connecting/index.ts
similarity index 78%
rename from x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview_header/index.ts
rename to x-pack/plugins/enterprise_search/public/applications/app_search/components/error_connecting/index.ts
index 2d37f037e21e5..c8b71e1a6e791 100644
--- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview_header/index.ts
+++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/error_connecting/index.ts
@@ -4,4 +4,4 @@
* you may not use this file except in compliance with the Elastic License.
*/
-export { EngineOverviewHeader } from './engine_overview_header';
+export { ErrorConnecting } from './error_connecting';
diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/index.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/index.test.tsx
index 0f4072c591bc7..94e9127bbed74 100644
--- a/x-pack/plugins/enterprise_search/public/applications/app_search/index.test.tsx
+++ b/x-pack/plugins/enterprise_search/public/applications/app_search/index.test.tsx
@@ -12,8 +12,10 @@ import { Redirect } from 'react-router-dom';
import { shallow } from 'enzyme';
import { useValues, useActions } from 'kea';
-import { SetupGuide } from './components/setup_guide';
import { Layout, SideNav, SideNavLink } from '../shared/layout';
+import { SetupGuide } from './components/setup_guide';
+import { ErrorConnecting } from './components/error_connecting';
+import { EngineOverview } from './components/engine_overview';
import { AppSearch, AppSearchUnconfigured, AppSearchConfigured, AppSearchNav } from './';
describe('AppSearch', () => {
@@ -42,12 +44,17 @@ describe('AppSearchUnconfigured', () => {
});
describe('AppSearchConfigured', () => {
- it('renders with layout', () => {
+ beforeEach(() => {
+ // Mock resets
+ (useValues as jest.Mock).mockImplementation(() => ({}));
(useActions as jest.Mock).mockImplementation(() => ({ initializeAppData: () => {} }));
+ });
+ it('renders with layout', () => {
const wrapper = shallow();
expect(wrapper.find(Layout)).toHaveLength(1);
+ expect(wrapper.find(EngineOverview)).toHaveLength(1);
});
it('initializes app data with passed props', () => {
@@ -62,12 +69,20 @@ describe('AppSearchConfigured', () => {
it('does not re-initialize app data', () => {
const initializeAppData = jest.fn();
(useActions as jest.Mock).mockImplementation(() => ({ initializeAppData }));
- (useValues as jest.Mock).mockImplementationOnce(() => ({ hasInitialized: true }));
+ (useValues as jest.Mock).mockImplementation(() => ({ hasInitialized: true }));
shallow();
expect(initializeAppData).not.toHaveBeenCalled();
});
+
+ it('renders ErrorConnecting', () => {
+ (useValues as jest.Mock).mockImplementation(() => ({ errorConnecting: true }));
+
+ const wrapper = shallow();
+
+ expect(wrapper.find(ErrorConnecting)).toHaveLength(1);
+ });
});
describe('AppSearchNav', () => {
diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/index.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/index.tsx
index 5f4734630624c..234201a157ec9 100644
--- a/x-pack/plugins/enterprise_search/public/applications/app_search/index.tsx
+++ b/x-pack/plugins/enterprise_search/public/applications/app_search/index.tsx
@@ -11,6 +11,7 @@ import { useActions, useValues } from 'kea';
import { i18n } from '@kbn/i18n';
import { KibanaContext, IKibanaContext } from '../index';
+import { HttpLogic, IHttpLogicValues } from '../shared/http';
import { AppLogic, IAppLogicActions, IAppLogicValues } from './app_logic';
import { IInitialAppData } from '../../../common/types';
@@ -27,6 +28,7 @@ import {
} from './routes';
import { SetupGuide } from './components/setup_guide';
+import { ErrorConnecting } from './components/error_connecting';
import { EngineOverview } from './components/engine_overview';
export const AppSearch: React.FC = (props) => {
@@ -48,6 +50,7 @@ export const AppSearchUnconfigured: React.FC = () => (
export const AppSearchConfigured: React.FC = (props) => {
const { hasInitialized } = useValues(AppLogic) as IAppLogicValues;
const { initializeAppData } = useActions(AppLogic) as IAppLogicActions;
+ const { errorConnecting } = useValues(HttpLogic) as IHttpLogicValues;
useEffect(() => {
if (!hasInitialized) initializeAppData(props);
@@ -60,14 +63,18 @@ export const AppSearchConfigured: React.FC = (props) => {
}>
-
-
-
-
-
-
-
-
+ {errorConnecting ? (
+
+ ) : (
+
+
+
+
+
+
+
+
+ )}
diff --git a/x-pack/plugins/enterprise_search/public/applications/index.tsx b/x-pack/plugins/enterprise_search/public/applications/index.tsx
index d6cc6e81509b2..60e4cedf413f2 100644
--- a/x-pack/plugins/enterprise_search/public/applications/index.tsx
+++ b/x-pack/plugins/enterprise_search/public/applications/index.tsx
@@ -22,6 +22,7 @@ import {
} from 'src/core/public';
import { ClientConfigType, ClientData, PluginsSetup } from '../plugin';
import { LicenseProvider } from './shared/licensing';
+import { HttpProvider } from './shared/http';
import { IExternalUrl } from './shared/enterprise_search_url';
import { IInitialAppData } from '../../common/types';
@@ -48,7 +49,7 @@ export const renderApp = (
core: CoreStart,
plugins: PluginsSetup,
config: ClientConfigType,
- { externalUrl, ...initialData }: ClientData
+ { externalUrl, errorConnecting, ...initialData }: ClientData
) => {
resetContext({ createStore: true });
const store = getContext().store as Store;
@@ -67,6 +68,7 @@ export const renderApp = (
>
+
@@ -77,7 +79,6 @@ export const renderApp = (
params.element
);
return () => {
- resetContext({});
ReactDOM.unmountComponentAtNode(params.element);
};
};
diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/http/http_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/shared/http/http_logic.test.ts
new file mode 100644
index 0000000000000..a6957340d33d3
--- /dev/null
+++ b/x-pack/plugins/enterprise_search/public/applications/shared/http/http_logic.test.ts
@@ -0,0 +1,110 @@
+/*
+ * 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 { resetContext } from 'kea';
+
+import { httpServiceMock } from 'src/core/public/mocks';
+
+import { HttpLogic } from './http_logic';
+
+describe('HttpLogic', () => {
+ const mockHttp = httpServiceMock.createSetupContract();
+ const DEFAULT_VALUES = {
+ http: null,
+ httpInterceptors: [],
+ errorConnecting: false,
+ };
+
+ beforeEach(() => {
+ jest.clearAllMocks();
+ resetContext({});
+ });
+
+ it('has expected default values', () => {
+ HttpLogic.mount();
+ expect(HttpLogic.values).toEqual(DEFAULT_VALUES);
+ });
+
+ describe('initializeHttp()', () => {
+ it('sets values based on passed props', () => {
+ HttpLogic.mount();
+ HttpLogic.actions.initializeHttp({ http: mockHttp, errorConnecting: true });
+
+ expect(HttpLogic.values).toEqual({
+ http: mockHttp,
+ httpInterceptors: [],
+ errorConnecting: true,
+ });
+ });
+ });
+
+ describe('setErrorConnecting()', () => {
+ it('sets errorConnecting value', () => {
+ HttpLogic.mount();
+ HttpLogic.actions.setErrorConnecting(true);
+ expect(HttpLogic.values.errorConnecting).toEqual(true);
+
+ HttpLogic.actions.setErrorConnecting(false);
+ expect(HttpLogic.values.errorConnecting).toEqual(false);
+ });
+ });
+
+ describe('http interceptors', () => {
+ describe('initializeHttpInterceptors()', () => {
+ beforeEach(() => {
+ HttpLogic.mount();
+ jest.spyOn(HttpLogic.actions, 'setHttpInterceptors');
+ jest.spyOn(HttpLogic.actions, 'setErrorConnecting');
+ HttpLogic.actions.initializeHttp({ http: mockHttp });
+
+ HttpLogic.actions.initializeHttpInterceptors();
+ });
+
+ it('calls http.intercept and sets an array of interceptors', () => {
+ mockHttp.intercept.mockImplementationOnce(() => 'removeInterceptorFn' as any);
+ HttpLogic.actions.initializeHttpInterceptors();
+
+ expect(mockHttp.intercept).toHaveBeenCalled();
+ expect(HttpLogic.actions.setHttpInterceptors).toHaveBeenCalledWith(['removeInterceptorFn']);
+ });
+
+ describe('errorConnectingInterceptor', () => {
+ it('handles errors connecting to Enterprise Search', async () => {
+ const { responseError } = mockHttp.intercept.mock.calls[0][0] as any;
+ await responseError({ response: { url: '/api/app_search/engines', status: 502 } });
+
+ expect(HttpLogic.actions.setErrorConnecting).toHaveBeenCalled();
+ });
+
+ it('does not handle non-502 Enterprise Search errors', async () => {
+ const { responseError } = mockHttp.intercept.mock.calls[0][0] as any;
+ await responseError({ response: { url: '/api/workplace_search/overview', status: 404 } });
+
+ expect(HttpLogic.actions.setErrorConnecting).not.toHaveBeenCalled();
+ });
+
+ it('does not handle errors for unrelated calls', async () => {
+ const { responseError } = mockHttp.intercept.mock.calls[0][0] as any;
+ await responseError({ response: { url: '/api/some_other_plugin/', status: 502 } });
+
+ expect(HttpLogic.actions.setErrorConnecting).not.toHaveBeenCalled();
+ });
+ });
+ });
+
+ it('sets httpInterceptors and calls all valid remove functions on unmount', () => {
+ const unmount = HttpLogic.mount();
+ const httpInterceptors = [jest.fn(), undefined, jest.fn()] as any;
+
+ HttpLogic.actions.setHttpInterceptors(httpInterceptors);
+ expect(HttpLogic.values.httpInterceptors).toEqual(httpInterceptors);
+
+ unmount();
+ expect(httpInterceptors[0]).toHaveBeenCalledTimes(1);
+ expect(httpInterceptors[2]).toHaveBeenCalledTimes(1);
+ });
+ });
+});
diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/http/http_logic.ts b/x-pack/plugins/enterprise_search/public/applications/shared/http/http_logic.ts
new file mode 100644
index 0000000000000..7bf7a19ed451f
--- /dev/null
+++ b/x-pack/plugins/enterprise_search/public/applications/shared/http/http_logic.ts
@@ -0,0 +1,86 @@
+/*
+ * 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 { kea } from 'kea';
+
+import { HttpSetup } from 'src/core/public';
+
+import { IKeaLogic, IKeaParams, TKeaReducers } from '../../shared/types';
+
+export interface IHttpLogicValues {
+ http: HttpSetup;
+ httpInterceptors: Function[];
+ errorConnecting: boolean;
+}
+export interface IHttpLogicActions {
+ initializeHttp({ http, errorConnecting }: { http: HttpSetup; errorConnecting?: boolean }): void;
+ initializeHttpInterceptors(): void;
+ setHttpInterceptors(httpInterceptors: Function[]): void;
+ setErrorConnecting(errorConnecting: boolean): void;
+}
+
+export const HttpLogic = kea({
+ actions: (): IHttpLogicActions => ({
+ initializeHttp: ({ http, errorConnecting }) => ({ http, errorConnecting }),
+ initializeHttpInterceptors: () => null,
+ setHttpInterceptors: (httpInterceptors) => ({ httpInterceptors }),
+ setErrorConnecting: (errorConnecting) => ({ errorConnecting }),
+ }),
+ reducers: (): TKeaReducers => ({
+ http: [
+ (null as unknown) as HttpSetup,
+ {
+ initializeHttp: (_, { http }) => http,
+ },
+ ],
+ httpInterceptors: [
+ [],
+ {
+ setHttpInterceptors: (_, { httpInterceptors }) => httpInterceptors,
+ },
+ ],
+ errorConnecting: [
+ false,
+ {
+ initializeHttp: (_, { errorConnecting }) => !!errorConnecting,
+ setErrorConnecting: (_, { errorConnecting }) => errorConnecting,
+ },
+ ],
+ }),
+ listeners: ({ values, actions }) => ({
+ initializeHttpInterceptors: () => {
+ const httpInterceptors = [];
+
+ const errorConnectingInterceptor = values.http.intercept({
+ responseError: async (httpResponse) => {
+ const { url, status } = httpResponse.response!;
+ const hasErrorConnecting = status === 502;
+ const isApiResponse =
+ url.includes('/api/app_search/') || url.includes('/api/workplace_search/');
+
+ if (isApiResponse && hasErrorConnecting) {
+ actions.setErrorConnecting(true);
+ }
+ return httpResponse;
+ },
+ });
+ httpInterceptors.push(errorConnectingInterceptor);
+
+ // TODO: Read only mode interceptor
+ actions.setHttpInterceptors(httpInterceptors);
+ },
+ }),
+ events: ({ values }) => ({
+ beforeUnmount: () => {
+ values.httpInterceptors.forEach((removeInterceptorFn?: Function) => {
+ if (removeInterceptorFn) removeInterceptorFn();
+ });
+ },
+ }),
+} as IKeaParams) as IKeaLogic<
+ IHttpLogicValues,
+ IHttpLogicActions
+>;
diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/http/http_provider.test.tsx b/x-pack/plugins/enterprise_search/public/applications/shared/http/http_provider.test.tsx
new file mode 100644
index 0000000000000..81106235780d6
--- /dev/null
+++ b/x-pack/plugins/enterprise_search/public/applications/shared/http/http_provider.test.tsx
@@ -0,0 +1,44 @@
+/*
+ * 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 '../../__mocks__/shallow_usecontext.mock';
+import '../../__mocks__/kea.mock';
+
+import React from 'react';
+import { shallow } from 'enzyme';
+import { useActions } from 'kea';
+
+import { HttpProvider } from './';
+
+describe('HttpProvider', () => {
+ const props = {
+ http: {} as any,
+ errorConnecting: false,
+ };
+ const initializeHttp = jest.fn();
+ const initializeHttpInterceptors = jest.fn();
+
+ beforeEach(() => {
+ jest.clearAllMocks();
+ (useActions as jest.Mock).mockImplementationOnce(() => ({
+ initializeHttp,
+ initializeHttpInterceptors,
+ }));
+ });
+
+ it('does not render', () => {
+ const wrapper = shallow();
+
+ expect(wrapper.isEmptyRender()).toBe(true);
+ });
+
+ it('calls initialization actions on mount', () => {
+ shallow();
+
+ expect(initializeHttp).toHaveBeenCalledWith(props);
+ expect(initializeHttpInterceptors).toHaveBeenCalled();
+ });
+});
diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/http/http_provider.tsx b/x-pack/plugins/enterprise_search/public/applications/shared/http/http_provider.tsx
new file mode 100644
index 0000000000000..6febc1869054f
--- /dev/null
+++ b/x-pack/plugins/enterprise_search/public/applications/shared/http/http_provider.tsx
@@ -0,0 +1,28 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import React, { useEffect } from 'react';
+import { useActions } from 'kea';
+
+import { HttpSetup } from 'src/core/public';
+
+import { HttpLogic, IHttpLogicActions } from './http_logic';
+
+interface IHttpProviderProps {
+ http: HttpSetup;
+ errorConnecting?: boolean;
+}
+
+export const HttpProvider: React.FC = (props) => {
+ const { initializeHttp, initializeHttpInterceptors } = useActions(HttpLogic) as IHttpLogicActions;
+
+ useEffect(() => {
+ initializeHttp(props);
+ initializeHttpInterceptors();
+ }, []);
+
+ return null;
+};
diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/http/index.ts b/x-pack/plugins/enterprise_search/public/applications/shared/http/index.ts
new file mode 100644
index 0000000000000..449ff9d56debf
--- /dev/null
+++ b/x-pack/plugins/enterprise_search/public/applications/shared/http/index.ts
@@ -0,0 +1,8 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+export { HttpLogic, IHttpLogicValues, IHttpLogicActions } from './http_logic';
+export { HttpProvider } from './http_provider';
diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/types.ts b/x-pack/plugins/enterprise_search/public/applications/shared/types.ts
index 74bb53ef3a954..a8e08323c5e3b 100644
--- a/x-pack/plugins/enterprise_search/public/applications/shared/types.ts
+++ b/x-pack/plugins/enterprise_search/public/applications/shared/types.ts
@@ -14,7 +14,7 @@ export interface IFlashMessagesProps {
}
export interface IKeaLogic {
- mount(): void;
+ mount(): Function;
values: IKeaValues;
actions: IKeaActions;
}
@@ -33,6 +33,7 @@ export interface IKeaLogic {
export interface IKeaParams {
selectors?(params: { selectors: IKeaValues }): void;
listeners?(params: { actions: IKeaActions; values: IKeaValues }): void;
+ events?(params: { actions: IKeaActions; values: IKeaValues }): void;
}
/**
@@ -47,7 +48,10 @@ export type TKeaReducers = {
[Value in keyof IKeaValues]?: [
IKeaValues[Value],
{
- [Action in keyof IKeaActions]?: (state: IKeaValues, payload: IKeaValues) => IKeaValues[Value];
+ [Action in keyof IKeaActions]?: (
+ state: IKeaValues[Value],
+ payload: IKeaValues
+ ) => IKeaValues[Value];
}
];
};
diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/overview/__mocks__/overview_logic.mock.ts b/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/overview/__mocks__/overview_logic.mock.ts
index 395d2044e7dbc..5588c4fc53b67 100644
--- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/overview/__mocks__/overview_logic.mock.ts
+++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/overview/__mocks__/overview_logic.mock.ts
@@ -22,7 +22,6 @@ export const mockLogicValues = {
personalSourcesCount: 0,
sourcesCount: 0,
dataLoading: true,
- hasErrorConnecting: false,
flashMessages: {},
} as IOverviewValues;
diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/overview/overview.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/overview/overview.test.tsx
index 744fd8aeb1951..fee966a56923d 100644
--- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/overview/overview.test.tsx
+++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/overview/overview.test.tsx
@@ -11,7 +11,6 @@ import { mockLogicActions, setMockValues } from './__mocks__';
import React from 'react';
import { shallow, mount } from 'enzyme';
-import { ErrorState } from '../error_state';
import { Loading } from '../shared/loading';
import { ViewContentHeader } from '../shared/view_content_header';
@@ -27,13 +26,6 @@ describe('Overview', () => {
expect(wrapper.find(Loading)).toHaveLength(1);
});
-
- it('hasErrorConnecting', () => {
- setMockValues({ hasErrorConnecting: true });
- const wrapper = shallow();
-
- expect(wrapper.find(ErrorState)).toHaveLength(1);
- });
});
describe('happy-path states', () => {
diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/overview/overview.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/overview/overview.tsx
index b816eb2973207..6aa3e1e608bfe 100644
--- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/overview/overview.tsx
+++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/overview/overview.tsx
@@ -6,19 +6,16 @@
// TODO: Remove EuiPage & EuiPageBody before exposing full app
-import React, { useContext, useEffect } from 'react';
+import React, { useEffect } from 'react';
import { EuiPage, EuiPageBody, EuiSpacer } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { useActions, useValues } from 'kea';
import { SetWorkplaceSearchChrome as SetPageChrome } from '../../../shared/kibana_chrome';
import { SendWorkplaceSearchTelemetry as SendTelemetry } from '../../../shared/telemetry';
-import { KibanaContext, IKibanaContext } from '../../../index';
import { OverviewLogic, IOverviewActions, IOverviewValues } from './overview_logic';
-import { ErrorState } from '../error_state';
-
import { Loading } from '../shared/loading';
import { ProductButton } from '../shared/product_button';
import { ViewContentHeader } from '../shared/view_content_header';
@@ -47,13 +44,10 @@ const HEADER_DESCRIPTION = i18n.translate(
);
export const Overview: React.FC = () => {
- const { http } = useContext(KibanaContext) as IKibanaContext;
-
const { initializeOverview } = useActions(OverviewLogic) as IOverviewActions;
const {
dataLoading,
- hasErrorConnecting,
hasUsers,
hasOrgSources,
isOldAccount,
@@ -61,10 +55,9 @@ export const Overview: React.FC = () => {
} = useValues(OverviewLogic) as IOverviewValues;
useEffect(() => {
- initializeOverview({ http });
+ initializeOverview();
}, [initializeOverview]);
- if (hasErrorConnecting) return ;
if (dataLoading) return ;
const hideOnboarding = hasUsers && hasOrgSources && isOldAccount && orgName !== defaultOrgName;
diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/overview/overview_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/overview/overview_logic.test.ts
index 7df4de4719f31..3fbf0e60b5b49 100644
--- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/overview/overview_logic.test.ts
+++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/overview/overview_logic.test.ts
@@ -5,24 +5,18 @@
*/
import { resetContext } from 'kea';
-import { act } from 'react-dom/test-utils';
-import { mockKibanaContext } from '../../../__mocks__';
+jest.mock('../../../shared/http', () => ({ HttpLogic: { values: { http: { get: jest.fn() } } } }));
+import { HttpLogic } from '../../../shared/http';
import { mockLogicValues } from './__mocks__';
import { OverviewLogic } from './overview_logic';
describe('OverviewLogic', () => {
- let unmount: any;
-
beforeEach(() => {
- resetContext({});
- unmount = OverviewLogic.mount() as any;
jest.clearAllMocks();
- });
-
- afterEach(() => {
- unmount();
+ resetContext({});
+ OverviewLogic.mount();
});
it('has expected default values', () => {
@@ -91,48 +85,14 @@ describe('OverviewLogic', () => {
});
});
- describe('setHasErrorConnecting', () => {
- it('will set `hasErrorConnecting`', () => {
- OverviewLogic.actions.setHasErrorConnecting(true);
-
- expect(OverviewLogic.values.hasErrorConnecting).toEqual(true);
- expect(OverviewLogic.values.dataLoading).toEqual(false);
- });
- });
-
describe('initializeOverview', () => {
it('calls API and sets values', async () => {
- const mockHttp = mockKibanaContext.http;
- const mockApi = jest.fn(() => mockLogicValues as any);
const setServerDataSpy = jest.spyOn(OverviewLogic.actions, 'setServerData');
- await act(async () =>
- OverviewLogic.actions.initializeOverview({
- http: {
- ...mockHttp,
- get: mockApi,
- },
- })
- );
+ await OverviewLogic.actions.initializeOverview();
- expect(mockApi).toHaveBeenCalledWith('/api/workplace_search/overview');
+ expect(HttpLogic.values.http.get).toHaveBeenCalledWith('/api/workplace_search/overview');
expect(setServerDataSpy).toHaveBeenCalled();
});
-
- it('handles error state', async () => {
- const mockHttp = mockKibanaContext.http;
- const setHasErrorConnectingSpy = jest.spyOn(OverviewLogic.actions, 'setHasErrorConnecting');
-
- await act(async () =>
- OverviewLogic.actions.initializeOverview({
- http: {
- ...mockHttp,
- get: () => Promise.reject(),
- },
- })
- );
-
- expect(setHasErrorConnectingSpy).toHaveBeenCalled();
- });
});
});
diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/overview/overview_logic.ts b/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/overview/overview_logic.ts
index 8bb177a2e742b..057bce1b4056c 100644
--- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/overview/overview_logic.ts
+++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/overview/overview_logic.ts
@@ -4,9 +4,8 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import { HttpSetup } from 'src/core/public';
-
import { kea } from 'kea';
+import { HttpLogic } from '../../../shared/http';
import { IAccount, IOrganization } from '../../types';
import { IFlashMessagesProps, IKeaLogic, TKeaReducers, IKeaParams } from '../../../shared/types';
@@ -32,13 +31,11 @@ export interface IOverviewServerData {
export interface IOverviewActions {
setServerData(serverData: IOverviewServerData): void;
setFlashMessages(flashMessages: IFlashMessagesProps): void;
- setHasErrorConnecting(hasErrorConnecting: boolean): void;
- initializeOverview({ http }: { http: HttpSetup }): void;
+ initializeOverview(): void;
}
export interface IOverviewValues extends IOverviewServerData {
dataLoading: boolean;
- hasErrorConnecting: boolean;
flashMessages: IFlashMessagesProps;
}
@@ -46,8 +43,7 @@ export const OverviewLogic = kea({
actions: (): IOverviewActions => ({
setServerData: (serverData) => serverData,
setFlashMessages: (flashMessages) => ({ flashMessages }),
- setHasErrorConnecting: (hasErrorConnecting) => ({ hasErrorConnecting }),
- initializeOverview: ({ http }) => ({ http }),
+ initializeOverview: () => null,
}),
reducers: (): TKeaReducers => ({
organization: [
@@ -138,24 +134,13 @@ export const OverviewLogic = kea({
true,
{
setServerData: () => false,
- setHasErrorConnecting: () => false,
- },
- ],
- hasErrorConnecting: [
- false,
- {
- setHasErrorConnecting: (_, { hasErrorConnecting }) => hasErrorConnecting,
},
],
}),
listeners: ({ actions }): Partial => ({
- initializeOverview: async ({ http }: { http: HttpSetup }) => {
- try {
- const response = await http.get('/api/workplace_search/overview');
- actions.setServerData(response);
- } catch (error) {
- actions.setHasErrorConnecting(true);
- }
+ initializeOverview: async () => {
+ const response = await HttpLogic.values.http.get('/api/workplace_search/overview');
+ actions.setServerData(response);
},
}),
} as IKeaParams) as IKeaLogic;
diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/index.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/index.test.tsx
index a55ff64014130..654f4dce0ebf3 100644
--- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/index.test.tsx
+++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/index.test.tsx
@@ -5,35 +5,44 @@
*/
import '../__mocks__/shallow_usecontext.mock';
+import '../__mocks__/kea.mock';
import React, { useContext } from 'react';
import { Redirect } from 'react-router-dom';
import { shallow } from 'enzyme';
+import { useValues } from 'kea';
import { Overview } from './components/overview';
+import { ErrorState } from './components/error_state';
import { WorkplaceSearch } from './';
describe('Workplace Search', () => {
- describe('/', () => {
- it('redirects to Setup Guide when enterpriseSearchUrl is not set', () => {
- (useContext as jest.Mock).mockImplementationOnce(() => ({
- config: { host: '' },
- }));
- const wrapper = shallow();
-
- expect(wrapper.find(Redirect)).toHaveLength(1);
- expect(wrapper.find(Overview)).toHaveLength(0);
- });
-
- it('renders the Overview when enterpriseSearchUrl is set', () => {
- (useContext as jest.Mock).mockImplementationOnce(() => ({
- config: { host: 'https://foo.bar' },
- }));
- const wrapper = shallow();
-
- expect(wrapper.find(Overview)).toHaveLength(1);
- expect(wrapper.find(Redirect)).toHaveLength(0);
- });
+ it('redirects to Setup Guide when enterpriseSearchUrl is not set', () => {
+ (useContext as jest.Mock).mockImplementationOnce(() => ({
+ config: { host: '' },
+ }));
+ const wrapper = shallow();
+
+ expect(wrapper.find(Redirect)).toHaveLength(1);
+ expect(wrapper.find(Overview)).toHaveLength(0);
+ });
+
+ it('renders the Overview when enterpriseSearchUrl is set', () => {
+ (useContext as jest.Mock).mockImplementationOnce(() => ({
+ config: { host: 'https://foo.bar' },
+ }));
+ const wrapper = shallow();
+
+ expect(wrapper.find(Overview)).toHaveLength(1);
+ expect(wrapper.find(Redirect)).toHaveLength(0);
+ });
+
+ it('renders ErrorState when the app cannot connect to Enterprise Search', () => {
+ (useValues as jest.Mock).mockImplementationOnce(() => ({ errorConnecting: true }));
+ const wrapper = shallow();
+
+ expect(wrapper.find(ErrorState).exists()).toBe(true);
+ expect(wrapper.find(Overview)).toHaveLength(0);
});
});
diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/index.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/index.tsx
index 94462aa8de7d1..b261c83e30dde 100644
--- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/index.tsx
+++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/index.tsx
@@ -6,19 +6,24 @@
import React, { useContext } from 'react';
import { Route, Redirect, Switch } from 'react-router-dom';
+import { useValues } from 'kea';
import { IInitialAppData } from '../../../common/types';
import { KibanaContext, IKibanaContext } from '../index';
+import { HttpLogic, IHttpLogicValues } from '../shared/http';
import { Layout } from '../shared/layout';
import { WorkplaceSearchNav } from './components/layout/nav';
import { SETUP_GUIDE_PATH } from './routes';
import { SetupGuide } from './components/setup_guide';
+import { ErrorState } from './components/error_state';
import { Overview } from './components/overview';
export const WorkplaceSearch: React.FC = (props) => {
const { config } = useContext(KibanaContext) as IKibanaContext;
+ const { errorConnecting } = useValues(HttpLogic) as IHttpLogicValues;
+
if (!config.host)
return (
@@ -37,16 +42,20 @@ export const WorkplaceSearch: React.FC = (props) => {
-
+ {errorConnecting ? : }
}>
-
-
- {/* Will replace with groups component subsequent PR */}
-
-
-
+ {errorConnecting ? (
+
+ ) : (
+
+
+ {/* Will replace with groups component subsequent PR */}
+
+
+
+ )}
diff --git a/x-pack/plugins/enterprise_search/public/plugin.ts b/x-pack/plugins/enterprise_search/public/plugin.ts
index 148a50fb4a5ce..881fe02af5b09 100644
--- a/x-pack/plugins/enterprise_search/public/plugin.ts
+++ b/x-pack/plugins/enterprise_search/public/plugin.ts
@@ -31,6 +31,7 @@ export interface ClientConfigType {
}
export interface ClientData extends IInitialAppData {
externalUrl: IExternalUrl;
+ errorConnecting?: boolean;
}
export interface PluginsSetup {
@@ -123,6 +124,7 @@ export class EnterpriseSearchPlugin implements Plugin {
this.hasInitialized = true;
} catch {
+ this.data.errorConnecting = true;
// The plugin will attempt to re-fetch config data on page change
}
}
diff --git a/x-pack/plugins/enterprise_search/server/routes/app_search/engines.test.ts b/x-pack/plugins/enterprise_search/server/routes/app_search/engines.test.ts
index 968ecb95fd931..1ea023ecacdbe 100644
--- a/x-pack/plugins/enterprise_search/server/routes/app_search/engines.test.ts
+++ b/x-pack/plugins/enterprise_search/server/routes/app_search/engines.test.ts
@@ -68,10 +68,11 @@ describe('engine routes', () => {
).andReturnError();
});
- it('should return 404 with a message', async () => {
+ it('should return 502 with a message', async () => {
await mockRouter.callRoute(mockRequest);
- expect(mockRouter.response.notFound).toHaveBeenCalledWith({
+ expect(mockRouter.response.customError).toHaveBeenCalledWith({
+ statusCode: 502,
body: 'cannot-connect',
});
expect(mockLogger.error).toHaveBeenCalledWith('Cannot connect to App Search: Failed');
@@ -87,10 +88,11 @@ describe('engine routes', () => {
).andReturnInvalidData();
});
- it('should return 404 with a message', async () => {
+ it('should return 502 with a message', async () => {
await mockRouter.callRoute(mockRequest);
- expect(mockRouter.response.notFound).toHaveBeenCalledWith({
+ expect(mockRouter.response.customError).toHaveBeenCalledWith({
+ statusCode: 502,
body: 'cannot-connect',
});
expect(mockLogger.error).toHaveBeenCalledWith(
diff --git a/x-pack/plugins/enterprise_search/server/routes/app_search/engines.ts b/x-pack/plugins/enterprise_search/server/routes/app_search/engines.ts
index ca83c0e187ddb..7190772fb92bb 100644
--- a/x-pack/plugins/enterprise_search/server/routes/app_search/engines.ts
+++ b/x-pack/plugins/enterprise_search/server/routes/app_search/engines.ts
@@ -52,7 +52,7 @@ export function registerEnginesRoute({ router, config, log }: IRouteDependencies
log.error(`Cannot connect to App Search: ${e.toString()}`);
if (e instanceof Error) log.debug(e.stack as string);
- return response.notFound({ body: 'cannot-connect' });
+ return response.customError({ statusCode: 502, body: 'cannot-connect' });
}
}
);
diff --git a/x-pack/plugins/enterprise_search/server/routes/workplace_search/overview.test.ts b/x-pack/plugins/enterprise_search/server/routes/workplace_search/overview.test.ts
index 3a4e28b0de5ff..f6534b27b5da0 100644
--- a/x-pack/plugins/enterprise_search/server/routes/workplace_search/overview.test.ts
+++ b/x-pack/plugins/enterprise_search/server/routes/workplace_search/overview.test.ts
@@ -63,10 +63,11 @@ describe('engine routes', () => {
}).andReturnError();
});
- it('should return 404 with a message', async () => {
+ it('should return 502 with a message', async () => {
await mockRouter.callRoute(mockRequest);
- expect(mockRouter.response.notFound).toHaveBeenCalledWith({
+ expect(mockRouter.response.customError).toHaveBeenCalledWith({
+ statusCode: 502,
body: 'cannot-connect',
});
expect(mockLogger.error).toHaveBeenCalledWith('Cannot connect to Workplace Search: Failed');
@@ -81,10 +82,11 @@ describe('engine routes', () => {
}).andReturnInvalidData();
});
- it('should return 404 with a message', async () => {
+ it('should return 502 with a message', async () => {
await mockRouter.callRoute(mockRequest);
- expect(mockRouter.response.notFound).toHaveBeenCalledWith({
+ expect(mockRouter.response.customError).toHaveBeenCalledWith({
+ statusCode: 502,
body: 'cannot-connect',
});
expect(mockLogger.error).toHaveBeenCalledWith(
diff --git a/x-pack/plugins/enterprise_search/server/routes/workplace_search/overview.ts b/x-pack/plugins/enterprise_search/server/routes/workplace_search/overview.ts
index d1e2f4f5f180d..9e5d94ac1b4fe 100644
--- a/x-pack/plugins/enterprise_search/server/routes/workplace_search/overview.ts
+++ b/x-pack/plugins/enterprise_search/server/routes/workplace_search/overview.ts
@@ -39,7 +39,7 @@ export function registerWSOverviewRoute({ router, config, log }: IRouteDependenc
log.error(`Cannot connect to Workplace Search: ${e.toString()}`);
if (e instanceof Error) log.debug(e.stack as string);
- return response.notFound({ body: 'cannot-connect' });
+ return response.customError({ statusCode: 502, body: 'cannot-connect' });
}
}
);