Skip to content

Commit

Permalink
[Workplace Search] Enables external SharePoint Online and custom Shar…
Browse files Browse the repository at this point in the history
…ePoint Server connectors (#126172)

This adds the ability to add and manage an External SharePoint Online connector and a Custom SharePoint Server connector via Kibana.

Co-authored-by: Byron Hulcher <byron.hulcher@elastic.co>
  • Loading branch information
sphilipse and Byron Hulcher authored Mar 2, 2022
1 parent 0bb0211 commit 5023a03
Show file tree
Hide file tree
Showing 45 changed files with 1,980 additions and 539 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import { groups } from './groups.mock';

import { IndexingRule } from '../types';
import { SourceConfigData } from '../views/content_sources/components/add_source/add_source_logic';
import { staticSourceData } from '../views/content_sources/source_data';
import { mergeServerAndStaticData } from '../views/content_sources/sources_logic';

Expand Down Expand Up @@ -339,23 +340,23 @@ export const mergedConfiguredSources = mergeServerAndStaticData(
contentSources
);

export const sourceConfigData = {
export const sourceConfigData: SourceConfigData = {
serviceType: 'confluence_cloud',
name: 'Confluence',
configured: true,
needsPermissions: true,
accountContextOnly: false,
supportedByLicense: true,
privateSourcesEnabled: false,
categories: ['wiki', 'atlassian', 'intranet'],
configuredFields: {
isOauth1: false,
clientId: 'CyztADsSECRETCSAUCEh1a',
clientSecret: 'GSjJxqSECRETCSAUCEksHk',
baseUrl: 'https://mine.atlassian.net',
privateKey: '-----BEGIN PRIVATE KEY-----\nkeykeykeykey==\n-----END PRIVATE KEY-----\n',
publicKey: '-----BEGIN PUBLIC KEY-----\nkeykeykeykey\n-----END PUBLIC KEY-----\n',
consumerKey: 'elastic_enterprise_search_123',
apiKey: 'asdf1234',
url: 'https://www.elastic.co',
},
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import oneDrive from './onedrive.svg';
import salesforce from './salesforce.svg';
import serviceNow from './servicenow.svg';
import sharePoint from './sharepoint.svg';
import sharePointServer from './sharepoint_server.svg';
import slack from './slack.svg';
import zendesk from './zendesk.svg';

Expand All @@ -29,6 +30,8 @@ export const images = {
confluenceServer: confluence,
custom,
dropbox,
// TODO: For now external sources are all SharePoint. When this is no longer the case, this needs to be dynamic.
external: sharePoint,
github,
githubEnterpriseServer: github,
githubViaApp: github,
Expand All @@ -44,6 +47,7 @@ export const images = {
salesforceSandbox: salesforce,
serviceNow,
sharePoint,
sharePointServer,
slack,
zendesk,
} as { [key: string]: string };
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,10 @@ export const SOURCE_NAMES = {
'xpack.enterpriseSearch.workplaceSearch.sources.sourceNames.sharePoint',
{ defaultMessage: 'SharePoint Online' }
),
SHAREPOINT_SERVER: i18n.translate(
'xpack.enterpriseSearch.workplaceSearch.sources.sourceNames.sharePointServer',
{ defaultMessage: 'SharePoint Server' }
),
SLACK: i18n.translate('xpack.enterpriseSearch.workplaceSearch.sources.sourceNames.slack', {
defaultMessage: 'Slack',
}),
Expand Down Expand Up @@ -357,6 +361,7 @@ export const GITHUB_VIA_APP_SERVICE_TYPE = 'github_via_app';
export const GITHUB_ENTERPRISE_SERVER_VIA_APP_SERVICE_TYPE = 'github_enterprise_server_via_app';

export const CUSTOM_SERVICE_TYPE = 'custom';
export const EXTERNAL_SERVICE_TYPE = 'external';

export const WORKPLACE_SEARCH_URL_PREFIX = '/app/enterprise_search/workplace_search';

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,6 @@

import { generatePath } from 'react-router-dom';

import {
GITHUB_VIA_APP_SERVICE_TYPE,
GITHUB_ENTERPRISE_SERVER_VIA_APP_SERVICE_TYPE,
} from './constants';

export const SETUP_GUIDE_PATH = '/setup_guide';

export const NOT_FOUND_PATH = '/404';
Expand Down Expand Up @@ -40,25 +35,7 @@ export const PRIVATE_SOURCES_PATH = `${PERSONAL_PATH}${SOURCES_PATH}`;

export const SOURCE_ADDED_PATH = `${SOURCES_PATH}/added`;
export const ADD_SOURCE_PATH = `${SOURCES_PATH}/add`;
export const ADD_BOX_PATH = `${SOURCES_PATH}/add/box`;
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_GITHUB_VIA_APP_PATH = `${SOURCES_PATH}/add/${GITHUB_VIA_APP_SERVICE_TYPE}`;
export const ADD_GITHUB_ENTERPRISE_SERVER_VIA_APP_PATH = `${SOURCES_PATH}/add/${GITHUB_ENTERPRISE_SERVER_VIA_APP_SERVICE_TYPE}`;
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_ONEDRIVE_PATH = `${SOURCES_PATH}/add/one_drive`;
export const ADD_SALESFORCE_PATH = `${SOURCES_PATH}/add/salesforce`;
export const ADD_SALESFORCE_SANDBOX_PATH = `${SOURCES_PATH}/add/salesforce_sandbox`;
export const ADD_SERVICENOW_PATH = `${SOURCES_PATH}/add/servicenow`;
export const ADD_SHAREPOINT_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_EXTERNAL_PATH = `${SOURCES_PATH}/add/external`;
export const ADD_CUSTOM_PATH = `${SOURCES_PATH}/add/custom`;

export const PERSONAL_SETTINGS_PATH = `${PERSONAL_PATH}/settings`;
Expand All @@ -83,24 +60,6 @@ export const ORG_SETTINGS_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_BOX_PATH = `${ORG_SETTINGS_CONNECTORS_PATH}/box/edit`;
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_ONEDRIVE_PATH = `${ORG_SETTINGS_CONNECTORS_PATH}/one_drive/edit`;
export const EDIT_SALESFORCE_PATH = `${ORG_SETTINGS_CONNECTORS_PATH}/salesforce/edit`;
export const EDIT_SALESFORCE_SANDBOX_PATH = `${ORG_SETTINGS_CONNECTORS_PATH}/salesforce_sandbox/edit`;
export const EDIT_SERVICENOW_PATH = `${ORG_SETTINGS_CONNECTORS_PATH}/servicenow/edit`;
export const EDIT_SHAREPOINT_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 getContentSourcePath = (
path: string,
Expand All @@ -118,3 +77,6 @@ export const getReindexJobRoute = (
isOrganization: boolean
) =>
getSourcesPath(generatePath(REINDEX_JOB_PATH, { sourceId, activeReindexJobId }), isOrganization);
export const getAddPath = (serviceType: string): string => `${SOURCES_PATH}/add/${serviceType}`;
export const getEditPath = (serviceType: string): string =>
`${ORG_SETTINGS_CONNECTORS_PATH}/${serviceType}/edit`;
Original file line number Diff line number Diff line change
Expand Up @@ -66,23 +66,27 @@ export interface Configuration {
needsConfiguration?: boolean;
hasOauthRedirect: boolean;
baseUrlTitle?: string;
helpText: string;
helpText?: string;
documentationUrl: string;
applicationPortalUrl?: string;
applicationLinkTitle?: string;
githubRepository?: string;
}

export interface SourceDataItem {
name: string;
iconName: string;
categories?: string[];
serviceType: string;
configuration: Configuration;
configured?: boolean;
connected?: boolean;
features?: Features;
objTypes?: string[];
addPath: string;
editPath?: string; // undefined for GitHub apps, as they are configured on a source level, and don't use a connector where you can edit the configuration
accountContextOnly: boolean;
internalConnectorAvailable?: boolean;
externalConnectorAvailable?: boolean;
customConnectorAvailable?: boolean;
}

export interface ContentSource {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import { SourceDataItem } from '../types';

export const hasMultipleConnectorOptions = ({
internalConnectorAvailable,
externalConnectorAvailable,
customConnectorAvailable,
}: SourceDataItem) =>
[externalConnectorAvailable, internalConnectorAvailable, customConnectorAvailable].filter(
(available) => !!available
).length > 1;
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,5 @@ export { mimeType } from './mime_types';
export { readUploadedFileAsBase64 } from './read_uploaded_file_as_base64';
export { readUploadedFileAsText } from './read_uploaded_file_as_text';
export { handlePrivateKeyUpload } from './handle_private_key_upload';
export { hasMultipleConnectorOptions } from './has_multiple_connector_options';
export { isNotNullish } from './is_not_nullish';
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

export function isNotNullish<T>(value: T | null | undefined): value is T {
return value !== null && value !== undefined;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import '../../../../../__mocks__/shallow_useeffect.mock';
import { setMockValues } from '../../../../../__mocks__/kea_logic';
import { sourceConfigData } from '../../../../__mocks__/content_sources.mock';

import React from 'react';

import { shallow } from 'enzyme';

import {
WorkplaceSearchPageTemplate,
PersonalDashboardLayout,
} from '../../../../components/layout';
import { staticSourceData } from '../../source_data';

import { AddCustomSource } from './add_custom_source';
import { AddCustomSourceSteps } from './add_custom_source_logic';
import { ConfigureCustom } from './configure_custom';
import { SaveCustom } from './save_custom';

describe('AddCustomSource', () => {
const props = {
sourceData: staticSourceData[0],
initialValues: undefined,
};

const values = {
sourceConfigData,
isOrganization: true,
};

beforeEach(() => {
setMockValues({ ...values });
});

it('renders', () => {
const wrapper = shallow(<AddCustomSource {...props} />);

expect(wrapper.find(WorkplaceSearchPageTemplate)).toHaveLength(1);
});

it('should show correct layout for personal dashboard', () => {
setMockValues({ isOrganization: false });
const wrapper = shallow(<AddCustomSource {...props} />);

expect(wrapper.find(WorkplaceSearchPageTemplate)).toHaveLength(0);
expect(wrapper.find(PersonalDashboardLayout)).toHaveLength(1);
});

it('should show Configure Custom for custom configuration step', () => {
setMockValues({ currentStep: AddCustomSourceSteps.ConfigureCustomStep });
const wrapper = shallow(<AddCustomSource {...props} />);

expect(wrapper.find(ConfigureCustom)).toHaveLength(1);
});

it('should show Save Custom for save custom step', () => {
setMockValues({ currentStep: AddCustomSourceSteps.SaveCustomStep });
const wrapper = shallow(<AddCustomSource {...props} />);

expect(wrapper.find(SaveCustom)).toHaveLength(1);
});
});
Original file line number Diff line number Diff line change
@@ -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
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import React from 'react';

import { useValues } from 'kea';

import { AppLogic } from '../../../../app_logic';
import {
WorkplaceSearchPageTemplate,
PersonalDashboardLayout,
} from '../../../../components/layout';
import { NAV } from '../../../../constants';

import { SourceDataItem } from '../../../../types';

import { AddCustomSourceLogic, AddCustomSourceSteps } from './add_custom_source_logic';
import { ConfigureCustom } from './configure_custom';
import { SaveCustom } from './save_custom';

import './add_source.scss';

interface Props {
sourceData: SourceDataItem;
initialValue?: string;
}
export const AddCustomSource: React.FC<Props> = ({ sourceData, initialValue = '' }) => {
const addCustomSourceLogic = AddCustomSourceLogic({ sourceData, initialValue });
const { currentStep } = useValues(addCustomSourceLogic);
const { isOrganization } = useValues(AppLogic);

const Layout = isOrganization ? WorkplaceSearchPageTemplate : PersonalDashboardLayout;

return (
<Layout pageChrome={[NAV.SOURCES, NAV.ADD_SOURCE, sourceData.name || '...']}>
{currentStep === AddCustomSourceSteps.ConfigureCustomStep && <ConfigureCustom />}
{currentStep === AddCustomSourceSteps.SaveCustomStep && <SaveCustom />}
</Layout>
);
};
Loading

0 comments on commit 5023a03

Please sign in to comment.