diff --git a/x-pack/plugins/enterprise_search/common/version.ts b/x-pack/plugins/enterprise_search/common/version.ts
new file mode 100644
index 0000000000000..e29ad8a9f866b
--- /dev/null
+++ b/x-pack/plugins/enterprise_search/common/version.ts
@@ -0,0 +1,11 @@
+/*
+ * 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 { SemVer } from 'semver';
+import pkg from '../../../../package.json';
+
+export const CURRENT_VERSION = new SemVer(pkg.version as string);
+export const CURRENT_MAJOR_VERSION = CURRENT_VERSION.major;
diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/error_state/error_state.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/error_state/error_state.tsx
index e1114986d2244..53f3a7a274429 100644
--- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/error_state/error_state.tsx
+++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/error_state/error_state.tsx
@@ -4,6 +4,8 @@
* you may not use this file except in compliance with the Elastic License.
*/
+// TODO: Remove EuiPage & EuiPageBody before exposing full app
+
import React from 'react';
import { EuiPage, EuiPageBody, EuiPageContent } from '@elastic/eui';
diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/layout/index.ts b/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/layout/index.ts
new file mode 100644
index 0000000000000..41861a8ee2dc5
--- /dev/null
+++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/layout/index.ts
@@ -0,0 +1,7 @@
+/*
+ * 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 { WorkplaceSearchNav } from './nav';
diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/layout/nav.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/layout/nav.test.tsx
new file mode 100644
index 0000000000000..0e85d8467cff0
--- /dev/null
+++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/layout/nav.test.tsx
@@ -0,0 +1,22 @@
+/*
+ * 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 React from 'react';
+import { shallow } from 'enzyme';
+
+import { SideNav, SideNavLink } from '../../../shared/layout';
+import { WorkplaceSearchNav } from './';
+
+describe('WorkplaceSearchNav', () => {
+ it('renders', () => {
+ const wrapper = shallow();
+
+ expect(wrapper.find(SideNav)).toHaveLength(1);
+ expect(wrapper.find(SideNavLink).first().prop('to')).toEqual('/');
+ expect(wrapper.find(SideNavLink).last().prop('to')).toEqual('http://localhost:3002/ws/search');
+ });
+});
diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/layout/nav.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/layout/nav.tsx
new file mode 100644
index 0000000000000..8f8edc61620ab
--- /dev/null
+++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/layout/nav.tsx
@@ -0,0 +1,74 @@
+/*
+ * 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, { useContext } from 'react';
+import { i18n } from '@kbn/i18n';
+
+import { EuiSpacer } from '@elastic/eui';
+
+import { WORKPLACE_SEARCH_PLUGIN } from '../../../../../common/constants';
+import { KibanaContext, IKibanaContext } from '../../../index';
+import { SideNav, SideNavLink } from '../../../shared/layout';
+
+import {
+ ORG_SOURCES_PATH,
+ SOURCES_PATH,
+ SECURITY_PATH,
+ ROLE_MAPPINGS_PATH,
+ GROUPS_PATH,
+ ORG_SETTINGS_PATH,
+} from '../../routes';
+
+export const WorkplaceSearchNav: React.FC = () => {
+ const { enterpriseSearchUrl } = useContext(KibanaContext) as IKibanaContext;
+ const legacyUrl = (path: string) => `${enterpriseSearchUrl}/ws#${path}`;
+
+ // TODO: icons
+ return (
+
+
+ {i18n.translate('xpack.enterpriseSearch.workplaceSearch.nav.overview', {
+ defaultMessage: 'Overview',
+ })}
+
+
+ {i18n.translate('xpack.enterpriseSearch.workplaceSearch.nav.sources', {
+ defaultMessage: 'Sources',
+ })}
+
+
+ {i18n.translate('xpack.enterpriseSearch.workplaceSearch.nav.groups', {
+ defaultMessage: 'Groups',
+ })}
+
+
+ {i18n.translate('xpack.enterpriseSearch.workplaceSearch.nav.roleMappings', {
+ defaultMessage: 'Role Mappings',
+ })}
+
+
+ {i18n.translate('xpack.enterpriseSearch.workplaceSearch.nav.security', {
+ defaultMessage: 'Security',
+ })}
+
+
+ {i18n.translate('xpack.enterpriseSearch.workplaceSearch.nav.settings', {
+ defaultMessage: 'Settings',
+ })}
+
+
+
+ {i18n.translate('xpack.enterpriseSearch.workplaceSearch.nav.personalDashboard', {
+ defaultMessage: 'View my personal dashboard',
+ })}
+
+
+ {i18n.translate('xpack.enterpriseSearch.workplaceSearch.nav.search', {
+ defaultMessage: 'Go to search application',
+ })}
+
+
+ );
+};
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 2c3e78b404d42..b816eb2973207 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
@@ -4,6 +4,8 @@
* you may not use this file except in compliance with the Elastic License.
*/
+// TODO: Remove EuiPage & EuiPageBody before exposing full app
+
import React, { useContext, useEffect } from 'react';
import { EuiPage, EuiPageBody, EuiSpacer } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
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 743080d965c36..a4af405247f83 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
@@ -15,7 +15,7 @@ import { Overview } from './components/overview';
import { WorkplaceSearch } from './';
-describe('Workplace Search Routes', () => {
+describe('Workplace Search', () => {
describe('/', () => {
it('redirects to Setup Guide when enterpriseSearchUrl is not set', () => {
(useContext as jest.Mock).mockImplementationOnce(() => ({ enterpriseSearchUrl: '' }));
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 cfa70ea29eca8..6470a3b78c5f1 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
@@ -5,7 +5,7 @@
*/
import React, { useContext } from 'react';
-import { Route, Redirect } from 'react-router-dom';
+import { Route, Redirect, Switch } from 'react-router-dom';
import { Provider } from 'react-redux';
import { Store } from 'redux';
import { getContext, resetContext } from 'kea';
@@ -15,6 +15,8 @@ resetContext({ createStore: true });
const store = getContext().store as Store;
import { KibanaContext, IKibanaContext } from '../index';
+import { Layout } from '../shared/layout';
+import { WorkplaceSearchNav } from './components/layout/nav';
import { SETUP_GUIDE_PATH } from './routes';
@@ -23,14 +25,39 @@ import { Overview } from './components/overview';
export const WorkplaceSearch: React.FC = () => {
const { enterpriseSearchUrl } = useContext(KibanaContext) as IKibanaContext;
+ if (!enterpriseSearchUrl)
+ return (
+
+
+
+
+
+
+ {/* Kibana displays a blank page on redirect if this isn't included */}
+
+
+ );
+
return (
-
- {!enterpriseSearchUrl ? : }
-
-
-
-
+
+
+
+
+
+
+
+
+ }>
+
+
+ {/* Will replace with groups component subsequent PR */}
+
+
+
+
+
+
);
};
diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/routes.ts b/x-pack/plugins/enterprise_search/public/applications/workplace_search/routes.ts
index d9798d1f30cfc..993a1a378e738 100644
--- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/routes.ts
+++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/routes.ts
@@ -4,9 +4,107 @@
* you may not use this file except in compliance with the Elastic License.
*/
-export const ORG_SOURCES_PATH = '/org/sources';
-export const USERS_PATH = '/org/users';
-export const ORG_SETTINGS_PATH = '/org/settings';
+import { CURRENT_MAJOR_VERSION } from '../../../common/version';
+
export const SETUP_GUIDE_PATH = '/setup_guide';
+export const LEAVE_FEEDBACK_EMAIL = 'support@elastic.co';
+export const LEAVE_FEEDBACK_URL = `mailto:${LEAVE_FEEDBACK_EMAIL}?Subject=Elastic%20Workplace%20Search%20Feedback`;
+
+export const DOCS_PREFIX = `https://www.elastic.co/guide/en/workplace-search/${CURRENT_MAJOR_VERSION}`;
+export const ENT_SEARCH_DOCS_PREFIX = `https://www.elastic.co/guide/en/enterprise-search/${CURRENT_MAJOR_VERSION}`;
+export const DOCUMENT_PERMISSIONS_DOCS_URL = `${DOCS_PREFIX}/workplace-search-sources-document-permissions.html`;
+export const DOCUMENT_PERMISSIONS_SYNC_DOCS_URL = `${DOCUMENT_PERMISSIONS_DOCS_URL}#sources-permissions-synchronizing`;
+export const PRIVATE_SOURCES_DOCS_URL = `${DOCUMENT_PERMISSIONS_DOCS_URL}#sources-permissions-org-private`;
+export const EXTERNAL_IDENTITIES_DOCS_URL = `${DOCS_PREFIX}/workplace-search-external-identities-api.html`;
+export const SECURITY_DOCS_URL = `${DOCS_PREFIX}/workplace-search-security.html`;
+export const SMTP_DOCS_URL = `${DOCS_PREFIX}/workplace-search-smtp-mailer.html`;
+export const CONFLUENCE_DOCS_URL = `${DOCS_PREFIX}/workplace-search-confluence-cloud-connector.html`;
+export const CONFLUENCE_SERVER_DOCS_URL = `${DOCS_PREFIX}/workplace-search-confluence-server-connector.html`;
+export const DROPBOX_DOCS_URL = `${DOCS_PREFIX}/workplace-search-dropbox-connector.html`;
+export const GITHUB_DOCS_URL = `${DOCS_PREFIX}/workplace-search-github-connector.html`;
+export const GITHUB_ENTERPRISE_DOCS_URL = `${DOCS_PREFIX}/workplace-search-github-connector.html`;
+export const GMAIL_DOCS_URL = `${DOCS_PREFIX}/workplace-search-gmail-connector.html`;
+export const GOOGLE_DRIVE_DOCS_URL = `${DOCS_PREFIX}/workplace-search-google-drive-connector.html`;
+export const JIRA_DOCS_URL = `${DOCS_PREFIX}/workplace-search-jira-cloud-connector.html`;
+export const JIRA_SERVER_DOCS_URL = `${DOCS_PREFIX}/workplace-search-jira-server-connector.html`;
+export const ONE_DRIVE_DOCS_URL = `${DOCS_PREFIX}/workplace-search-onedrive-connector.html`;
+export const SALESFORCE_DOCS_URL = `${DOCS_PREFIX}/workplace-search-salesforce-connector.html`;
+export const SERVICE_NOW_DOCS_URL = `${DOCS_PREFIX}/workplace-search-servicenow-connector.html`;
+export const SHARE_POINT_DOCS_URL = `${DOCS_PREFIX}/workplace-search-sharepoint-online-connector.html`;
+export const SLACK_DOCS_URL = `${DOCS_PREFIX}/workplace-search-slack-connector.html`;
+export const ZENDESK_DOCS_URL = `${DOCS_PREFIX}/workplace-search-zendesk-connector.html`;
+export const CUSTOM_SOURCE_DOCS_URL = `${DOCS_PREFIX}/workplace-search-custom-api-sources.html`;
+export const CUSTOM_API_DOCS_URL = `${DOCS_PREFIX}/workplace-search-custom-sources-api.html`;
+export const CUSTOM_API_DOCUMENT_PERMISSIONS_DOCS_URL = `${CUSTOM_SOURCE_DOCS_URL}#custom-api-source-document-level-access-control`;
+export const ENT_SEARCH_LICENSE_MANAGEMENT = `${ENT_SEARCH_DOCS_PREFIX}/license-management.html`;
+
+export const ORG_PATH = '/org';
+
+export const ROLE_MAPPINGS_PATH = `${ORG_PATH}/role-mappings`;
+export const ROLE_MAPPING_PATH = `${ROLE_MAPPINGS_PATH}/:roleId`;
+export const ROLE_MAPPING_NEW_PATH = `${ROLE_MAPPINGS_PATH}/new`;
+
+export const USERS_PATH = `${ORG_PATH}/users`;
+export const SECURITY_PATH = `${ORG_PATH}/security`;
+
+export const GROUPS_PATH = `${ORG_PATH}/groups`;
+export const GROUP_PATH = `${GROUPS_PATH}/:groupId`;
+export const GROUP_SOURCE_PRIORITIZATION_PATH = `${GROUPS_PATH}/:groupId/source-prioritization`;
+
+export const SOURCES_PATH = '/sources';
+export const ORG_SOURCES_PATH = `${ORG_PATH}${SOURCES_PATH}`;
+
+export const SOURCE_ADDED_PATH = `${SOURCES_PATH}/added`;
+export const ADD_SOURCE_PATH = `${SOURCES_PATH}/add`;
+export const ADD_CONFLUENCE_PATH = `${SOURCES_PATH}/add/confluence-cloud`;
+export const ADD_CONFLUENCE_SERVER_PATH = `${SOURCES_PATH}/add/confluence-server`;
+export const ADD_DROPBOX_PATH = `${SOURCES_PATH}/add/dropbox`;
+export const ADD_GITHUB_ENTERPRISE_PATH = `${SOURCES_PATH}/add/github-enterprise-server`;
+export const ADD_GITHUB_PATH = `${SOURCES_PATH}/add/github`;
+export const ADD_GMAIL_PATH = `${SOURCES_PATH}/add/gmail`;
+export const ADD_GOOGLE_DRIVE_PATH = `${SOURCES_PATH}/add/google-drive`;
+export const ADD_JIRA_PATH = `${SOURCES_PATH}/add/jira-cloud`;
+export const ADD_JIRA_SERVER_PATH = `${SOURCES_PATH}/add/jira-server`;
+export const ADD_ONE_DRIVE_PATH = `${SOURCES_PATH}/add/one-drive`;
+export const ADD_SALESFORCE_PATH = `${SOURCES_PATH}/add/salesforce`;
+export const ADD_SERVICE_NOW_PATH = `${SOURCES_PATH}/add/service-now`;
+export const ADD_SHARE_POINT_PATH = `${SOURCES_PATH}/add/share-point`;
+export const ADD_SLACK_PATH = `${SOURCES_PATH}/add/slack`;
+export const ADD_ZENDESK_PATH = `${SOURCES_PATH}/add/zendesk`;
+export const ADD_CUSTOM_PATH = `${SOURCES_PATH}/add/custom`;
+
+export const PERSONAL_SETTINGS_PATH = '/settings';
+
+export const SOURCE_DETAILS_PATH = `${SOURCES_PATH}/:sourceId`;
+export const SOURCE_CONTENT_PATH = `${SOURCES_PATH}/:sourceId/content`;
+export const SOURCE_SCHEMAS_PATH = `${SOURCES_PATH}/:sourceId/schemas`;
+export const SOURCE_DISPLAY_SETTINGS_PATH = `${SOURCES_PATH}/:sourceId/display-settings`;
+export const SOURCE_SETTINGS_PATH = `${SOURCES_PATH}/:sourceId/settings`;
+export const REINDEX_JOB_PATH = `${SOURCES_PATH}/:sourceId/schema-errors/:activeReindexJobId`;
+
+export const DISPLAY_SETTINGS_SEARCH_RESULT_PATH = `${SOURCE_DISPLAY_SETTINGS_PATH}/`;
+export const DISPLAY_SETTINGS_RESULT_DETAIL_PATH = `${SOURCE_DISPLAY_SETTINGS_PATH}/result-detail`;
+
+export const ORG_SETTINGS_PATH = `${ORG_PATH}/settings`;
+export const ORG_SETTINGS_CUSTOMIZE_PATH = `${ORG_SETTINGS_PATH}/customize`;
+export const ORG_SETTINGS_CONNECTORS_PATH = `${ORG_SETTINGS_PATH}/connectors`;
+export const ORG_SETTINGS_OAUTH_APPLICATION_PATH = `${ORG_SETTINGS_PATH}/oauth`;
+export const EDIT_CONFLUENCE_PATH = `${ORG_SETTINGS_CONNECTORS_PATH}/confluence-cloud/edit`;
+export const EDIT_CONFLUENCE_SERVER_PATH = `${ORG_SETTINGS_CONNECTORS_PATH}/confluence-server/edit`;
+export const EDIT_DROPBOX_PATH = `${ORG_SETTINGS_CONNECTORS_PATH}/dropbox/edit`;
+export const EDIT_GITHUB_ENTERPRISE_PATH = `${ORG_SETTINGS_CONNECTORS_PATH}/github-enterprise-server/edit`;
+export const EDIT_GITHUB_PATH = `${ORG_SETTINGS_CONNECTORS_PATH}/github/edit`;
+export const EDIT_GMAIL_PATH = `${ORG_SETTINGS_CONNECTORS_PATH}/gmail/edit`;
+export const EDIT_GOOGLE_DRIVE_PATH = `${ORG_SETTINGS_CONNECTORS_PATH}/google-drive/edit`;
+export const EDIT_JIRA_PATH = `${ORG_SETTINGS_CONNECTORS_PATH}/jira-cloud/edit`;
+export const EDIT_JIRA_SERVER_PATH = `${ORG_SETTINGS_CONNECTORS_PATH}/jira-server/edit`;
+export const EDIT_ONE_DRIVE_PATH = `${ORG_SETTINGS_CONNECTORS_PATH}/one-drive/edit`;
+export const EDIT_SALESFORCE_PATH = `${ORG_SETTINGS_CONNECTORS_PATH}/salesforce/edit`;
+export const EDIT_SERVICE_NOW_PATH = `${ORG_SETTINGS_CONNECTORS_PATH}/service-now/edit`;
+export const EDIT_SHARE_POINT_PATH = `${ORG_SETTINGS_CONNECTORS_PATH}/share-point/edit`;
+export const EDIT_SLACK_PATH = `${ORG_SETTINGS_CONNECTORS_PATH}/slack/edit`;
+export const EDIT_ZENDESK_PATH = `${ORG_SETTINGS_CONNECTORS_PATH}/zendesk/edit`;
+export const EDIT_CUSTOM_PATH = `${ORG_SETTINGS_CONNECTORS_PATH}/custom/edit`;
+
export const getSourcePath = (sourceId: string): string => `${ORG_SOURCES_PATH}/${sourceId}`;