From dd1da2c292dccb50043a7989a2b0e45c06317141 Mon Sep 17 00:00:00 2001 From: scottybollinger Date: Wed, 18 Nov 2020 16:22:24 -0600 Subject: [PATCH 01/11] Initial copy/paste of components MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Changes for pre-commit hooks were: - Linting - Lodash imports - changed enum names in add_source because there were collistions with component names. So SaveConfig becomes SaveConfigStep because there is a component by the same name - replaced apostrophe’s with ‘'’ per lint rule Finally, the linter didn’t like this expression: asOauthRedirect ? onOauthFormSubmit() : onCredentialsFormSubmit(); … so I changed it to: const onSubmit = hasOauthRedirect ? onOauthFormSubmit : onCredentialsFormSubmit; onSubmit(); --- .../components/add_source/add_source.tsx | 260 ++++++++++++++++++ .../add_source/add_source_header.tsx | 57 ++++ .../components/add_source/add_source_list.tsx | 158 +++++++++++ .../add_source/available_sources_list.tsx | 97 +++++++ .../add_source/config_completed.tsx | 111 ++++++++ .../add_source/config_docs_links.tsx | 38 +++ .../add_source/configuration_intro.tsx | 131 +++++++++ .../add_source/configure_custom.tsx | 85 ++++++ .../components/add_source/configure_oauth.tsx | 104 +++++++ .../add_source/configured_sources_list.tsx | 120 ++++++++ .../add_source/connect_instance.tsx | 254 +++++++++++++++++ .../components/add_source/index.ts | 8 + .../components/add_source/re_authenticate.tsx | 76 +++++ .../components/add_source/save_config.tsx | 218 +++++++++++++++ .../components/add_source/save_custom.tsx | 160 +++++++++++ .../components/add_source/source_features.tsx | 223 +++++++++++++++ 16 files changed, 2100 insertions(+) create mode 100644 x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/add_source.tsx create mode 100644 x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/add_source_header.tsx create mode 100644 x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/add_source_list.tsx create mode 100644 x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/available_sources_list.tsx create mode 100644 x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/config_completed.tsx create mode 100644 x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/config_docs_links.tsx create mode 100644 x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/configuration_intro.tsx create mode 100644 x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/configure_custom.tsx create mode 100644 x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/configure_oauth.tsx create mode 100644 x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/configured_sources_list.tsx create mode 100644 x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/connect_instance.tsx create mode 100644 x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/index.ts create mode 100644 x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/re_authenticate.tsx create mode 100644 x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/save_config.tsx create mode 100644 x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/save_custom.tsx create mode 100644 x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/source_features.tsx diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/add_source.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/add_source.tsx new file mode 100644 index 00000000000000..6f2824a418681a --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/add_source.tsx @@ -0,0 +1,260 @@ +/* + * 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, useState } from 'react'; + +import { History } from 'history'; +import { useActions, useValues } from 'kea'; +import { useHistory } from 'react-router-dom'; + +import FlashMessages from 'shared/components/FlashMessages'; +import { AppLogic } from 'workplace_search/App/AppLogic'; +import { SidebarNavigation, Loading, AppView } from 'workplace_search/components'; +import { CUSTOM_SERVICE_TYPE } from 'workplace_search/constants'; +import { staticSourceData } from 'workplace_search/ContentSources/sourceData'; +import { SourceLogic } from 'workplace_search/ContentSources/SourceLogic'; +import { SourceDataItem, FeatureIds } from 'workplace_search/types'; +import { + ADD_SOURCE_PATH, + SOURCE_ADDED_PATH, + getSourcesPath, +} from 'workplace_search/utils/routePaths'; + +import { AddSourceHeader } from './AddSourceHeader'; +import { ConfigCompleted } from './ConfigCompleted'; +import { ConfigurationIntro } from './ConfigurationIntro'; +import { ConfigureCustom } from './ConfigureCustom'; +import { ConfigureOauth } from './ConfigureOauth'; +import { ConnectInstance } from './ConnectInstance'; +import { ReAuthenticate } from './ReAuthenticate'; +import { SaveConfig } from './SaveConfig'; +import { SaveCustom } from './SaveCustom'; + +enum Steps { + ConfigIntroStep = 'Config Intro', + SaveConfigStep = 'Save Config', + ConfigCompletedStep = 'Config Completed', + ConnectInstanceStep = 'Connect Instance', + ConfigureCustomStep = 'Configure Custom', + ConfigureOauthStep = 'Configure Oauth', + SaveCustomStep = 'Save Custom', + ReAuthenticateStep = 'ReAuthenticate', +} + +interface AddSourceProps { + sourceIndex: number; + connect?: boolean; + configure?: boolean; + reAuthenticate?: boolean; +} + +export const AddSource: React.FC = ({ + sourceIndex, + connect, + configure, + reAuthenticate, +}) => { + const history = useHistory() as History; + const { + getSourceConfigData, + saveSourceConfig, + createContentSource, + resetSourceState, + } = useActions(SourceLogic); + const { + sourceConfigData: { + name, + categories, + needsPermissions, + accountContextOnly, + privateSourcesEnabled, + }, + dataLoading, + flashMessages, + newCustomSource, + } = useValues(SourceLogic); + + const { + serviceType, + configuration, + features, + objTypes, + sourceDescription, + connectStepDescription, + addPath, + } = staticSourceData[sourceIndex] as SourceDataItem; + + const { isOrganization } = useValues(AppLogic); + + useEffect(() => { + getSourceConfigData(serviceType); + return resetSourceState; + }, []); + + const breadcrumbs = { + topLevelPath: getSourcesPath(ADD_SOURCE_PATH, isOrganization), + topLevelName: '← Back to sources', + }; + + const isCustom = serviceType === CUSTOM_SERVICE_TYPE; + const isRemote = features?.platinumPrivateContext.includes(FeatureIds.Remote); + + const getFirstStep = () => { + if (isCustom) return Steps.ConfigureCustomStep; + if (connect) return Steps.ConnectInstanceStep; + if (configure) return Steps.ConfigureOauthStep; + if (reAuthenticate) return Steps.ReAuthenticateStep; + return Steps.ConfigIntroStep; + }; + + const [currentStep, setStep] = useState(getFirstStep()); + + if (dataLoading) return ; + + const goToConfigurationIntro = () => setStep(Steps.ConfigIntroStep); + const goToSaveConfig = () => setStep(Steps.SaveConfigStep); + const setConfigCompletedStep = () => setStep(Steps.ConfigCompletedStep); + const goToConfigCompleted = () => saveSourceConfig(false, setConfigCompletedStep); + + const goToConnectInstance = () => { + setStep(Steps.ConnectInstanceStep); + history.push(`${getSourcesPath(addPath, isOrganization)}/connect`); + }; + + const saveCustomSuccess = () => setStep(Steps.SaveCustomStep); + const goToSaveCustom = () => createContentSource(CUSTOM_SERVICE_TYPE, saveCustomSuccess); + + const goToFormSourceCreated = (sourceName) => { + history.push(`${getSourcesPath(SOURCE_ADDED_PATH, isOrganization)}/?name=${sourceName}`); + }; + + const sidebarTitle = () => { + if (currentStep === Steps.ConnectInstanceStep || currentStep === Steps.ConfigureOauthStep) { + return 'Connect'; + } + if (currentStep === Steps.ReAuthenticateStep) { + return 'Re-authenticate'; + } + if (currentStep === Steps.ConfigureCustomStep || currentStep === Steps.SaveCustomStep) { + return 'Create a'; + } + return 'Configure'; + }; + + const CREATE_CUSTOM_SOURCE_SIDEBAR_BLURB = + 'Custom API Sources provide a set of feature-rich endpoints for indexing data from any content repository.'; + const CONFIGURE_ORGANIZATION_SOURCE_SIDEBAR_BLURB = + 'Follow the configuration flow to add a new content source to Workplace Search. First, create an OAuth application in the content source. After that, connect as many instances of the content source that you need.'; + const CONFIGURE_PRIVATE_SOURCE_SIDEBAR_BLURB = + 'Follow the configuration flow to add a new private content source to Workplace Search. Private content sources are added by each person via their own personal dashboards. Their data stays safe and visible only to them.'; + const CONNECT_ORGANIZATION_SOURCE_SIDEBAR_BLURB = `Upon successfully connecting ${name}, source content will be synced to your organization and will be made available and searchable.`; + const CONNECT_PRIVATE_REMOTE_SOURCE_SIDEBAR_BLURB = ( + <> + {name} is a remote source, which means that each time you search, we reach + out to the content source and get matching results directly from {name}'s servers. + + ); + const CONNECT_PRIVATE_STANDARD_SOURCE_SIDEBAR_BLURB = ( + <> + {name} is a standard source for which content is synchronized on a regular + basis, in a relevant and secure way. + + ); + + const CONNECT_PRIVATE_SOURCE_SIDEBAR_BLURB = isRemote + ? CONNECT_PRIVATE_REMOTE_SOURCE_SIDEBAR_BLURB + : CONNECT_PRIVATE_STANDARD_SOURCE_SIDEBAR_BLURB; + const CONFIGURE_SOURCE_SIDEBAR_BLURB = accountContextOnly + ? CONFIGURE_PRIVATE_SOURCE_SIDEBAR_BLURB + : CONFIGURE_ORGANIZATION_SOURCE_SIDEBAR_BLURB; + + const CONFIG_SIDEBAR_BLURB = isCustom + ? CREATE_CUSTOM_SOURCE_SIDEBAR_BLURB + : CONFIGURE_SOURCE_SIDEBAR_BLURB; + const CONNECT_SIDEBAR_BLURB = isOrganization + ? CONNECT_ORGANIZATION_SOURCE_SIDEBAR_BLURB + : CONNECT_PRIVATE_SOURCE_SIDEBAR_BLURB; + + const sidebarBlurb = + currentStep === Steps.ConnectInstanceStep ? CONNECT_SIDEBAR_BLURB : CONFIG_SIDEBAR_BLURB; + + const sidebar = ( + + ); + const header = ; + + return ( + + {!!flashMessages && } + + {currentStep === Steps.ConfigIntroStep && ( + + )} + + {currentStep === Steps.SaveConfigStep && ( + + )} + + {currentStep === Steps.ConfigCompletedStep && ( + + )} + + {currentStep === Steps.ConnectInstanceStep && ( + + )} + + {currentStep === Steps.ConfigureCustomStep && ( + + )} + + {currentStep === Steps.ConfigureOauthStep && ( + + )} + + {currentStep === Steps.SaveCustomStep && ( + + )} + + {currentStep === Steps.ReAuthenticateStep && } + + ); +}; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/add_source_header.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/add_source_header.tsx new file mode 100644 index 00000000000000..5f832ac2765c50 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/add_source_header.tsx @@ -0,0 +1,57 @@ +/* + * 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 { startCase } from 'lodash'; + +import { EuiFlexGroup, EuiFlexItem, EuiSpacer, EuiText, EuiTextColor } from '@elastic/eui'; + +import { SourceIcon } from 'workplace_search/components'; + +interface AddSourceHeaderProps { + name: string; + serviceType: string; + categories: string[]; +} + +export const AddSourceHeader: React.FC = ({ + name, + serviceType, + categories, +}) => { + return ( + <> + + + + + + + +

+ {name} +

+
+ + {categories.map((category) => startCase(category)).join(', ')} + +
+
+ + + ); +}; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/add_source_list.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/add_source_list.tsx new file mode 100644 index 00000000000000..9c5e82975afacc --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/add_source_list.tsx @@ -0,0 +1,158 @@ +/* + * 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, useState } from 'react'; +import noSharedSourcesIcon from 'workplace_search/components/assets/shareCircle.svg'; + +import { useActions, useValues } from 'kea'; + +import { + EuiFieldSearch, + EuiFormRow, + EuiSpacer, + EuiFlexGroup, + EuiFlexItem, + EuiPanel, + EuiEmptyPrompt, +} from '@elastic/eui'; + +import { AppLogic } from 'workplace_search/App/AppLogic'; +import { SidebarNavigation, ContentSection, Loading, AppView } from 'workplace_search/components'; +import { CUSTOM_SERVICE_TYPE } from 'workplace_search/constants'; +import { SourceDataItem } from 'workplace_search/types'; +import { SOURCES_PATH, getSourcesPath } from 'workplace_search/utils/routePaths'; + +import { SourcesLogic } from 'workplace_search/ContentSources/SourcesLogic'; +import { AvailableSourcesList } from './AvailableSourcesList'; +import { ConfiguredSourcesList } from './ConfiguredSourcesList'; + +const NEW_SOURCE_DESCRIPTION = + 'When configuring and connecting a source, you are creating distinct entities with searchable content synchronized from the content platform itself. A source can be added using one of the available source connectors or via Custom API Sources, for additional flexibility.'; +const ORG_SOURCE_DESCRIPTION = + 'Shared content sources are available to your entire organization or can be assigned to specific user groups.'; +const PRIVATE_SOURCE_DESCRIPTION = + 'Connect a new source to add its content and documents to your search experience.'; +const NO_SOURCES_TITLE = 'Configure and connect your first content source'; +const ORG_SOURCES_TITLE = 'Add a shared content source'; +const PRIVATE_SOURCES_TITLE = 'Add a new content source'; +const PLACEHOLDER = 'Filter sources...'; + +export const AddSourceList: React.FC = () => { + const { contentSources, dataLoading, availableSources, configuredSources } = useValues( + SourcesLogic + ); + + const { initializeSources, resetSourcesState } = useActions(SourcesLogic); + + const { isOrganization } = useValues(AppLogic); + + const [filterValue, setFilterValue] = useState(''); + + useEffect(() => { + initializeSources(); + return resetSourcesState; + }, []); + + if (dataLoading) return ; + + const hasSources = contentSources.length > 0; + const showConfiguredSourcesList = configuredSources.find( + ({ serviceType }) => serviceType !== CUSTOM_SERVICE_TYPE + ); + + const breadcrumbs = { + topLevelPath: getSourcesPath(SOURCES_PATH, isOrganization), + topLevelName: `${isOrganization ? 'Shared' : 'Private'} content sources`, + activeName: 'Add', + }; + + const SIDEBAR_DESCRIPTION = hasSources ? '' : NEW_SOURCE_DESCRIPTION; + const SIDEBAR_CONTEXT_DESCRIPTION = isOrganization + ? ORG_SOURCE_DESCRIPTION + : PRIVATE_SOURCE_DESCRIPTION; + const HAS_SOURCES_TITLE = isOrganization ? ORG_SOURCES_TITLE : PRIVATE_SOURCES_TITLE; + const SIDEBAR_TITLE = hasSources ? HAS_SOURCES_TITLE : NO_SOURCES_TITLE; + + const handleFilterChange = (e) => setFilterValue(e.target.value); + + const filterSources = (source, sources): boolean => { + if (!filterValue) return true; + const filterSource = sources.find(({ serviceType }) => serviceType === source.serviceType); + const filteredName = filterSource?.name || ''; + return filteredName.toLowerCase().indexOf(filterValue.toLowerCase()) > -1; + }; + + const filterAvailableSources = (source) => filterSources(source, availableSources); + const filterConfiguredSources = (source) => filterSources(source, configuredSources); + + const visibleAvailableSources = availableSources.filter( + filterAvailableSources + ) as SourceDataItem[]; + const visibleConfiguredSources = configuredSources.filter( + filterConfiguredSources + ) as SourceDataItem[]; + + const sidebar = ( + {SIDEBAR_CONTEXT_DESCRIPTION}

} + /> + ); + + return ( + + {showConfiguredSourcesList || isOrganization ? ( + + + + + + + {showConfiguredSourcesList && ( + + )} + {isOrganization && } + + ) : ( + + + + + + + + No available sources} + body={ +

+ Sources will be available for search when an administrator adds them to this + organization. +

+ } + /> + + +
+ +
+
+
+ )} +
+ ); +}; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/available_sources_list.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/available_sources_list.tsx new file mode 100644 index 00000000000000..d6d3beb00ded72 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/available_sources_list.tsx @@ -0,0 +1,97 @@ +/* + * 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 { Link } from 'react-router-dom'; + +import { + EuiCard, + EuiFlexGrid, + EuiFlexItem, + EuiSpacer, + EuiTitle, + EuiText, + EuiToolTip, +} from '@elastic/eui'; + +import { useValues } from 'kea'; + +import { AppLogic } from 'workplace_search/App/AppLogic'; +import { SourceIcon } from 'workplace_search/components'; +import { SourceDataItem } from 'workplace_search/types'; +import { ADD_CUSTOM_PATH, getSourcesPath } from 'workplace_search/utils/routePaths'; + +interface AvailableSourcesListProps { + sources: SourceDataItem[]; +} + +export const AvailableSourcesList: React.FC = ({ sources }) => { + const { + fpAccount: { minimumPlatinumLicense }, + } = useValues(AppLogic); + + const getSourceCard = ({ name, serviceType, addPath, accountContextOnly }) => { + const disabled = !minimumPlatinumLicense && accountContextOnly; + const card = ( + } + isDisabled={disabled} + icon={ + + } + /> + ); + + if (disabled) { + return ( + + {card} + + ); + } + return {card}; + }; + + const visibleSources = ( + + {sources.map((source, i) => ( + + {getSourceCard(source)} + + ))} + + ); + + const emptyState =

No available sources matching your query.

; + + return ( + <> + +

Available for configuration

+
+ +

+ Configure an available source or build your own with the{' '} + + Custom API Source + + . +

+
+ + {sources.length > 0 ? visibleSources : emptyState} + + ); +}; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/config_completed.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/config_completed.tsx new file mode 100644 index 00000000000000..aff25c97c255e6 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/config_completed.tsx @@ -0,0 +1,111 @@ +/* + * 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 { Link } from 'react-router-dom'; + +import { + EuiButton, + EuiFlexGroup, + EuiFlexItem, + EuiIcon, + EuiLink, + EuiSpacer, + EuiText, + EuiTextAlign, +} from '@elastic/eui'; + +import { + getSourcesPath, + ADD_SOURCE_PATH, + SECURITY_PATH, + PRIVATE_SOURCES_DOCS_URL, +} from 'workplace_search/utils/routePaths'; + +interface ConfigCompletedProps { + header: React.ReactNode; + name: string; + accountContextOnly?: boolean; + privateSourcesEnabled: boolean; + advanceStep(); +} + +export const ConfigCompleted: React.FC = ({ + name, + advanceStep, + accountContextOnly, + header, + privateSourcesEnabled, +}) => ( +
+ {header} + + + + + + + + + + +

{name} Configured

+
+
+ + + {!accountContextOnly ? ( +

{name} can now be connected to Workplace Search

+ ) : ( + +

Users can now link their {name} accounts from their personal dashboards.

+ {!privateSourcesEnabled && ( +

+ Remember to{' '} + + enable private source connection + {' '} + in Security settings. +

+ )} +

+ + Learn more about private content sources. + +

+
+ )} +
+
+
+
+
+
+ + + + + + Configure a new content source + + + + {!accountContextOnly && ( + + + Connect {name} + + + )} + +
+); diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/config_docs_links.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/config_docs_links.tsx new file mode 100644 index 00000000000000..b666c859948d5d --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/config_docs_links.tsx @@ -0,0 +1,38 @@ +/* + * 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 { EuiButtonEmpty, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; + +interface ConfigDocsLinksProps { + name: string; + documentationUrl: string; + applicationPortalUrl?: string; + applicationLinkTitle?: string; +} + +export const ConfigDocsLinks: React.FC = ({ + name, + documentationUrl, + applicationPortalUrl, + applicationLinkTitle, +}) => ( + + + + Documentation + + + + {applicationPortalUrl && ( + + {applicationLinkTitle || `${name} Application Portal`} + + )} + + +); diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/configuration_intro.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/configuration_intro.tsx new file mode 100644 index 00000000000000..70fcbec51209e4 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/configuration_intro.tsx @@ -0,0 +1,131 @@ +/* + * 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 { + EuiBadge, + EuiButton, + EuiFlexGroup, + EuiFlexItem, + EuiFormRow, + EuiSpacer, + EuiText, + EuiTitle, +} from '@elastic/eui'; + +import connectionIllustration from 'workplace_search/components/assets/connectionIllustration.svg'; + +interface ConfigurationIntroProps { + header: React.ReactNode; + name: string; + advanceStep(); +} + +export const ConfigurationIntro: React.FC = ({ + name, + advanceStep, + header, +}) => ( +
+ {header} + + + + +
+ connection illustration +
+
+ + + + + +

How to add {name}

+
+ + +

Quick setup, then all of your documents will be searchable.

+
+ +
+ + + +
+ +

Step 1

+
+
+
+ + +

+ Configure an OAuth application  + One-Time Action +

+

+ Setup a secure OAuth application through the content source that you or your + team will use to connect and synchronize content. You only have to do this + once per content source. +

+
+
+
+
+ + + +
+ +

Step 2

+
+
+
+ + +

Connect the content source

+

+ Use the new OAuth application to connect any number of instances of the + content source to Workplace Search. +

+
+
+
+
+ + + + + Configure {name} + + + + +
+
+
+
+
+
+); diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/configure_custom.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/configure_custom.tsx new file mode 100644 index 00000000000000..2a03f8254a9baf --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/configure_custom.tsx @@ -0,0 +1,85 @@ +/* + * 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 { useActions, useValues } from 'kea'; + +import { + EuiButton, + EuiFieldText, + EuiForm, + EuiFormRow, + EuiLink, + EuiSpacer, + EuiText, +} from '@elastic/eui'; + +import { CUSTOM_SOURCE_DOCS_URL } from 'workplace_search/utils/routePaths'; +import { SourceLogic } from '../../SourceLogic'; + +interface ConfigureCustomProps { + header: React.ReactNode; + helpText: string; + advanceStep(); +} + +export const ConfigureCustom: React.FC = ({ + helpText, + advanceStep, + header, +}) => { + const { setCustomSourceNameValue } = useActions(SourceLogic); + const { customSourceNameValue, buttonLoading } = useValues(SourceLogic); + + const handleFormSubmit = (e) => { + e.preventDefault(); + advanceStep(); + }; + + const handleNameChange = (e) => setCustomSourceNameValue(e.target.value); + + return ( +
+ {header} +
+ + +

{helpText}

+

+ + Read the documentation + {' '} + to learn more about Custom API Sources. +

+
+ + + + + + + + Create Custom API Source + + +
+
+
+ ); +}; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/configure_oauth.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/configure_oauth.tsx new file mode 100644 index 00000000000000..b45d373fe8b55d --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/configure_oauth.tsx @@ -0,0 +1,104 @@ +/* + * 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, useState } from 'react'; + +import { Location } from 'history'; +import { useActions, useValues } from 'kea'; +import { useLocation } from 'react-router-dom'; + +import { parseQueryParams } from 'app_search/utils/queryParams'; + +import { + EuiButton, + EuiCheckboxGroup, + EuiFlexGroup, + EuiFlexItem, + EuiFormRow, + EuiSpacer, +} from '@elastic/eui'; + +import { Loading } from 'workplace_search/components'; +import { SourceLogic } from 'workplace_search/ContentSources/SourceLogic'; + +interface OauthQueryParams { + preContentSourceId: string; +} + +interface ConfigureOauthProps { + header: React.ReactNode; + name: string; + onFormCreated(name: string); +} + +export const ConfigureOauth: React.FC = ({ name, onFormCreated, header }) => { + const { search } = useLocation() as Location; + + const { preContentSourceId } = (parseQueryParams(search) as unknown) as OauthQueryParams; + const [formLoading, setFormLoading] = useState(false); + + const { + getPreContentSourceConfigData, + setSelectedGithubOrganizations, + createContentSource, + } = useActions(SourceLogic); + const { + currentServiceType, + githubOrganizations, + selectedGithubOrganizationsMap, + sectionLoading, + } = useValues(SourceLogic); + + const checkboxOptions = githubOrganizations.map((item) => ({ id: item, label: item })); + + useEffect(() => { + getPreContentSourceConfigData(preContentSourceId); + }, []); + + const handleChange = (option) => setSelectedGithubOrganizations(option); + const formSubmitSuccess = () => onFormCreated(name); + const handleFormSubmitError = () => setFormLoading(false); + const handleFormSubmut = (e) => { + setFormLoading(true); + e.preventDefault(); + createContentSource(currentServiceType, formSubmitSuccess, handleFormSubmitError); + }; + + const configfieldsForm = ( +
+ + + + + + + + + Complete connection + + + + +
+ ); + + return ( +
+ {header} + {sectionLoading ? : configfieldsForm} +
+ ); +}; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/configured_sources_list.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/configured_sources_list.tsx new file mode 100644 index 00000000000000..05e0182c42a5bd --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/configured_sources_list.tsx @@ -0,0 +1,120 @@ +/* + * 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 { Link } from 'react-router-dom'; + +import { + EuiButtonEmpty, + EuiFlexGrid, + EuiFlexGroup, + EuiFlexItem, + EuiSpacer, + EuiText, + EuiTitle, + EuiToken, + EuiToolTip, +} from '@elastic/eui'; + +import { SourceIcon } from 'workplace_search/components'; +import { SourceDataItem } from 'workplace_search/types'; +import { getSourcesPath } from 'workplace_search/utils/routePaths'; + +interface ConfiguredSourcesProps { + sources: SourceDataItem[]; + isOrganization?: boolean; +} + +export const ConfiguredSourcesList: React.FC = ({ + sources, + isOrganization, +}) => { + const unConnectedTooltip = ( + + + + + + ); + + const accountOnlyTooltip = ( + + + + + + ); + + const visibleSources = ( + + {sources.map(({ name, serviceType, addPath, connected, accountContextOnly }, i) => ( + + +
+ + + + + + + + +

+ {name}  + {!connected && + !accountContextOnly && + isOrganization && + unConnectedTooltip} + {accountContextOnly && isOrganization && accountOnlyTooltip} +

+
+
+
+
+ {(!isOrganization || (isOrganization && !accountContextOnly)) && ( + + + Connect + + + )} +
+
+
+
+ ))} +
+ ); + + const emptyState =

There are no configured sources matching your query.

; + + return ( + <> + +

Configured content sources

+
+ +

Configured and ready for connection.

+
+ + {sources.length > 0 ? visibleSources : emptyState} + + + ); +}; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/connect_instance.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/connect_instance.tsx new file mode 100644 index 00000000000000..46a812fcd6f57e --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/connect_instance.tsx @@ -0,0 +1,254 @@ +/* + * 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, { useState, useEffect } from 'react'; + +import { useActions, useValues } from 'kea'; + +import { + EuiButton, + EuiCallOut, + EuiFlexGroup, + EuiFlexItem, + EuiFieldText, + EuiFormRow, + EuiLink, + EuiSpacer, + EuiSwitch, + EuiText, + EuiTitle, + EuiTextColor, + EuiBadge, + EuiBadgeGroup, +} from '@elastic/eui'; + +import { AppLogic } from 'workplace_search/App/AppLogic'; +import { SourceLogic } from 'workplace_search/ContentSources/SourceLogic'; +import { FeatureIds, Configuration, Features } from 'workplace_search/types'; +import { DOCUMENT_PERMISSIONS_DOCS_URL } from 'workplace_search/utils/routePaths'; +import { SourceFeatures } from './SourceFeatures'; + +interface ConnectInstanceProps { + header: React.ReactNode; + configuration: Configuration; + features?: Features; + objTypes?: string[]; + name: string; + serviceType: string; + sourceDescription: string; + connectStepDescription: string; + needsPermissions: boolean; + onFormCreated(name: string); +} + +export const ConnectInstance: React.FC = ({ + configuration: { needsSubdomain, hasOauthRedirect }, + features, + objTypes, + name, + serviceType, + sourceDescription, + connectStepDescription, + needsPermissions, + onFormCreated, + header, +}) => { + const [formLoading, setFormLoading] = useState(false); + const { + getSourceConnectData, + createContentSource, + setSourceLoginValue, + setSourcePasswordValue, + setSourceSubdomainValue, + setSourceIndexPermissionsValue, + } = useActions(SourceLogic); + + const { loginValue, passwordValue, indexPermissionsValue, subdomainValue } = useValues( + SourceLogic + ); + + const { + isOrganization, + fpAccount: { minimumPlatinumLicense }, + } = useValues(AppLogic); + + // Default indexPermissions to true, if needed + useEffect(() => { + setSourceIndexPermissionsValue(needsPermissions && isOrganization && minimumPlatinumLicense); + }, []); + + const redirectOauth = (oauthUrl: string) => (window.location.href = oauthUrl); + const redirectFormCreated = () => onFormCreated(name); + const onOauthFormSubmit = () => getSourceConnectData(serviceType, redirectOauth); + const handleFormSubmitError = () => setFormLoading(false); + const onCredentialsFormSubmit = () => + createContentSource(serviceType, redirectFormCreated, handleFormSubmitError); + + const handleFormSubmit = (e) => { + setFormLoading(true); + e.preventDefault(); + const onSubmit = hasOauthRedirect ? onOauthFormSubmit : onCredentialsFormSubmit; + onSubmit(); + }; + + const credentialsFields = ( + <> + + setSourceLoginValue(e.target.value)} + /> + + + setSourcePasswordValue(e.target.value)} + /> + + + + ); + + const subdomainField = ( + <> + + setSourceSubdomainValue(e.target.value)} + /> + + + + ); + + const featureBadgeGroup = () => { + if (isOrganization) { + return null; + } + + const isRemote = features?.platinumPrivateContext.includes(FeatureIds.Remote); + const isPrivate = features?.platinumPrivateContext.includes(FeatureIds.Private); + + if (isRemote || isPrivate) { + return ( + <> + + {isRemote && Remote} + {isPrivate && Private} + + + + ); + } + }; + + const descriptionBlock = ( + + {sourceDescription &&

{sourceDescription}

} + {connectStepDescription &&

{connectStepDescription}

} + +
+ ); + + const whichDocsLink = ( + + Which option should I choose? + + ); + + const permissionField = ( + <> + + + Document-level permissions + + + + Enable document-level permission synchronization} + name="index_permissions" + onChange={(e) => setSourceIndexPermissionsValue(e.target.checked)} + checked={indexPermissionsValue} + disabled={!needsPermissions} + /> + + + {!needsPermissions && ( + + Document-level permissions are not yet available for this source.{' '} + + Learn more + + + )} + {needsPermissions && indexPermissionsValue && ( + + Document-level permission information will be synchronized. Additional configuration is + required following the initial connection before documents are available for search. +
+ {whichDocsLink} +
+ )} +
+ + {!indexPermissionsValue && ( + +

+ All documents accessible to the connecting service user will be synchronized and made + available to the organization’s users, or group’s users. Documents are immediately + available for search. {needsPermissions && whichDocsLink} +

+
+ )} + + + ); + + const formFields = ( + <> + {isOrganization && minimumPlatinumLicense && permissionField} + {!hasOauthRedirect && credentialsFields} + {needsSubdomain && subdomainField} + + + + Connect {name} + + + + ); + + return ( +
+
+ + + {header} + {featureBadgeGroup()} + {descriptionBlock} + {formFields} + + + + + +
+
+ ); +}; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/index.ts b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/index.ts new file mode 100644 index 00000000000000..02f0e1db7ff0b7 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/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 { AddSource } from './AddSource'; +export { AddSourceList } from './AddSourceList'; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/re_authenticate.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/re_authenticate.tsx new file mode 100644 index 00000000000000..231f277dfbad6a --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/re_authenticate.tsx @@ -0,0 +1,76 @@ +/* + * 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, useState } from 'react'; + +import { Location } from 'history'; +import { useActions, useValues } from 'kea'; +import { useLocation } from 'react-router-dom'; + +import { parseQueryParams } from 'app_search/utils/queryParams'; + +import { EuiButton, EuiFlexGroup, EuiFlexItem, EuiFormRow, EuiSpacer } from '@elastic/eui'; + +import { SourceLogic } from 'workplace_search/ContentSources/SourceLogic'; + +interface SourceQueryParams { + sourceId: string; +} + +interface ReAuthenticateProps { + name: string; + header: React.ReactNode; +} + +export const ReAuthenticate: React.FC = ({ name, header }) => { + const { search } = useLocation() as Location; + + const { sourceId } = (parseQueryParams(search) as unknown) as SourceQueryParams; + const [formLoading, setFormLoading] = useState(false); + + const { getSourceReConnectData } = useActions(SourceLogic); + const { + sourceConnectData: { oauthUrl }, + } = useValues(SourceLogic); + + useEffect(() => { + getSourceReConnectData(sourceId); + }, []); + + const handleFormSubmit = (e) => { + e.preventDefault(); + setFormLoading(true); + window.location.href = oauthUrl; + }; + + return ( +
+ {header} +
+ + +

+ Your {name} credentials are no longer valid. Please re-authenticate with the original + credentials to resume content syncing. +

+
+
+ + + + Re-authenticate {name} + + + +
+ ); +}; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/save_config.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/save_config.tsx new file mode 100644 index 00000000000000..ada079f88da351 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/save_config.tsx @@ -0,0 +1,218 @@ +/* + * 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 { useActions, useValues } from 'kea'; + +import { + EuiButton, + EuiButtonEmpty, + EuiFieldText, + EuiFlexGroup, + EuiFlexItem, + EuiForm, + EuiFormRow, + EuiSpacer, + EuiSteps, +} from '@elastic/eui'; + +import { AppLogic } from 'workplace_search/App/AppLogic'; +import { ApiKey } from 'workplace_search/components'; +import { SourceLogic } from 'workplace_search/ContentSources/SourceLogic'; +import { Configuration } from 'workplace_search/types'; + +import { ConfigDocsLinks } from './ConfigDocsLinks'; + +interface SaveConfigProps { + header: React.ReactNode; + name: string; + configuration: Configuration; + advanceStep(); + goBackStep?(); + onDeleteConfig?(); +} + +export const SaveConfig: React.FC = ({ + name, + configuration: { + isPublicKey, + needsBaseUrl, + documentationUrl, + applicationPortalUrl, + applicationLinkTitle, + baseUrlTitle, + }, + advanceStep, + goBackStep, + onDeleteConfig, + header, +}) => { + const { setClientIdValue, setClientSecretValue, setBaseUrlValue } = useActions(SourceLogic); + + const { + sourceConfigData, + buttonLoading, + clientIdValue, + clientSecretValue, + baseUrlValue, + } = useValues(SourceLogic); + + const { + accountContextOnly, + configuredFields: { publicKey, consumerKey }, + } = sourceConfigData; + const { + fpAccount: { minimumPlatinumLicense }, + } = useValues(AppLogic); + + const handleFormSubmission = (e) => { + e.preventDefault(); + advanceStep(); + }; + + const saveButton = ( + + Save configuration + + ); + + const deleteButton = ( + + Remove + + ); + + const backButton =  Go back; + const showSaveButton = minimumPlatinumLicense || !accountContextOnly; + + const formActions = ( + + + {showSaveButton && {saveButton}} + + {goBackStep && backButton} + {onDeleteConfig && deleteButton} + + + + ); + + const publicKeyStep1 = ( + + + + + + + + + + + + + + ); + + const credentialsStep1 = ( + + ); + + const publicKeyStep2 = ( + <> + + setBaseUrlValue(e.target.value)} + name="base-uri" + /> + + + {formActions} + + ); + + const credentialsStep2 = ( + + + + + setClientIdValue(e.target.value)} + name="client-id" + /> + + + setClientSecretValue(e.target.value)} + name="client-secret" + /> + + {needsBaseUrl && ( + + setBaseUrlValue(e.target.value)} + name="base-uri" + /> + + )} + + {formActions} + + + + ); + + const oauthSteps = (sourceName: string) => [ + `Create an OAuth app in your organization's ${sourceName}\u00A0account`, + 'Provide the appropriate configuration information', + ]; + + const configSteps = [ + { + title: oauthSteps(name)[0], + children: isPublicKey ? publicKeyStep1 : credentialsStep1, + }, + { + title: oauthSteps(name)[1], + children: isPublicKey ? publicKeyStep2 : credentialsStep2, + }, + ]; + + return ( + <> + {header} +
+ + + + ); +}; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/save_custom.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/save_custom.tsx new file mode 100644 index 00000000000000..0c7ca14bebb821 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/save_custom.tsx @@ -0,0 +1,160 @@ +/* + * 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 { Link } from 'react-router-dom'; + +import { + EuiFlexGroup, + EuiFlexItem, + EuiHorizontalRule, + EuiIcon, + EuiSpacer, + EuiText, + EuiTextAlign, + EuiTitle, + EuiLink, + EuiPanel, +} from '@elastic/eui'; +import { CredentialItem } from 'workplace_search/components/CredentialItem'; + +import { LicenseBadge } from 'workplace_search/components'; + +import { CustomSource } from 'workplace_search/types'; +import { + SOURCES_PATH, + SOURCE_DISPLAY_SETTINGS_PATH, + CUSTOM_API_DOCUMENT_PERMISSIONS_DOCS_URL, + ENT_SEARCH_LICENSE_MANAGEMENT, + getContentSourcePath, + getSourcesPath, +} from 'workplace_search/utils/routePaths'; + +interface SaveCustomProps { + documentationUrl: string; + newCustomSource: CustomSource; + isOrganization: boolean; + header: React.ReactNode; +} + +export const SaveCustom: React.FC = ({ + documentationUrl, + newCustomSource: { key, id, accessToken, name }, + isOrganization, + header, +}) => ( +
+ {header} + + + + + + + + + + +

{name} Created

+
+
+ + + Your endpoints are ready to accept requests. +
+ Be sure to copy your API keys below. +
+ + Return to Sources + +
+
+
+
+ + + + +

API Keys

+
+ +

You'll need these keys to sync documents for this custom source.

+
+ + + + +
+
+
+
+ + + + +
+ +

Visual Walkthrough

+
+ + +

+ + Check out the documentation + {' '} + to learn more about Custom API Sources. +

+
+
+ +
+ +

Styling Results

+
+ + +

+ Use{' '} + + Display Settings + {' '} + to customize how your documents will appear within your search results. Workplace + Search will use fields in alphabetical order by default. +

+
+
+ +
+ + + + +

Set document-level permissions

+
+ + +

+ + Document-level permissions + {' '} + manage content access content on individual or group attributes. Allow or deny + access to specific documents. +

+
+ + + + Learn about Platinum features + + +
+
+
+
+
+
+); diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/source_features.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/source_features.tsx new file mode 100644 index 00000000000000..b32b889b91c8ce --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/source_features.tsx @@ -0,0 +1,223 @@ +/* + * 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 { useValues } from 'kea'; + +import { + EuiFlexGroup, + EuiFlexItem, + EuiLink, + EuiPanel, + EuiSpacer, + EuiText, + EuiTitle, +} from '@elastic/eui'; + +import { AppLogic } from 'workplace_search/App/AppLogic'; +import { LicenseBadge } from 'workplace_search/components'; +import { Features, FeatureIds } from 'workplace_search/types'; +import { ENT_SEARCH_LICENSE_MANAGEMENT } from 'workplace_search/utils/routePaths'; + +interface ConnectInstanceProps { + features?: Features; + objTypes?: string[]; + name: string; +} + +export const SourceFeatures: React.FC = ({ features, objTypes, name }) => { + const { + isOrganization, + fpAccount: { minimumPlatinumLicense }, + } = useValues(AppLogic); + + const Feature = ({ title, children }: { title: string; children: React.ReactElement }) => ( + <> + + + {title} + + + {children} + + ); + + const SyncFrequencyFeature = ( + + +

+ This source gets new content from {name} every 2 hours (following the + initial sync). +

+
+
+ ); + + const SyncedItemsFeature = ( + + <> + +

The following items are searchable:

+
+ + +
    + {objTypes!.map((objType, i) => ( +
  • {objType}
  • + ))} +
+
+ +
+ ); + + const SearchableContentFeature = ( + + + +

The following items are searchable:

+
+ +
    + {objTypes!.map((objType, i) => ( +
  • {objType}
  • + ))} +
+
+
+ ); + + const RemoteFeature = ( + + +

+ Message data and other information is searchable in real-time from the Workplace Search + experience. +

+
+
+ ); + + const PrivateFeature = ( + + +

+ Results returned are specific and relevant to you. Connecting this source does not expose + your personal data to other search users - only you. +

+
+
+ ); + + const GlobalAccessPermissionsFeature = ( + + +

+ All documents accessible to the connecting service user will be synchronized and made + available to the organization’s users, or group’s users. Documents are immediately + available for search +

+
+
+ ); + + const DocumentLevelPermissionsFeature = ( + + +

+ Document-level permissions manage user content access based on defined rules. Allow or + deny access to certain documents for individuals and groups. +

+ + Explore Platinum features + +
+
+ ); + + const FeaturesRouter = ({ featureId }: { featureId: FeatureIds }) => + ({ + [FeatureIds.SyncFrequency]: SyncFrequencyFeature, + [FeatureIds.SearchableContent]: SearchableContentFeature, + [FeatureIds.SyncedItems]: SyncedItemsFeature, + [FeatureIds.Remote]: RemoteFeature, + [FeatureIds.Private]: PrivateFeature, + [FeatureIds.GlobalAccessPermissions]: GlobalAccessPermissionsFeature, + [FeatureIds.DocumentLevelPermissions]: DocumentLevelPermissionsFeature, + }[featureId]); + + const IncludedFeatures = () => { + let includedFeatures: FeatureIds[] | undefined; + + if (!minimumPlatinumLicense && isOrganization) { + includedFeatures = features?.basicOrgContext; + } + if (minimumPlatinumLicense && isOrganization) { + includedFeatures = features?.platinumOrgContext; + } + if (minimumPlatinumLicense && !isOrganization) { + includedFeatures = features?.platinumPrivateContext; + } + + if (!includedFeatures?.length) { + return null; + } + + return ( + + +

Included features

+
+ {includedFeatures.map((featureId, i) => ( + + ))} +
+ ); + }; + + const ExcludedFeatures = () => { + let excludedFeatures: FeatureIds[] | undefined; + + if (!minimumPlatinumLicense && isOrganization) { + excludedFeatures = features?.basicOrgContextExcludedFeatures; + } + + if (!excludedFeatures?.length) { + return null; + } + + return ( + + + {excludedFeatures.map((featureId, i) => ( + + ))} + + ); + }; + + return ( + + + + + + + + + + ); +}; From 49c22a6dd87633ed1ddedb047b7a107e1bcedcb6 Mon Sep 17 00:00:00 2001 From: scottybollinger Date: Wed, 18 Nov 2020 16:36:59 -0600 Subject: [PATCH 02/11] Add route helper --- .../public/applications/workplace_search/routes.ts | 2 ++ 1 file changed, 2 insertions(+) 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 8f62984db1b5ea..be95c6ffe6f38b 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 @@ -124,3 +124,5 @@ export const getContentSourcePath = ( export const getGroupPath = (groupId: string) => generatePath(GROUP_PATH, { groupId }); export const getGroupSourcePrioritizationPath = (groupId: string) => `${GROUPS_PATH}/${groupId}/source_prioritization`; +export const getSourcesPath = (path: string, isOrganization: boolean) => + isOrganization ? `${ORG_PATH}${path}` : path; From 34ca5b959807dca9bf3d58010667e7f6434c7f27 Mon Sep 17 00:00:00 2001 From: scottybollinger Date: Wed, 18 Nov 2020 17:15:17 -0600 Subject: [PATCH 03/11] Remove AppView, Sidebar navigation and FlashMessages Sidebar copy and breadcrumbs will be recreated at the top level in a separate PR --- .../components/add_source/add_source.tsx | 17 +-- .../components/add_source/add_source_list.tsx | 102 ++++++++---------- 2 files changed, 46 insertions(+), 73 deletions(-) diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/add_source.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/add_source.tsx index 6f2824a418681a..bad77a25f37fed 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/add_source.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/add_source.tsx @@ -10,9 +10,8 @@ import { History } from 'history'; import { useActions, useValues } from 'kea'; import { useHistory } from 'react-router-dom'; -import FlashMessages from 'shared/components/FlashMessages'; import { AppLogic } from 'workplace_search/App/AppLogic'; -import { SidebarNavigation, Loading, AppView } from 'workplace_search/components'; +import { Loading } from 'workplace_search/components'; import { CUSTOM_SERVICE_TYPE } from 'workplace_search/constants'; import { staticSourceData } from 'workplace_search/ContentSources/sourceData'; import { SourceLogic } from 'workplace_search/ContentSources/SourceLogic'; @@ -73,7 +72,6 @@ export const AddSource: React.FC = ({ privateSourcesEnabled, }, dataLoading, - flashMessages, newCustomSource, } = useValues(SourceLogic); @@ -181,19 +179,10 @@ export const AddSource: React.FC = ({ const sidebarBlurb = currentStep === Steps.ConnectInstanceStep ? CONNECT_SIDEBAR_BLURB : CONFIG_SIDEBAR_BLURB; - const sidebar = ( - - ); const header = ; return ( - - {!!flashMessages && } - + <> {currentStep === Steps.ConfigIntroStep && ( )} @@ -255,6 +244,6 @@ export const AddSource: React.FC = ({ )} {currentStep === Steps.ReAuthenticateStep && } - + ); }; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/add_source_list.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/add_source_list.tsx index 9c5e82975afacc..45437a8fc79682 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/add_source_list.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/add_source_list.tsx @@ -20,7 +20,7 @@ import { } from '@elastic/eui'; import { AppLogic } from 'workplace_search/App/AppLogic'; -import { SidebarNavigation, ContentSection, Loading, AppView } from 'workplace_search/components'; +import { ContentSection, Loading } from 'workplace_search/components'; import { CUSTOM_SERVICE_TYPE } from 'workplace_search/constants'; import { SourceDataItem } from 'workplace_search/types'; import { SOURCES_PATH, getSourcesPath } from 'workplace_search/utils/routePaths'; @@ -95,64 +95,48 @@ export const AddSourceList: React.FC = () => { filterConfiguredSources ) as SourceDataItem[]; - const sidebar = ( - {SIDEBAR_CONTEXT_DESCRIPTION}

} - /> - ); - - return ( - - {showConfiguredSourcesList || isOrganization ? ( - - - - - - - {showConfiguredSourcesList && ( - - )} - {isOrganization && } - - ) : ( - - - - - - - - No available sources} - body={ -

- Sources will be available for search when an administrator adds them to this - organization. -

- } - /> - - -
- -
-
-
+ return showConfiguredSourcesList || isOrganization ? ( + + + + + + + {showConfiguredSourcesList && ( + )} -
+ {isOrganization && } + + ) : ( + + + + + + + + No available sources} + body={ +

+ Sources will be available for search when an administrator adds them to this + organization. +

+ } + /> + + +
+ +
+
+
); }; From 6c102a2abdc38173bce65781e19fbc2ce3887822 Mon Sep 17 00:00:00 2001 From: scottybollinger Date: Wed, 18 Nov 2020 17:15:36 -0600 Subject: [PATCH 04/11] Update component paths --- .../components/add_source/add_source.tsx | 38 +++++++++---------- .../add_source/add_source_header.tsx | 2 +- .../components/add_source/add_source_list.tsx | 19 +++++----- .../add_source/available_sources_list.tsx | 8 ++-- .../add_source/config_completed.tsx | 2 +- .../add_source/configure_custom.tsx | 4 +- .../components/add_source/configure_oauth.tsx | 7 ++-- .../add_source/configured_sources_list.tsx | 6 +-- .../add_source/connect_instance.tsx | 10 ++--- .../components/add_source/re_authenticate.tsx | 5 +-- .../components/add_source/save_config.tsx | 10 ++--- .../components/add_source/save_custom.tsx | 8 ++-- .../components/add_source/source_features.tsx | 8 ++-- 13 files changed, 61 insertions(+), 66 deletions(-) diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/add_source.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/add_source.tsx index bad77a25f37fed..2cf91de14b5616 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/add_source.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/add_source.tsx @@ -10,27 +10,23 @@ import { History } from 'history'; import { useActions, useValues } from 'kea'; import { useHistory } from 'react-router-dom'; -import { AppLogic } from 'workplace_search/App/AppLogic'; -import { Loading } from 'workplace_search/components'; -import { CUSTOM_SERVICE_TYPE } from 'workplace_search/constants'; -import { staticSourceData } from 'workplace_search/ContentSources/sourceData'; -import { SourceLogic } from 'workplace_search/ContentSources/SourceLogic'; -import { SourceDataItem, FeatureIds } from 'workplace_search/types'; -import { - ADD_SOURCE_PATH, - SOURCE_ADDED_PATH, - getSourcesPath, -} from 'workplace_search/utils/routePaths'; - -import { AddSourceHeader } from './AddSourceHeader'; -import { ConfigCompleted } from './ConfigCompleted'; -import { ConfigurationIntro } from './ConfigurationIntro'; -import { ConfigureCustom } from './ConfigureCustom'; -import { ConfigureOauth } from './ConfigureOauth'; -import { ConnectInstance } from './ConnectInstance'; -import { ReAuthenticate } from './ReAuthenticate'; -import { SaveConfig } from './SaveConfig'; -import { SaveCustom } from './SaveCustom'; +import { AppLogic } from '../../../../app_logic'; +import { Loading } from '../../../../../../applications/shared/loading'; +import { CUSTOM_SERVICE_TYPE } from '../../../../constants'; +import { staticSourceData } from '../../source_data'; +import { SourceLogic } from '../../source_logic'; +import { SourceDataItem, FeatureIds } from '../../../../types'; +import { ADD_SOURCE_PATH, SOURCE_ADDED_PATH, getSourcesPath } from '../../../../routes'; + +import { AddSourceHeader } from './add_source_header'; +import { ConfigCompleted } from './config_completed'; +import { ConfigurationIntro } from './configuration_intro'; +import { ConfigureCustom } from './configure_custom'; +import { ConfigureOauth } from './configure_oauth'; +import { ConnectInstance } from './connect_instance'; +import { ReAuthenticate } from './re_authenticate'; +import { SaveConfig } from './save_config'; +import { SaveCustom } from './save_custom'; enum Steps { ConfigIntroStep = 'Config Intro', diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/add_source_header.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/add_source_header.tsx index 5f832ac2765c50..22230bb59f8475 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/add_source_header.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/add_source_header.tsx @@ -10,7 +10,7 @@ import { startCase } from 'lodash'; import { EuiFlexGroup, EuiFlexItem, EuiSpacer, EuiText, EuiTextColor } from '@elastic/eui'; -import { SourceIcon } from 'workplace_search/components'; +import { SourceIcon } from '../../../../components/shared/source_icon'; interface AddSourceHeaderProps { name: string; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/add_source_list.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/add_source_list.tsx index 45437a8fc79682..d7e5841660e38d 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/add_source_list.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/add_source_list.tsx @@ -19,15 +19,16 @@ import { EuiEmptyPrompt, } from '@elastic/eui'; -import { AppLogic } from 'workplace_search/App/AppLogic'; -import { ContentSection, Loading } from 'workplace_search/components'; -import { CUSTOM_SERVICE_TYPE } from 'workplace_search/constants'; -import { SourceDataItem } from 'workplace_search/types'; -import { SOURCES_PATH, getSourcesPath } from 'workplace_search/utils/routePaths'; - -import { SourcesLogic } from 'workplace_search/ContentSources/SourcesLogic'; -import { AvailableSourcesList } from './AvailableSourcesList'; -import { ConfiguredSourcesList } from './ConfiguredSourcesList'; +import { AppLogic } from '../../../../app_logic'; +import { ContentSection } from '../../../../components/shared/content_section'; +import { Loading } from '../../../../../../applications/shared/loading'; +import { CUSTOM_SERVICE_TYPE } from '../../../../constants'; +import { SourceDataItem } from '../../../../types'; +import { SOURCES_PATH, getSourcesPath } from '../../../../routes'; + +import { SourcesLogic } from '../../sources_logic'; +import { AvailableSourcesList } from './available_sources_list'; +import { ConfiguredSourcesList } from './configured_sources_list'; const NEW_SOURCE_DESCRIPTION = 'When configuring and connecting a source, you are creating distinct entities with searchable content synchronized from the content platform itself. A source can be added using one of the available source connectors or via Custom API Sources, for additional flexibility.'; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/available_sources_list.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/available_sources_list.tsx index d6d3beb00ded72..31e7202b66f0cb 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/available_sources_list.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/available_sources_list.tsx @@ -19,10 +19,10 @@ import { import { useValues } from 'kea'; -import { AppLogic } from 'workplace_search/App/AppLogic'; -import { SourceIcon } from 'workplace_search/components'; -import { SourceDataItem } from 'workplace_search/types'; -import { ADD_CUSTOM_PATH, getSourcesPath } from 'workplace_search/utils/routePaths'; +import { AppLogic } from '../../../../app_logic'; +import { SourceIcon } from '../../../../components/shared/source_icon'; +import { SourceDataItem } from '../../../../types'; +import { ADD_CUSTOM_PATH, getSourcesPath } from '../../../../routes'; interface AvailableSourcesListProps { sources: SourceDataItem[]; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/config_completed.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/config_completed.tsx index aff25c97c255e6..57add9c04660f3 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/config_completed.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/config_completed.tsx @@ -24,7 +24,7 @@ import { ADD_SOURCE_PATH, SECURITY_PATH, PRIVATE_SOURCES_DOCS_URL, -} from 'workplace_search/utils/routePaths'; +} from '../../../../routes'; interface ConfigCompletedProps { header: React.ReactNode; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/configure_custom.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/configure_custom.tsx index 2a03f8254a9baf..e1dd8579aeb693 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/configure_custom.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/configure_custom.tsx @@ -18,8 +18,8 @@ import { EuiText, } from '@elastic/eui'; -import { CUSTOM_SOURCE_DOCS_URL } from 'workplace_search/utils/routePaths'; -import { SourceLogic } from '../../SourceLogic'; +import { CUSTOM_SOURCE_DOCS_URL } from '../../../../routes'; +import { SourceLogic } from '../../source_logic'; interface ConfigureCustomProps { header: React.ReactNode; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/configure_oauth.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/configure_oauth.tsx index b45d373fe8b55d..f6aa218bcb51a5 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/configure_oauth.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/configure_oauth.tsx @@ -10,8 +10,6 @@ import { Location } from 'history'; import { useActions, useValues } from 'kea'; import { useLocation } from 'react-router-dom'; -import { parseQueryParams } from 'app_search/utils/queryParams'; - import { EuiButton, EuiCheckboxGroup, @@ -21,8 +19,9 @@ import { EuiSpacer, } from '@elastic/eui'; -import { Loading } from 'workplace_search/components'; -import { SourceLogic } from 'workplace_search/ContentSources/SourceLogic'; +import { parseQueryParams } from '../../../../../../applications/shared/query_params'; +import { Loading } from '../../../../../../applications/shared/loading'; +import { SourceLogic } from '../../source_logic'; interface OauthQueryParams { preContentSourceId: string; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/configured_sources_list.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/configured_sources_list.tsx index 05e0182c42a5bd..abb2745eb0a229 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/configured_sources_list.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/configured_sources_list.tsx @@ -20,9 +20,9 @@ import { EuiToolTip, } from '@elastic/eui'; -import { SourceIcon } from 'workplace_search/components'; -import { SourceDataItem } from 'workplace_search/types'; -import { getSourcesPath } from 'workplace_search/utils/routePaths'; +import { SourceIcon } from '../../../../components/shared/source_icon'; +import { SourceDataItem } from '../../../../types'; +import { getSourcesPath } from '../../../../routes'; interface ConfiguredSourcesProps { sources: SourceDataItem[]; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/connect_instance.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/connect_instance.tsx index 46a812fcd6f57e..96fe9251103435 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/connect_instance.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/connect_instance.tsx @@ -25,11 +25,11 @@ import { EuiBadgeGroup, } from '@elastic/eui'; -import { AppLogic } from 'workplace_search/App/AppLogic'; -import { SourceLogic } from 'workplace_search/ContentSources/SourceLogic'; -import { FeatureIds, Configuration, Features } from 'workplace_search/types'; -import { DOCUMENT_PERMISSIONS_DOCS_URL } from 'workplace_search/utils/routePaths'; -import { SourceFeatures } from './SourceFeatures'; +import { AppLogic } from '../../../../app_logic'; +import { SourceLogic } from '../../source_logic'; +import { FeatureIds, Configuration, Features } from '../../../../types'; +import { DOCUMENT_PERMISSIONS_DOCS_URL } from '../../../../routes'; +import { SourceFeatures } from './source_features'; interface ConnectInstanceProps { header: React.ReactNode; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/re_authenticate.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/re_authenticate.tsx index 231f277dfbad6a..65cae8061b0b31 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/re_authenticate.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/re_authenticate.tsx @@ -10,11 +10,10 @@ import { Location } from 'history'; import { useActions, useValues } from 'kea'; import { useLocation } from 'react-router-dom'; -import { parseQueryParams } from 'app_search/utils/queryParams'; - import { EuiButton, EuiFlexGroup, EuiFlexItem, EuiFormRow, EuiSpacer } from '@elastic/eui'; +import { parseQueryParams } from '../../../../../../applications/shared/query_params'; -import { SourceLogic } from 'workplace_search/ContentSources/SourceLogic'; +import { SourceLogic } from '../../source_logic'; interface SourceQueryParams { sourceId: string; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/save_config.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/save_config.tsx index ada079f88da351..7cfc5cb581c280 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/save_config.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/save_config.tsx @@ -20,12 +20,12 @@ import { EuiSteps, } from '@elastic/eui'; -import { AppLogic } from 'workplace_search/App/AppLogic'; -import { ApiKey } from 'workplace_search/components'; -import { SourceLogic } from 'workplace_search/ContentSources/SourceLogic'; -import { Configuration } from 'workplace_search/types'; +import { AppLogic } from '../../../../app_logic'; +import { ApiKey } from '../../../../components/shared/api_key'; +import { SourceLogic } from '../../source_logic'; +import { Configuration } from '../../../../types'; -import { ConfigDocsLinks } from './ConfigDocsLinks'; +import { ConfigDocsLinks } from './config_docs_links'; interface SaveConfigProps { header: React.ReactNode; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/save_custom.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/save_custom.tsx index 0c7ca14bebb821..17510c3ece9147 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/save_custom.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/save_custom.tsx @@ -20,11 +20,11 @@ import { EuiLink, EuiPanel, } from '@elastic/eui'; -import { CredentialItem } from 'workplace_search/components/CredentialItem'; -import { LicenseBadge } from 'workplace_search/components'; +import { CredentialItem } from '../../../../components/shared/credential_item'; +import { LicenseBadge } from '../../../../components/shared/license_badge'; -import { CustomSource } from 'workplace_search/types'; +import { CustomSource } from '../../../../types'; import { SOURCES_PATH, SOURCE_DISPLAY_SETTINGS_PATH, @@ -32,7 +32,7 @@ import { ENT_SEARCH_LICENSE_MANAGEMENT, getContentSourcePath, getSourcesPath, -} from 'workplace_search/utils/routePaths'; +} from '../../../../routes'; interface SaveCustomProps { documentationUrl: string; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/source_features.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/source_features.tsx index b32b889b91c8ce..296ee63ebe2710 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/source_features.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/source_features.tsx @@ -18,10 +18,10 @@ import { EuiTitle, } from '@elastic/eui'; -import { AppLogic } from 'workplace_search/App/AppLogic'; -import { LicenseBadge } from 'workplace_search/components'; -import { Features, FeatureIds } from 'workplace_search/types'; -import { ENT_SEARCH_LICENSE_MANAGEMENT } from 'workplace_search/utils/routePaths'; +import { AppLogic } from '../../../../app_logic'; +import { LicenseBadge } from '../../../../components/shared/license_badge'; +import { Features, FeatureIds } from '../../../../types'; +import { ENT_SEARCH_LICENSE_MANAGEMENT } from '../../../../routes'; interface ConnectInstanceProps { features?: Features; From 13a67b48bf5e29d56ce2ee842c6ef43580743801 Mon Sep 17 00:00:00 2001 From: scottybollinger Date: Wed, 18 Nov 2020 17:25:24 -0600 Subject: [PATCH 05/11] =?UTF-8?q?Use=20Kibana=E2=80=99s=20hasPlatinumLicen?= =?UTF-8?q?se=20over=20minimumPlatinumLicense?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../add_source/available_sources_list.tsx | 9 ++++----- .../components/add_source/connect_instance.tsx | 14 ++++++++------ .../components/add_source/save_config.tsx | 10 +++++----- .../components/add_source/source_features.tsx | 16 ++++++++-------- 4 files changed, 25 insertions(+), 24 deletions(-) diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/available_sources_list.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/available_sources_list.tsx index 31e7202b66f0cb..517b9c3649959b 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/available_sources_list.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/available_sources_list.tsx @@ -19,7 +19,8 @@ import { import { useValues } from 'kea'; -import { AppLogic } from '../../../../app_logic'; +import { LicensingLogic } from '../../../../../../applications/shared/licensing'; + import { SourceIcon } from '../../../../components/shared/source_icon'; import { SourceDataItem } from '../../../../types'; import { ADD_CUSTOM_PATH, getSourcesPath } from '../../../../routes'; @@ -29,12 +30,10 @@ interface AvailableSourcesListProps { } export const AvailableSourcesList: React.FC = ({ sources }) => { - const { - fpAccount: { minimumPlatinumLicense }, - } = useValues(AppLogic); + const { hasPlatinumLicense } = useValues(LicensingLogic); const getSourceCard = ({ name, serviceType, addPath, accountContextOnly }) => { - const disabled = !minimumPlatinumLicense && accountContextOnly; + const disabled = !hasPlatinumLicense && accountContextOnly; const card = ( = ({ header, }) => { const [formLoading, setFormLoading] = useState(false); + + const { hasPlatinumLicense } = useValues(LicensingLogic); + const { getSourceConnectData, createContentSource, @@ -70,14 +75,11 @@ export const ConnectInstance: React.FC = ({ SourceLogic ); - const { - isOrganization, - fpAccount: { minimumPlatinumLicense }, - } = useValues(AppLogic); + const { isOrganization } = useValues(AppLogic); // Default indexPermissions to true, if needed useEffect(() => { - setSourceIndexPermissionsValue(needsPermissions && isOrganization && minimumPlatinumLicense); + setSourceIndexPermissionsValue(needsPermissions && isOrganization && hasPlatinumLicense); }, []); const redirectOauth = (oauthUrl: string) => (window.location.href = oauthUrl); @@ -216,7 +218,7 @@ export const ConnectInstance: React.FC = ({ const formFields = ( <> - {isOrganization && minimumPlatinumLicense && permissionField} + {isOrganization && hasPlatinumLicense && permissionField} {!hasOauthRedirect && credentialsFields} {needsSubdomain && subdomainField} diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/save_config.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/save_config.tsx index 7cfc5cb581c280..0c547c174fbe56 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/save_config.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/save_config.tsx @@ -20,7 +20,8 @@ import { EuiSteps, } from '@elastic/eui'; -import { AppLogic } from '../../../../app_logic'; +import { LicensingLogic } from '../../../../../../applications/shared/licensing'; + import { ApiKey } from '../../../../components/shared/api_key'; import { SourceLogic } from '../../source_logic'; import { Configuration } from '../../../../types'; @@ -51,6 +52,8 @@ export const SaveConfig: React.FC = ({ onDeleteConfig, header, }) => { + const { hasPlatinumLicense } = useValues(LicensingLogic); + const { setClientIdValue, setClientSecretValue, setBaseUrlValue } = useActions(SourceLogic); const { @@ -65,9 +68,6 @@ export const SaveConfig: React.FC = ({ accountContextOnly, configuredFields: { publicKey, consumerKey }, } = sourceConfigData; - const { - fpAccount: { minimumPlatinumLicense }, - } = useValues(AppLogic); const handleFormSubmission = (e) => { e.preventDefault(); @@ -87,7 +87,7 @@ export const SaveConfig: React.FC = ({ ); const backButton =  Go back; - const showSaveButton = minimumPlatinumLicense || !accountContextOnly; + const showSaveButton = hasPlatinumLicense || !accountContextOnly; const formActions = ( diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/source_features.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/source_features.tsx index 296ee63ebe2710..6c92f3a9e13ffb 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/source_features.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/source_features.tsx @@ -18,6 +18,8 @@ import { EuiTitle, } from '@elastic/eui'; +import { LicensingLogic } from '../../../../../../applications/shared/licensing'; + import { AppLogic } from '../../../../app_logic'; import { LicenseBadge } from '../../../../components/shared/license_badge'; import { Features, FeatureIds } from '../../../../types'; @@ -30,10 +32,8 @@ interface ConnectInstanceProps { } export const SourceFeatures: React.FC = ({ features, objTypes, name }) => { - const { - isOrganization, - fpAccount: { minimumPlatinumLicense }, - } = useValues(AppLogic); + const { hasPlatinumLicense } = useValues(LicensingLogic); + const { isOrganization } = useValues(AppLogic); const Feature = ({ title, children }: { title: string; children: React.ReactElement }) => ( <> @@ -153,13 +153,13 @@ export const SourceFeatures: React.FC = ({ features, objTy const IncludedFeatures = () => { let includedFeatures: FeatureIds[] | undefined; - if (!minimumPlatinumLicense && isOrganization) { + if (!hasPlatinumLicense && isOrganization) { includedFeatures = features?.basicOrgContext; } - if (minimumPlatinumLicense && isOrganization) { + if (hasPlatinumLicense && isOrganization) { includedFeatures = features?.platinumOrgContext; } - if (minimumPlatinumLicense && !isOrganization) { + if (hasPlatinumLicense && !isOrganization) { includedFeatures = features?.platinumPrivateContext; } @@ -182,7 +182,7 @@ export const SourceFeatures: React.FC = ({ features, objTy const ExcludedFeatures = () => { let excludedFeatures: FeatureIds[] | undefined; - if (!minimumPlatinumLicense && isOrganization) { + if (!hasPlatinumLicense && isOrganization) { excludedFeatures = features?.basicOrgContextExcludedFeatures; } From b51cb81c5452124fcec4344d452b16ccff44fc08 Mon Sep 17 00:00:00 2001 From: scottybollinger Date: Wed, 18 Nov 2020 17:40:03 -0600 Subject: [PATCH 06/11] Various TypeScript lint fixes --- .../components/add_source/add_source.tsx | 2 +- .../components/add_source/add_source_list.tsx | 12 +++++++----- .../components/add_source/available_sources_list.tsx | 2 +- .../components/add_source/config_completed.tsx | 2 +- .../components/add_source/configuration_intro.tsx | 2 +- .../components/add_source/configure_custom.tsx | 9 +++++---- .../components/add_source/configure_oauth.tsx | 12 +++++++----- .../add_source/configured_sources_list.tsx | 2 +- .../components/add_source/connect_instance.tsx | 6 +++--- .../components/add_source/re_authenticate.tsx | 4 ++-- .../components/add_source/save_config.tsx | 10 +++++----- 11 files changed, 34 insertions(+), 29 deletions(-) diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/add_source.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/add_source.tsx index 2cf91de14b5616..fa4f206800fbee 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/add_source.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/add_source.tsx @@ -121,7 +121,7 @@ export const AddSource: React.FC = ({ const saveCustomSuccess = () => setStep(Steps.SaveCustomStep); const goToSaveCustom = () => createContentSource(CUSTOM_SERVICE_TYPE, saveCustomSuccess); - const goToFormSourceCreated = (sourceName) => { + const goToFormSourceCreated = (sourceName: string) => { history.push(`${getSourcesPath(SOURCE_ADDED_PATH, isOrganization)}/?name=${sourceName}`); }; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/add_source_list.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/add_source_list.tsx index d7e5841660e38d..650510619bd0ef 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/add_source_list.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/add_source_list.tsx @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import React, { useEffect, useState } from 'react'; +import React, { useEffect, useState, ChangeEvent } from 'react'; import noSharedSourcesIcon from 'workplace_search/components/assets/shareCircle.svg'; import { useActions, useValues } from 'kea'; @@ -77,17 +77,19 @@ export const AddSourceList: React.FC = () => { const HAS_SOURCES_TITLE = isOrganization ? ORG_SOURCES_TITLE : PRIVATE_SOURCES_TITLE; const SIDEBAR_TITLE = hasSources ? HAS_SOURCES_TITLE : NO_SOURCES_TITLE; - const handleFilterChange = (e) => setFilterValue(e.target.value); + const handleFilterChange = (e: ChangeEvent) => setFilterValue(e.target.value); - const filterSources = (source, sources): boolean => { + const filterSources = (source: SourceDataItem, sources: SourceDataItem[]): boolean => { if (!filterValue) return true; const filterSource = sources.find(({ serviceType }) => serviceType === source.serviceType); const filteredName = filterSource?.name || ''; return filteredName.toLowerCase().indexOf(filterValue.toLowerCase()) > -1; }; - const filterAvailableSources = (source) => filterSources(source, availableSources); - const filterConfiguredSources = (source) => filterSources(source, configuredSources); + const filterAvailableSources = (source: SourceDataItem) => + filterSources(source, availableSources); + const filterConfiguredSources = (source: SourceDataItem) => + filterSources(source, configuredSources); const visibleAvailableSources = availableSources.filter( filterAvailableSources diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/available_sources_list.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/available_sources_list.tsx index 517b9c3649959b..0d4345c67cfb3c 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/available_sources_list.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/available_sources_list.tsx @@ -32,7 +32,7 @@ interface AvailableSourcesListProps { export const AvailableSourcesList: React.FC = ({ sources }) => { const { hasPlatinumLicense } = useValues(LicensingLogic); - const getSourceCard = ({ name, serviceType, addPath, accountContextOnly }) => { + const getSourceCard = ({ name, serviceType, addPath, accountContextOnly }: SourceDataItem) => { const disabled = !hasPlatinumLicense && accountContextOnly; const card = ( = ({ diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/configuration_intro.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/configuration_intro.tsx index 70fcbec51209e4..2bf5134e59e264 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/configuration_intro.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/configuration_intro.tsx @@ -22,7 +22,7 @@ import connectionIllustration from 'workplace_search/components/assets/connectio interface ConfigurationIntroProps { header: React.ReactNode; name: string; - advanceStep(); + advanceStep(): void; } export const ConfigurationIntro: React.FC = ({ diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/configure_custom.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/configure_custom.tsx index e1dd8579aeb693..3788071979e67b 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/configure_custom.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/configure_custom.tsx @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import React from 'react'; +import React, { ChangeEvent, FormEvent } from 'react'; import { useActions, useValues } from 'kea'; @@ -24,7 +24,7 @@ import { SourceLogic } from '../../source_logic'; interface ConfigureCustomProps { header: React.ReactNode; helpText: string; - advanceStep(); + advanceStep(): void; } export const ConfigureCustom: React.FC = ({ @@ -35,12 +35,13 @@ export const ConfigureCustom: React.FC = ({ const { setCustomSourceNameValue } = useActions(SourceLogic); const { customSourceNameValue, buttonLoading } = useValues(SourceLogic); - const handleFormSubmit = (e) => { + const handleFormSubmit = (e: FormEvent) => { e.preventDefault(); advanceStep(); }; - const handleNameChange = (e) => setCustomSourceNameValue(e.target.value); + const handleNameChange = (e: ChangeEvent) => + setCustomSourceNameValue(e.target.value); return (
diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/configure_oauth.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/configure_oauth.tsx index f6aa218bcb51a5..9c2084483c816b 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/configure_oauth.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/configure_oauth.tsx @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import React, { useEffect, useState } from 'react'; +import React, { useEffect, useState, FormEvent } from 'react'; import { Location } from 'history'; import { useActions, useValues } from 'kea'; @@ -19,6 +19,8 @@ import { EuiSpacer, } from '@elastic/eui'; +import { EuiCheckboxGroupIdToSelectedMap } from '@elastic/eui/src/components/form/checkbox/checkbox_group'; + import { parseQueryParams } from '../../../../../../applications/shared/query_params'; import { Loading } from '../../../../../../applications/shared/loading'; import { SourceLogic } from '../../source_logic'; @@ -30,7 +32,7 @@ interface OauthQueryParams { interface ConfigureOauthProps { header: React.ReactNode; name: string; - onFormCreated(name: string); + onFormCreated(name: string): void; } export const ConfigureOauth: React.FC = ({ name, onFormCreated, header }) => { @@ -57,10 +59,10 @@ export const ConfigureOauth: React.FC = ({ name, onFormCrea getPreContentSourceConfigData(preContentSourceId); }, []); - const handleChange = (option) => setSelectedGithubOrganizations(option); + const handleChange = (option: string) => setSelectedGithubOrganizations(option); const formSubmitSuccess = () => onFormCreated(name); const handleFormSubmitError = () => setFormLoading(false); - const handleFormSubmut = (e) => { + const handleFormSubmut = (e: FormEvent) => { setFormLoading(true); e.preventDefault(); createContentSource(currentServiceType, formSubmitSuccess, handleFormSubmitError); @@ -79,7 +81,7 @@ export const ConfigureOauth: React.FC = ({ name, onFormCrea diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/configured_sources_list.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/configured_sources_list.tsx index abb2745eb0a229..792db71fef02e6 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/configured_sources_list.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/configured_sources_list.tsx @@ -89,7 +89,7 @@ export const ConfiguredSourcesList: React.FC = ({ {(!isOrganization || (isOrganization && !accountContextOnly)) && ( - + Connect diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/connect_instance.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/connect_instance.tsx index 6dcdb29c76d126..ad183181b4ecad 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/connect_instance.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/connect_instance.tsx @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import React, { useState, useEffect } from 'react'; +import React, { useState, useEffect, FormEvent } from 'react'; import { useActions, useValues } from 'kea'; @@ -43,7 +43,7 @@ interface ConnectInstanceProps { sourceDescription: string; connectStepDescription: string; needsPermissions: boolean; - onFormCreated(name: string); + onFormCreated(name: string): void; } export const ConnectInstance: React.FC = ({ @@ -89,7 +89,7 @@ export const ConnectInstance: React.FC = ({ const onCredentialsFormSubmit = () => createContentSource(serviceType, redirectFormCreated, handleFormSubmitError); - const handleFormSubmit = (e) => { + const handleFormSubmit = (e: FormEvent) => { setFormLoading(true); e.preventDefault(); const onSubmit = hasOauthRedirect ? onOauthFormSubmit : onCredentialsFormSubmit; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/re_authenticate.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/re_authenticate.tsx index 65cae8061b0b31..7336a3b51a4449 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/re_authenticate.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/re_authenticate.tsx @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import React, { useEffect, useState } from 'react'; +import React, { useEffect, useState, FormEvent } from 'react'; import { Location } from 'history'; import { useActions, useValues } from 'kea'; @@ -39,7 +39,7 @@ export const ReAuthenticate: React.FC = ({ name, header }) getSourceReConnectData(sourceId); }, []); - const handleFormSubmit = (e) => { + const handleFormSubmit = (e: FormEvent) => { e.preventDefault(); setFormLoading(true); window.location.href = oauthUrl; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/save_config.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/save_config.tsx index 0c547c174fbe56..4036bb6a771bb6 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/save_config.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/save_config.tsx @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import React from 'react'; +import React, { FormEvent } from 'react'; import { useActions, useValues } from 'kea'; @@ -32,9 +32,9 @@ interface SaveConfigProps { header: React.ReactNode; name: string; configuration: Configuration; - advanceStep(); - goBackStep?(); - onDeleteConfig?(); + advanceStep(): void; + goBackStep?(): void; + onDeleteConfig?(): void; } export const SaveConfig: React.FC = ({ @@ -69,7 +69,7 @@ export const SaveConfig: React.FC = ({ configuredFields: { publicKey, consumerKey }, } = sourceConfigData; - const handleFormSubmission = (e) => { + const handleFormSubmission = (e: FormEvent) => { e.preventDefault(); advanceStep(); }; From d21a6619fdba935c288b36ec3b25c93fd5a022a2 Mon Sep 17 00:00:00 2001 From: scottybollinger Date: Wed, 18 Nov 2020 17:46:37 -0600 Subject: [PATCH 07/11] Fix index paths --- .../views/content_sources/components/add_source/index.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/index.ts b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/index.ts index 02f0e1db7ff0b7..8a46eaa7d70e95 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/index.ts +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/index.ts @@ -4,5 +4,5 @@ * you may not use this file except in compliance with the Elastic License. */ -export { AddSource } from './AddSource'; -export { AddSourceList } from './AddSourceList'; +export { AddSource } from './add_source'; +export { AddSourceList } from './add_source_list'; From bce570c2760f09c17e84eaf1a45c0ba889fd4d0b Mon Sep 17 00:00:00 2001 From: scottybollinger Date: Wed, 18 Nov 2020 17:50:36 -0600 Subject: [PATCH 08/11] Remove in-page breadcrumbs and move sidebar copy In Kibana, breadcrumbs will be at the top-level and not in the view Also, we have no sidebar with contextual copy. The Figma designs call for this copy to be above the main content. For now I am placing this in the existing ViewContentHeader component. This will be slightly broken because of the structure of ViewContentHeader but that is expected for now since it cannot be rendered in the browser yet to fix --- .../components/add_source/add_source.tsx | 20 +--- .../components/add_source/add_source_list.tsx | 108 +++++++++--------- 2 files changed, 61 insertions(+), 67 deletions(-) diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/add_source.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/add_source.tsx index fa4f206800fbee..7b6d02c36c0ccc 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/add_source.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/add_source.tsx @@ -12,11 +12,12 @@ import { useHistory } from 'react-router-dom'; import { AppLogic } from '../../../../app_logic'; import { Loading } from '../../../../../../applications/shared/loading'; +import { ViewContentHeader } from '../../../../components/shared/view_content_header'; import { CUSTOM_SERVICE_TYPE } from '../../../../constants'; import { staticSourceData } from '../../source_data'; import { SourceLogic } from '../../source_logic'; import { SourceDataItem, FeatureIds } from '../../../../types'; -import { ADD_SOURCE_PATH, SOURCE_ADDED_PATH, getSourcesPath } from '../../../../routes'; +import { SOURCE_ADDED_PATH, getSourcesPath } from '../../../../routes'; import { AddSourceHeader } from './add_source_header'; import { ConfigCompleted } from './config_completed'; @@ -88,11 +89,6 @@ export const AddSource: React.FC = ({ return resetSourceState; }, []); - const breadcrumbs = { - topLevelPath: getSourcesPath(ADD_SOURCE_PATH, isOrganization), - topLevelName: '← Back to sources', - }; - const isCustom = serviceType === CUSTOM_SERVICE_TYPE; const isRemote = features?.platinumPrivateContext.includes(FeatureIds.Remote); @@ -125,7 +121,7 @@ export const AddSource: React.FC = ({ history.push(`${getSourcesPath(SOURCE_ADDED_PATH, isOrganization)}/?name=${sourceName}`); }; - const sidebarTitle = () => { + const pageTitle = () => { if (currentStep === Steps.ConnectInstanceStep || currentStep === Steps.ConfigureOauthStep) { return 'Connect'; } @@ -172,17 +168,17 @@ export const AddSource: React.FC = ({ ? CONNECT_ORGANIZATION_SOURCE_SIDEBAR_BLURB : CONNECT_PRIVATE_SOURCE_SIDEBAR_BLURB; - const sidebarBlurb = + const PAGE_DESCRIPTION = currentStep === Steps.ConnectInstanceStep ? CONNECT_SIDEBAR_BLURB : CONFIG_SIDEBAR_BLURB; const header = ; return ( <> + {currentStep === Steps.ConfigIntroStep && ( )} - {currentStep === Steps.SaveConfigStep && ( = ({ header={header} /> )} - {currentStep === Steps.ConfigCompletedStep && ( = ({ header={header} /> )} - {currentStep === Steps.ConnectInstanceStep && ( = ({ header={header} /> )} - {currentStep === Steps.ConfigureCustomStep && ( = ({ header={header} /> )} - {currentStep === Steps.ConfigureOauthStep && ( )} - {currentStep === Steps.SaveCustomStep && ( = ({ header={header} /> )} - {currentStep === Steps.ReAuthenticateStep && } ); diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/add_source_list.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/add_source_list.tsx index 650510619bd0ef..24c3a8f8ddb3b4 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/add_source_list.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/add_source_list.tsx @@ -21,10 +21,10 @@ import { import { AppLogic } from '../../../../app_logic'; import { ContentSection } from '../../../../components/shared/content_section'; +import { ViewContentHeader } from '../../../../components/shared/view_content_header'; import { Loading } from '../../../../../../applications/shared/loading'; import { CUSTOM_SERVICE_TYPE } from '../../../../constants'; import { SourceDataItem } from '../../../../types'; -import { SOURCES_PATH, getSourcesPath } from '../../../../routes'; import { SourcesLogic } from '../../sources_logic'; import { AvailableSourcesList } from './available_sources_list'; @@ -64,18 +64,14 @@ export const AddSourceList: React.FC = () => { ({ serviceType }) => serviceType !== CUSTOM_SERVICE_TYPE ); - const breadcrumbs = { - topLevelPath: getSourcesPath(SOURCES_PATH, isOrganization), - topLevelName: `${isOrganization ? 'Shared' : 'Private'} content sources`, - activeName: 'Add', - }; - - const SIDEBAR_DESCRIPTION = hasSources ? '' : NEW_SOURCE_DESCRIPTION; - const SIDEBAR_CONTEXT_DESCRIPTION = isOrganization + const BASE_DESCRIPTION = hasSources ? '' : NEW_SOURCE_DESCRIPTION; + const PAGE_CONTEXT_DESCRIPTION = isOrganization ? ORG_SOURCE_DESCRIPTION : PRIVATE_SOURCE_DESCRIPTION; + + const PAGE_DESCRIPTION = BASE_DESCRIPTION + PAGE_CONTEXT_DESCRIPTION; const HAS_SOURCES_TITLE = isOrganization ? ORG_SOURCES_TITLE : PRIVATE_SOURCES_TITLE; - const SIDEBAR_TITLE = hasSources ? HAS_SOURCES_TITLE : NO_SOURCES_TITLE; + const PAGE_TITLE = hasSources ? HAS_SOURCES_TITLE : NO_SOURCES_TITLE; const handleFilterChange = (e: ChangeEvent) => setFilterValue(e.target.value); @@ -98,48 +94,56 @@ export const AddSourceList: React.FC = () => { filterConfiguredSources ) as SourceDataItem[]; - return showConfiguredSourcesList || isOrganization ? ( - - - - - - - {showConfiguredSourcesList && ( - - )} - {isOrganization && } - - ) : ( - - - - - - - - No available sources} - body={ -

- Sources will be available for search when an administrator adds them to this - organization. -

- } + return ( + <> + + {showConfiguredSourcesList || isOrganization ? ( + + + + + + + {showConfiguredSourcesList && ( + - - -
- -
-
-
+ )} + {isOrganization && } + + ) : ( + + + + + + + + No available sources} + body={ +

+ Sources will be available for search when an administrator adds them to this + organization. +

+ } + /> + + +
+ +
+
+
+ )} + ); }; From c7c4bd2863e554b5c8dae21d8b7a6b9e29dfc5ad Mon Sep 17 00:00:00 2001 From: scottybollinger Date: Thu, 19 Nov 2020 08:26:24 -0600 Subject: [PATCH 09/11] Temporarily add parseQueryParams This is a placeholder until https://github.com/elastic/kibana/pull/83750 lands --- .../public/applications/shared/query_params/index.ts | 7 +++++++ .../applications/shared/query_params/query_params.ts | 10 ++++++++++ 2 files changed, 17 insertions(+) create mode 100644 x-pack/plugins/enterprise_search/public/applications/shared/query_params/index.ts create mode 100644 x-pack/plugins/enterprise_search/public/applications/shared/query_params/query_params.ts diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/query_params/index.ts b/x-pack/plugins/enterprise_search/public/applications/shared/query_params/index.ts new file mode 100644 index 00000000000000..61eb1792911eeb --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/shared/query_params/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 { parseQueryParams } from './query_params'; diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/query_params/query_params.ts b/x-pack/plugins/enterprise_search/public/applications/shared/query_params/query_params.ts new file mode 100644 index 00000000000000..f39760d27fbf33 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/shared/query_params/query_params.ts @@ -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; + * you may not use this file except in compliance with the Elastic License. + */ + +import queryString from 'query-string'; + +export const parseQueryParams = (search: string) => + queryString.parse(search, { arrayFormat: 'bracket' }); From 7fae6a403d02cb883f21894faaaa4eb9b53a52e8 Mon Sep 17 00:00:00 2001 From: scottybollinger Date: Thu, 19 Nov 2020 11:35:33 -0600 Subject: [PATCH 10/11] Remove optional from isOrganization Looks like the value is always passed --- .../components/add_source/configured_sources_list.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/configured_sources_list.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/configured_sources_list.tsx index 792db71fef02e6..7e23b88c575382 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/configured_sources_list.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/configured_sources_list.tsx @@ -26,7 +26,7 @@ import { getSourcesPath } from '../../../../routes'; interface ConfiguredSourcesProps { sources: SourceDataItem[]; - isOrganization?: boolean; + isOrganization: boolean; } export const ConfiguredSourcesList: React.FC = ({ From cffe5d7a9aa480d253350118c418c09c554ad182 Mon Sep 17 00:00:00 2001 From: scottybollinger Date: Thu, 19 Nov 2020 11:36:32 -0600 Subject: [PATCH 11/11] =?UTF-8?q?Remove=20=E2=80=98!!=E2=80=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/add_source/configured_sources_list.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/configured_sources_list.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/configured_sources_list.tsx index 7e23b88c575382..a95d5ca75b0b69 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/configured_sources_list.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/add_source/configured_sources_list.tsx @@ -89,7 +89,7 @@ export const ConfiguredSourcesList: React.FC = ({ {(!isOrganization || (isOrganization && !accountContextOnly)) && ( - + Connect