diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_nav.scss b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_nav.scss
index d7740724204a7..529fb9c4bd63e 100644
--- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_nav.scss
+++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_nav.scss
@@ -15,3 +15,11 @@
margin-top: $euiSizeXS;
}
}
+
+.appSearchNavIcons {
+ // EUI override
+ &.euiFlexItem {
+ flex-grow: 0;
+ flex-direction: row;
+ }
+}
diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_nav.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_nav.test.tsx
index 7bdc3c86a50d6..7e8228a89cb8d 100644
--- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_nav.test.tsx
+++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_nav.test.tsx
@@ -4,134 +4,188 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import '../../../__mocks__/react_router_history.mock';
import { setMockValues } from '../../../__mocks__/kea.mock';
import React from 'react';
-import { shallow, mount } from 'enzyme';
-import { Switch, useParams } from 'react-router-dom';
-import { EuiBadge } from '@elastic/eui';
+import { shallow } from 'enzyme';
+import { EuiBadge, EuiIcon } from '@elastic/eui';
-import { EngineRouter, EngineNav } from './';
+import { EngineNav } from './';
-describe('EngineRouter', () => {
- it('renders a default engine overview', () => {
- setMockValues({ myRole: {} });
- const wrapper = shallow();
-
- expect(wrapper.find(Switch)).toHaveLength(1);
- expect(wrapper.find('[data-test-subj="EngineOverviewTODO"]')).toHaveLength(1);
- });
-
- it('renders an analytics view', () => {
- setMockValues({ myRole: { canViewEngineAnalytics: true } });
- const wrapper = shallow();
+describe('EngineNav', () => {
+ const values = { myRole: {}, engineName: 'some-engine', dataLoading: false, engine: {} };
- expect(wrapper.find('[data-test-subj="AnalyticsTODO"]')).toHaveLength(1);
+ beforeEach(() => {
+ setMockValues(values);
});
-});
-describe('EngineNav', () => {
- beforeEach(() => {
- (useParams as jest.Mock).mockReturnValue({ engineName: 'some-engine' });
+ it('does not render if async data is still loading', () => {
+ setMockValues({ ...values, dataLoading: true });
+ const wrapper = shallow();
+ expect(wrapper.isEmptyRender()).toBe(true);
});
it('does not render without an engine name', () => {
- setMockValues({ myRole: {} });
- (useParams as jest.Mock).mockReturnValue({ engineName: '' });
+ setMockValues({ ...values, engineName: '' });
const wrapper = shallow();
expect(wrapper.isEmptyRender()).toBe(true);
});
- it('renders an engine label', () => {
- setMockValues({ myRole: {} });
- const wrapper = mount();
+ it('renders an engine label and badges', () => {
+ setMockValues({ ...values, isSampleEngine: false, isMetaEngine: false });
+ const wrapper = shallow();
+ const label = wrapper.find('[data-test-subj="EngineLabel"]').find('.eui-textTruncate');
+
+ expect(label.text()).toEqual('SOME-ENGINE');
+ expect(wrapper.find(EuiBadge)).toHaveLength(0);
- const label = wrapper.find('[data-test-subj="EngineLabel"]').last();
- expect(label.text()).toEqual(expect.stringContaining('SOME-ENGINE'));
+ setMockValues({ ...values, isSampleEngine: true });
+ wrapper.setProps({}); // Re-render
+ expect(wrapper.find(EuiBadge).prop('children')).toEqual('SAMPLE ENGINE');
- // TODO: Test sample & meta engine conditional rendering
- expect(label.find(EuiBadge).text()).toEqual('SAMPLE ENGINE');
+ setMockValues({ ...values, isMetaEngine: true });
+ wrapper.setProps({}); // Re-render
+ expect(wrapper.find(EuiBadge).prop('children')).toEqual('META ENGINE');
});
it('renders a default engine overview link', () => {
- setMockValues({ myRole: {} });
const wrapper = shallow();
expect(wrapper.find('[data-test-subj="EngineOverviewLink"]')).toHaveLength(1);
});
it('renders an analytics link', () => {
- setMockValues({ myRole: { canViewEngineAnalytics: true } });
+ setMockValues({ ...values, myRole: { canViewEngineAnalytics: true } });
const wrapper = shallow();
expect(wrapper.find('[data-test-subj="EngineAnalyticsLink"]')).toHaveLength(1);
});
it('renders a documents link', () => {
- setMockValues({ myRole: { canViewEngineDocuments: true } });
+ setMockValues({ ...values, myRole: { canViewEngineDocuments: true } });
const wrapper = shallow();
expect(wrapper.find('[data-test-subj="EngineDocumentsLink"]')).toHaveLength(1);
});
it('renders a schema link', () => {
- setMockValues({ myRole: { canViewEngineSchema: true } });
+ setMockValues({ ...values, myRole: { canViewEngineSchema: true } });
const wrapper = shallow();
expect(wrapper.find('[data-test-subj="EngineSchemaLink"]')).toHaveLength(1);
+ });
+
+ describe('schema nav icons', () => {
+ const myRole = { canViewEngineSchema: true };
+
+ it('renders unconfirmed schema fields info icon', () => {
+ setMockValues({ ...values, myRole, hasUnconfirmedSchemaFields: true });
+ const wrapper = shallow();
+ expect(wrapper.find('[data-test-subj="EngineNavSchemaUnconfirmedFields"]')).toHaveLength(1);
+ });
- // TODO: Schema warning icon
+ it('renders schema conflicts alert icon', () => {
+ setMockValues({ ...values, myRole, hasSchemaConflicts: true });
+ const wrapper = shallow();
+ expect(wrapper.find('[data-test-subj="EngineNavSchemaConflicts"]')).toHaveLength(1);
+ });
});
- // TODO: Unskip when EngineLogic is migrated
- it.skip('renders a crawler link', () => {
- setMockValues({ myRole: { canViewEngineCrawler: true } });
- const wrapper = shallow();
- expect(wrapper.find('[data-test-subj="EngineCrawlerLink"]')).toHaveLength(1);
+ describe('crawler link', () => {
+ const myRole = { canViewEngineCrawler: true };
+
+ it('renders', () => {
+ setMockValues({ ...values, myRole });
+ const wrapper = shallow();
+ expect(wrapper.find('[data-test-subj="EngineCrawlerLink"]')).toHaveLength(1);
+ });
+
+ it('does not render for meta engines', () => {
+ setMockValues({ ...values, myRole, isMetaEngine: true });
+ const wrapper = shallow();
+ expect(wrapper.find('[data-test-subj="EngineCrawlerLink"]')).toHaveLength(0);
+ });
- // TODO: Test that the crawler link does NOT show up for meta/sample engines
+ it('does not render for sample engine', () => {
+ setMockValues({ ...values, myRole, isSampleEngine: true });
+ const wrapper = shallow();
+ expect(wrapper.find('[data-test-subj="EngineCrawlerLink"]')).toHaveLength(0);
+ });
});
- // TODO: Unskip when EngineLogic is migrated
- it.skip('renders a meta engine source engines link', () => {
- setMockValues({ myRole: { canViewMetaEngineSourceEngines: true } });
- const wrapper = shallow();
- expect(wrapper.find('[data-test-subj="MetaEngineEnginesLink"]')).toHaveLength(1);
+ describe('meta engine source engines link', () => {
+ const myRole = { canViewMetaEngineSourceEngines: true };
+
+ it('renders', () => {
+ setMockValues({ ...values, myRole, isMetaEngine: true });
+ const wrapper = shallow();
+ expect(wrapper.find('[data-test-subj="MetaEngineEnginesLink"]')).toHaveLength(1);
+ });
- // TODO: Test that the crawler link does NOT show up for non-meta engines
+ it('does not render for non meta engines', () => {
+ setMockValues({ ...values, myRole, isMetaEngine: false });
+ const wrapper = shallow();
+ expect(wrapper.find('[data-test-subj="MetaEngineEnginesLink"]')).toHaveLength(0);
+ });
});
it('renders a relevance tuning link', () => {
- setMockValues({ myRole: { canManageEngineRelevanceTuning: true } });
+ setMockValues({ ...values, myRole: { canManageEngineRelevanceTuning: true } });
const wrapper = shallow();
expect(wrapper.find('[data-test-subj="EngineRelevanceTuningLink"]')).toHaveLength(1);
+ });
+
+ describe('relevance tuning nav icons', () => {
+ const myRole = { canManageEngineRelevanceTuning: true };
+
+ it('renders unconfirmed schema fields info icon', () => {
+ const engine = { unsearchedUnconfirmedFields: true };
+ setMockValues({ ...values, myRole, engine });
+ const wrapper = shallow();
+ expect(
+ wrapper.find('[data-test-subj="EngineNavRelevanceTuningUnsearchedFields"]')
+ ).toHaveLength(1);
+ });
+
+ it('renders schema conflicts alert icon', () => {
+ const engine = { invalidBoosts: true };
+ setMockValues({ ...values, myRole, engine });
+ const wrapper = shallow();
+ expect(wrapper.find('[data-test-subj="EngineNavRelevanceTuningInvalidBoosts"]')).toHaveLength(
+ 1
+ );
+ });
- // TODO: Boost error icon
+ it('can render multiple icons', () => {
+ const engine = { invalidBoosts: true, unsearchedUnconfirmedFields: true };
+ setMockValues({ ...values, myRole, engine });
+ const wrapper = shallow();
+ expect(wrapper.find(EuiIcon)).toHaveLength(2);
+ });
});
it('renders a synonyms link', () => {
- setMockValues({ myRole: { canManageEngineSynonyms: true } });
+ setMockValues({ ...values, myRole: { canManageEngineSynonyms: true } });
const wrapper = shallow();
expect(wrapper.find('[data-test-subj="EngineSynonymsLink"]')).toHaveLength(1);
});
it('renders a curations link', () => {
- setMockValues({ myRole: { canManageEngineCurations: true } });
+ setMockValues({ ...values, myRole: { canManageEngineCurations: true } });
const wrapper = shallow();
expect(wrapper.find('[data-test-subj="EngineCurationsLink"]')).toHaveLength(1);
});
it('renders a results settings link', () => {
- setMockValues({ myRole: { canManageEngineResultSettings: true } });
+ setMockValues({ ...values, myRole: { canManageEngineResultSettings: true } });
const wrapper = shallow();
expect(wrapper.find('[data-test-subj="EngineResultSettingsLink"]')).toHaveLength(1);
});
it('renders a Search UI link', () => {
- setMockValues({ myRole: { canManageEngineSearchUi: true } });
+ setMockValues({ ...values, myRole: { canManageEngineSearchUi: true } });
const wrapper = shallow();
expect(wrapper.find('[data-test-subj="EngineSearchUILink"]')).toHaveLength(1);
});
it('renders an API logs link', () => {
- setMockValues({ myRole: { canViewEngineApiLogs: true } });
+ setMockValues({ ...values, myRole: { canViewEngineApiLogs: true } });
const wrapper = shallow();
expect(wrapper.find('[data-test-subj="EngineAPILogsLink"]')).toHaveLength(1);
});
diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_nav.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_nav.tsx
index f92fefc7124b8..77aca8a71994d 100644
--- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_nav.tsx
+++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_nav.tsx
@@ -5,18 +5,15 @@
*/
import React from 'react';
-import { Route, Switch, useParams } from 'react-router-dom';
import { useValues } from 'kea';
-import { EuiText, EuiBadge } from '@elastic/eui';
+import { EuiText, EuiBadge, EuiIcon, EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { SideNavLink, SideNavItem } from '../../../shared/layout';
-import { SetAppSearchChrome as SetPageChrome } from '../../../shared/kibana_chrome';
import { AppLogic } from '../../app_logic';
import {
getEngineRoute,
- ENGINE_PATH,
ENGINE_ANALYTICS_PATH,
ENGINE_DOCUMENTS_PATH,
ENGINE_SCHEMA_PATH,
@@ -45,34 +42,10 @@ import {
API_LOGS_TITLE,
} from './constants';
-import './engine_nav.scss';
-
-export const EngineRouter: React.FC = () => {
- const {
- myRole: { canViewEngineAnalytics },
- } = useValues(AppLogic);
+import { EngineLogic } from './';
+import { EngineDetails } from './types';
- // TODO: EngineLogic
-
- const { engineName } = useParams() as { engineName: string };
- const engineBreadcrumb = [ENGINES_TITLE, engineName];
-
- return (
- // TODO: Add more routes as we migrate them
-
- {canViewEngineAnalytics && (
-
-
- Just testing right now
-
- )}
-
-
- Overview
-
-
- );
-};
+import './engine_nav.scss';
export const EngineNav: React.FC = () => {
const {
@@ -91,14 +64,22 @@ export const EngineNav: React.FC = () => {
},
} = useValues(AppLogic);
- // TODO: Use EngineLogic
- const isSampleEngine = true;
- const isMetaEngine = false;
- const { engineName } = useParams() as { engineName: string };
- const engineRoute = engineName && getEngineRoute(engineName);
+ const {
+ engineName,
+ dataLoading,
+ isSampleEngine,
+ isMetaEngine,
+ hasSchemaConflicts,
+ hasUnconfirmedSchemaFields,
+ engine,
+ } = useValues(EngineLogic);
+ if (dataLoading) return null;
if (!engineName) return null;
+ const engineRoute = getEngineRoute(engineName);
+ const { invalidBoosts, unsearchedUnconfirmedFields } = engine as Required;
+
return (
<>
@@ -143,8 +124,33 @@ export const EngineNav: React.FC = () => {
to={getAppSearchUrl(engineRoute + ENGINE_SCHEMA_PATH)}
data-test-subj="EngineSchemaLink"
>
- {SCHEMA_TITLE}
- {/* TODO: Engine schema warning icon */}
+
+ {SCHEMA_TITLE}
+
+ {hasUnconfirmedSchemaFields && (
+
+ )}
+ {hasSchemaConflicts && (
+
+ )}
+
+
)}
{canViewEngineCrawler && !isMetaEngine && !isSampleEngine && (
@@ -171,8 +177,33 @@ export const EngineNav: React.FC = () => {
to={getAppSearchUrl(engineRoute + ENGINE_RELEVANCE_TUNING_PATH)}
data-test-subj="EngineRelevanceTuningLink"
>
- {RELEVANCE_TUNING_TITLE}
- {/* TODO: invalid boosts error icon */}
+
+ {RELEVANCE_TUNING_TITLE}
+
+ {invalidBoosts && (
+
+ )}
+ {unsearchedUnconfirmedFields && (
+
+ )}
+
+
)}
{canManageEngineSynonyms && (
diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_router.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_router.test.tsx
new file mode 100644
index 0000000000000..e38381cad32ba
--- /dev/null
+++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_router.test.tsx
@@ -0,0 +1,81 @@
+/*
+ * 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__/react_router_history.mock';
+import { unmountHandler } from '../../../__mocks__/shallow_useeffect.mock';
+import { setMockValues, setMockActions } from '../../../__mocks__/kea.mock';
+
+import React from 'react';
+import { shallow } from 'enzyme';
+import { Switch, Redirect, useParams } from 'react-router-dom';
+
+jest.mock('../../../shared/flash_messages', () => ({
+ setQueuedErrorMessage: jest.fn(),
+}));
+import { setQueuedErrorMessage } from '../../../shared/flash_messages';
+
+import { EngineRouter } from './';
+
+describe('EngineRouter', () => {
+ const values = { dataLoading: false, engineNotFound: false, myRole: {} };
+ const actions = { setEngineName: jest.fn(), initializeEngine: jest.fn(), clearEngine: jest.fn() };
+
+ beforeEach(() => {
+ setMockValues(values);
+ setMockActions(actions);
+ });
+
+ describe('useEffect', () => {
+ beforeEach(() => {
+ (useParams as jest.Mock).mockReturnValue({ engineName: 'some-engine' });
+ shallow();
+ });
+
+ it('sets engineName based on the current route parameters', () => {
+ expect(actions.setEngineName).toHaveBeenCalledWith('some-engine');
+ });
+
+ it('initializes/fetches engine API data', () => {
+ expect(actions.initializeEngine).toHaveBeenCalled();
+ });
+
+ it('clears engine on unmount', () => {
+ unmountHandler();
+ expect(actions.clearEngine).toHaveBeenCalled();
+ });
+ });
+
+ it('redirects to engines list and flashes an error if the engine param was not found', () => {
+ (useParams as jest.Mock).mockReturnValue({ engineName: '404-engine' });
+ setMockValues({ ...values, engineNotFound: true });
+ const wrapper = shallow();
+
+ expect(wrapper.find(Redirect).prop('to')).toEqual('/engines');
+ expect(setQueuedErrorMessage).toHaveBeenCalledWith(
+ "No engine with name '404-engine' could be found."
+ );
+ });
+
+ it('does not render if async data is still loading', () => {
+ setMockValues({ ...values, dataLoading: true });
+ const wrapper = shallow();
+ expect(wrapper.isEmptyRender()).toBe(true);
+ });
+
+ it('renders a default engine overview', () => {
+ const wrapper = shallow();
+
+ expect(wrapper.find(Switch)).toHaveLength(1);
+ expect(wrapper.find('[data-test-subj="EngineOverviewTODO"]')).toHaveLength(1);
+ });
+
+ it('renders an analytics view', () => {
+ setMockValues({ myRole: { canViewEngineAnalytics: true } });
+ const wrapper = shallow();
+
+ expect(wrapper.find('[data-test-subj="AnalyticsTODO"]')).toHaveLength(1);
+ });
+});
diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_router.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_router.tsx
new file mode 100644
index 0000000000000..3e6856771f7d9
--- /dev/null
+++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_router.tsx
@@ -0,0 +1,105 @@
+/*
+ * 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 { Route, Switch, Redirect, useParams } from 'react-router-dom';
+import { useValues, useActions } from 'kea';
+
+import { i18n } from '@kbn/i18n';
+
+import { SetAppSearchChrome as SetPageChrome } from '../../../shared/kibana_chrome';
+import { setQueuedErrorMessage } from '../../../shared/flash_messages';
+import { AppLogic } from '../../app_logic';
+
+// TODO: Uncomment and add more routes as we migrate them
+import {
+ ENGINES_PATH,
+ ENGINE_PATH,
+ ENGINE_ANALYTICS_PATH,
+ // ENGINE_DOCUMENTS_PATH,
+ // ENGINE_SCHEMA_PATH,
+ // ENGINE_CRAWLER_PATH,
+ // META_ENGINE_SOURCE_ENGINES_PATH,
+ // ENGINE_RELEVANCE_TUNING_PATH,
+ // ENGINE_SYNONYMS_PATH,
+ // ENGINE_CURATIONS_PATH,
+ // ENGINE_RESULT_SETTINGS_PATH,
+ // ENGINE_SEARCH_UI_PATH,
+ // ENGINE_API_LOGS_PATH,
+} from '../../routes';
+import { ENGINES_TITLE } from '../engines';
+import {
+ OVERVIEW_TITLE,
+ ANALYTICS_TITLE,
+ // DOCUMENTS_TITLE,
+ // SCHEMA_TITLE,
+ // CRAWLER_TITLE,
+ // RELEVANCE_TUNING_TITLE,
+ // SYNONYMS_TITLE,
+ // CURATIONS_TITLE,
+ // RESULT_SETTINGS_TITLE,
+ // SEARCH_UI_TITLE,
+ // API_LOGS_TITLE,
+} from './constants';
+
+import { EngineLogic } from './';
+
+export const EngineRouter: React.FC = () => {
+ const {
+ myRole: {
+ canViewEngineAnalytics,
+ // canViewEngineDocuments,
+ // canViewEngineSchema,
+ // canViewEngineCrawler,
+ // canViewMetaEngineSourceEngines,
+ // canManageEngineSynonyms,
+ // canManageEngineCurations,
+ // canManageEngineRelevanceTuning,
+ // canManageEngineResultSettings,
+ // canManageEngineSearchUi,
+ // canViewEngineApiLogs,
+ },
+ } = useValues(AppLogic);
+
+ const { dataLoading, engineNotFound } = useValues(EngineLogic);
+ const { setEngineName, initializeEngine, clearEngine } = useActions(EngineLogic);
+
+ const { engineName } = useParams() as { engineName: string };
+ const engineBreadcrumb = [ENGINES_TITLE, engineName];
+
+ useEffect(() => {
+ setEngineName(engineName);
+ initializeEngine();
+ return clearEngine;
+ }, [engineName]);
+
+ if (engineNotFound) {
+ setQueuedErrorMessage(
+ i18n.translate('xpack.enterpriseSearch.appSearch.engine.notFound', {
+ defaultMessage: "No engine with name '{engineName}' could be found.",
+ values: { engineName },
+ })
+ );
+ return ;
+ }
+
+ if (dataLoading) return null;
+
+ return (
+
+ {canViewEngineAnalytics && (
+
+
+ Just testing right now
+
+ )}
+
+
+ Overview
+
+
+ );
+};
diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/index.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/index.ts
index 3d8f343312cc6..4e7d81f73fb8d 100644
--- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/index.ts
+++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/index.ts
@@ -4,5 +4,6 @@
* you may not use this file except in compliance with the Elastic License.
*/
-export { EngineRouter, EngineNav } from './engine_nav';
+export { EngineRouter } from './engine_router';
+export { EngineNav } from './engine_nav';
export { EngineLogic } from './engine_logic';
diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/flash_messages/index.ts b/x-pack/plugins/enterprise_search/public/applications/shared/flash_messages/index.ts
index 8792c26f9bad4..a109640f09bbe 100644
--- a/x-pack/plugins/enterprise_search/public/applications/shared/flash_messages/index.ts
+++ b/x-pack/plugins/enterprise_search/public/applications/shared/flash_messages/index.ts
@@ -7,4 +7,9 @@
export { FlashMessages } from './flash_messages';
export { FlashMessagesLogic, IFlashMessage, mountFlashMessagesLogic } from './flash_messages_logic';
export { flashAPIErrors } from './handle_api_errors';
-export { setSuccessMessage, setErrorMessage, setQueuedSuccessMessage } from './set_message_helpers';
+export {
+ setSuccessMessage,
+ setErrorMessage,
+ setQueuedSuccessMessage,
+ setQueuedErrorMessage,
+} from './set_message_helpers';
diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/flash_messages/set_message_helpers.test.ts b/x-pack/plugins/enterprise_search/public/applications/shared/flash_messages/set_message_helpers.test.ts
index 46027fdfb22b1..c5ee8200c490d 100644
--- a/x-pack/plugins/enterprise_search/public/applications/shared/flash_messages/set_message_helpers.test.ts
+++ b/x-pack/plugins/enterprise_search/public/applications/shared/flash_messages/set_message_helpers.test.ts
@@ -15,6 +15,7 @@ import {
setSuccessMessage,
setErrorMessage,
setQueuedSuccessMessage,
+ setQueuedErrorMessage,
} from './';
describe('Flash Message Helpers', () => {
@@ -56,4 +57,15 @@ describe('Flash Message Helpers', () => {
},
]);
});
+
+ it('setQueuedErrorMessage()', () => {
+ setQueuedErrorMessage(message);
+
+ expect(FlashMessagesLogic.values.queuedMessages).toEqual([
+ {
+ message,
+ type: 'error',
+ },
+ ]);
+ });
});
diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/flash_messages/set_message_helpers.ts b/x-pack/plugins/enterprise_search/public/applications/shared/flash_messages/set_message_helpers.ts
index 6abb540b7c14b..cb73d54fd7b1e 100644
--- a/x-pack/plugins/enterprise_search/public/applications/shared/flash_messages/set_message_helpers.ts
+++ b/x-pack/plugins/enterprise_search/public/applications/shared/flash_messages/set_message_helpers.ts
@@ -26,3 +26,10 @@ export const setQueuedSuccessMessage = (message: string) => {
message,
});
};
+
+export const setQueuedErrorMessage = (message: string) => {
+ FlashMessagesLogic.actions.setQueuedMessages({
+ type: 'error',
+ message,
+ });
+};
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 3bfe8abf8a2df..b7009c1b76fbc 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
@@ -6,7 +6,7 @@
import { MockRouter, mockRequestHandler, mockDependencies } from '../../__mocks__';
-import { registerEnginesRoute } from './engines';
+import { registerEnginesRoutes } from './engines';
describe('engine routes', () => {
describe('GET /api/app_search/engines', () => {
@@ -31,7 +31,7 @@ describe('engine routes', () => {
payload: 'query',
});
- registerEnginesRoute({
+ registerEnginesRoutes({
...mockDependencies,
router: mockRouter.router,
});
@@ -107,4 +107,30 @@ describe('engine routes', () => {
});
});
});
+
+ describe('GET /api/app_search/engines/{name}', () => {
+ let mockRouter: MockRouter;
+
+ beforeEach(() => {
+ jest.clearAllMocks();
+ mockRouter = new MockRouter({
+ method: 'get',
+ path: '/api/app_search/engines/{name}',
+ payload: 'params',
+ });
+
+ registerEnginesRoutes({
+ ...mockDependencies,
+ router: mockRouter.router,
+ });
+ });
+
+ it('creates a request to enterprise search', () => {
+ mockRouter.callRoute({ params: { name: 'some-engine' } });
+
+ expect(mockRequestHandler.createRequest).toHaveBeenCalledWith({
+ path: '/as/engines/some-engine/details',
+ });
+ });
+ });
});
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 6cbd60e494fe3..2c4e235556ae3 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
@@ -14,7 +14,7 @@ interface EnginesResponse {
meta: { page: { total_results: number } };
}
-export function registerEnginesRoute({
+export function registerEnginesRoutes({
router,
enterpriseSearchRequestHandler,
}: RouteDependencies) {
@@ -43,4 +43,21 @@ export function registerEnginesRoute({
})(context, request, response);
}
);
+
+ // Single engine endpoints
+ router.get(
+ {
+ path: '/api/app_search/engines/{name}',
+ validate: {
+ params: schema.object({
+ name: schema.string(),
+ }),
+ },
+ },
+ async (context, request, response) => {
+ return enterpriseSearchRequestHandler.createRequest({
+ path: `/as/engines/${request.params.name}/details`,
+ })(context, request, response);
+ }
+ );
}
diff --git a/x-pack/plugins/enterprise_search/server/routes/app_search/index.ts b/x-pack/plugins/enterprise_search/server/routes/app_search/index.ts
index 7ce3ee9654f42..faf74203cf17d 100644
--- a/x-pack/plugins/enterprise_search/server/routes/app_search/index.ts
+++ b/x-pack/plugins/enterprise_search/server/routes/app_search/index.ts
@@ -6,12 +6,12 @@
import { RouteDependencies } from '../../plugin';
-import { registerEnginesRoute } from './engines';
+import { registerEnginesRoutes } from './engines';
import { registerCredentialsRoutes } from './credentials';
import { registerSettingsRoutes } from './settings';
export const registerAppSearchRoutes = (dependencies: RouteDependencies) => {
- registerEnginesRoute(dependencies);
+ registerEnginesRoutes(dependencies);
registerCredentialsRoutes(dependencies);
registerSettingsRoutes(dependencies);
};