Skip to content

Commit

Permalink
[Workplace Search] Add UI logic for GitHub Configure Step (#95254)
Browse files Browse the repository at this point in the history
* Fix typo

This was mis-copied from ent-search

* No longer store preContentSourceId in query param

In ent-search, we had the Rails server redirect with this param. Now, it is contained in the server response as JSON and is persisted in the logic file

* Pass query params to SourceAdded component

The entire state is stored in query params now and must be passed when doing a manual redirect

* Redirect to config view if config needed

* Don’t redirect if the config has already been completed

This was really tricky and could use a refactor in the future, perhaps. The issue is that the persisted query params will contain the `preContentSourceId` even after the config has been completed. This caused the UI to attempt to navigate back to the config screen after it had been completed. This sets a prop once that has been completed and bypasses the redirect.

* Use correct key to determine if config needed

* Update tests
  • Loading branch information
scottybollinger authored and kibanamachine committed Mar 25, 2021
1 parent 0dc832b commit 86b5456
Show file tree
Hide file tree
Showing 5 changed files with 90 additions and 26 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
*/

import React, { useEffect } from 'react';
import { useLocation } from 'react-router-dom';

import { Location } from 'history';

import { useActions, useValues } from 'kea';

Expand All @@ -31,6 +34,7 @@ import { SaveCustom } from './save_custom';
import './add_source.scss';

export const AddSource: React.FC<AddSourceProps> = (props) => {
const { search } = useLocation() as Location;
const {
initializeAddSource,
setAddSourceStep,
Expand Down Expand Up @@ -83,9 +87,9 @@ export const AddSource: React.FC<AddSourceProps> = (props) => {
const saveCustomSuccess = () => setAddSourceStep(AddSourceSteps.SaveCustomStep);
const goToSaveCustom = () => createContentSource(CUSTOM_SERVICE_TYPE, saveCustomSuccess);

const goToFormSourceCreated = (sourceName: string) => {
const goToFormSourceCreated = () => {
KibanaLogic.values.navigateToUrl(
`${getSourcesPath(SOURCE_ADDED_PATH, isOrganization)}/?name=${sourceName}`
`${getSourcesPath(SOURCE_ADDED_PATH, isOrganization)}${search}`
);
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ jest.mock('../../../../app_logic', () => ({
}));
import { AppLogic } from '../../../../app_logic';

import { SOURCES_PATH, getSourcesPath } from '../../../../routes';
import { ADD_GITHUB_PATH, SOURCES_PATH, getSourcesPath } from '../../../../routes';
import { CustomSource } from '../../../../types';
import { SourcesLogic } from '../../sources_logic';

Expand Down Expand Up @@ -55,10 +55,12 @@ describe('AddSourceLogic', () => {
sourceConfigData: {} as SourceConfigData,
sourceConnectData: {} as SourceConnectData,
newCustomSource: {} as CustomSource,
oauthConfigCompleted: false,
currentServiceType: '',
githubOrganizations: [],
selectedGithubOrganizationsMap: {} as OrganizationsMap,
selectedGithubOrganizations: [],
preContentSourceId: '',
};

const sourceConnectData = {
Expand Down Expand Up @@ -182,6 +184,12 @@ describe('AddSourceLogic', () => {
expect(AddSourceLogic.values.selectedGithubOrganizationsMap).toEqual({ foo: true });
});

it('setPreContentSourceId', () => {
AddSourceLogic.actions.setPreContentSourceId('123');

expect(AddSourceLogic.values.preContentSourceId).toEqual('123');
});

it('setButtonNotLoading', () => {
AddSourceLogic.actions.setButtonNotLoading();

Expand Down Expand Up @@ -317,6 +325,34 @@ describe('AddSourceLogic', () => {
expect(navigateToUrl).toHaveBeenCalledWith(getSourcesPath(SOURCES_PATH, false));
});

it('redirects to oauth config when preContentSourceId is present', async () => {
const preContentSourceId = 'id123';
const setPreContentSourceIdSpy = jest.spyOn(
AddSourceLogic.actions,
'setPreContentSourceId'
);

http.get.mockReturnValue(
Promise.resolve({
...response,
hasConfigureStep: true,
preContentSourceId,
})
);
AddSourceLogic.actions.saveSourceParams(queryString);
expect(http.get).toHaveBeenCalledWith('/api/workplace_search/sources/create', {
query: {
...params,
kibana_host: '',
},
});

await nextTick();

expect(setPreContentSourceIdSpy).toHaveBeenCalledWith(preContentSourceId);
expect(navigateToUrl).toHaveBeenCalledWith(`${ADD_GITHUB_PATH}/configure${queryString}`);
});

it('handles error', async () => {
http.get.mockReturnValue(Promise.reject('this is an error'));

Expand Down Expand Up @@ -440,13 +476,14 @@ describe('AddSourceLogic', () => {

describe('getPreContentSourceConfigData', () => {
it('calls API and sets values', async () => {
mount({ preContentSourceId: '123' });
const setPreContentSourceConfigDataSpy = jest.spyOn(
AddSourceLogic.actions,
'setPreContentSourceConfigData'
);
http.get.mockReturnValue(Promise.resolve(config));

AddSourceLogic.actions.getPreContentSourceConfigData('123');
AddSourceLogic.actions.getPreContentSourceConfigData();

expect(http.get).toHaveBeenCalledWith('/api/workplace_search/org/pre_sources/123');
await nextTick();
Expand All @@ -456,7 +493,7 @@ describe('AddSourceLogic', () => {
it('handles error', async () => {
http.get.mockReturnValue(Promise.reject('this is an error'));

AddSourceLogic.actions.getPreContentSourceConfigData('123');
AddSourceLogic.actions.getPreContentSourceConfigData();
await nextTick();

expect(flashAPIErrors).toHaveBeenCalledWith('this is an error');
Expand Down Expand Up @@ -616,7 +653,8 @@ describe('AddSourceLogic', () => {
});

it('getPreContentSourceConfigData', () => {
AddSourceLogic.actions.getPreContentSourceConfigData('123');
mount({ preContentSourceId: '123' });
AddSourceLogic.actions.getPreContentSourceConfigData();

expect(http.get).toHaveBeenCalledWith('/api/workplace_search/account/pre_sources/123');
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import { KibanaLogic } from '../../../../../shared/kibana';
import { parseQueryParams } from '../../../../../shared/query_params';
import { AppLogic } from '../../../../app_logic';
import { CUSTOM_SERVICE_TYPE, WORKPLACE_SEARCH_URL_PREFIX } from '../../../../constants';
import { SOURCES_PATH, getSourcesPath } from '../../../../routes';
import { SOURCES_PATH, ADD_GITHUB_PATH, getSourcesPath } from '../../../../routes';
import { CustomSource } from '../../../../types';
import { staticSourceData } from '../../source_data';
import { SourcesLogic } from '../../sources_logic';
Expand Down Expand Up @@ -74,6 +74,7 @@ export interface AddSourceActions {
setSourceIndexPermissionsValue(indexPermissionsValue: boolean): boolean;
setCustomSourceData(data: CustomSource): CustomSource;
setPreContentSourceConfigData(data: PreContentSourceResponse): PreContentSourceResponse;
setPreContentSourceId(preContentSourceId: string): string;
setSelectedGithubOrganizations(option: string): string;
resetSourceState(): void;
createContentSource(
Expand All @@ -92,7 +93,7 @@ export interface AddSourceActions {
successCallback: (oauthUrl: string) => void
): { serviceType: string; successCallback(oauthUrl: string): void };
getSourceReConnectData(sourceId: string): { sourceId: string };
getPreContentSourceConfigData(preContentSourceId: string): { preContentSourceId: string };
getPreContentSourceConfigData(): void;
setButtonNotLoading(): void;
}

Expand Down Expand Up @@ -144,6 +145,8 @@ interface AddSourceValues {
githubOrganizations: string[];
selectedGithubOrganizationsMap: OrganizationsMap;
selectedGithubOrganizations: string[];
preContentSourceId: string;
oauthConfigCompleted: boolean;
}

interface PreContentSourceResponse {
Expand Down Expand Up @@ -181,14 +184,15 @@ export const AddSourceLogic = kea<MakeLogicType<AddSourceValues, AddSourceAction
setSourceIndexPermissionsValue: (indexPermissionsValue: boolean) => indexPermissionsValue,
setCustomSourceData: (data: CustomSource) => data,
setPreContentSourceConfigData: (data: PreContentSourceResponse) => data,
setPreContentSourceId: (preContentSourceId: string) => preContentSourceId,
setSelectedGithubOrganizations: (option: string) => option,
getSourceConfigData: (serviceType: string) => ({ serviceType }),
getSourceConnectData: (serviceType: string, successCallback: (oauthUrl: string) => string) => ({
serviceType,
successCallback,
}),
getSourceReConnectData: (sourceId: string) => ({ sourceId }),
getPreContentSourceConfigData: (preContentSourceId: string) => ({ preContentSourceId }),
getPreContentSourceConfigData: () => true,
saveSourceConfig: (isUpdating: boolean, successCallback?: () => void) => ({
isUpdating,
successCallback,
Expand Down Expand Up @@ -344,6 +348,20 @@ export const AddSourceLogic = kea<MakeLogicType<AddSourceValues, AddSourceAction
resetSourceState: () => ({}),
},
],
preContentSourceId: [
'',
{
setPreContentSourceId: (_, preContentSourceId) => preContentSourceId,
setPreContentSourceConfigData: () => '',
resetSourceState: () => '',
},
],
oauthConfigCompleted: [
false,
{
setPreContentSourceConfigData: () => true,
},
],
},
selectors: ({ selectors }) => ({
selectedGithubOrganizations: [
Expand Down Expand Up @@ -407,8 +425,9 @@ export const AddSourceLogic = kea<MakeLogicType<AddSourceValues, AddSourceAction
flashAPIErrors(e);
}
},
getPreContentSourceConfigData: async ({ preContentSourceId }) => {
getPreContentSourceConfigData: async () => {
const { isOrganization } = AppLogic.values;
const { preContentSourceId } = values;
const route = isOrganization
? `/api/workplace_search/org/pre_sources/${preContentSourceId}`
: `/api/workplace_search/account/pre_sources/${preContentSourceId}`;
Expand Down Expand Up @@ -480,12 +499,24 @@ export const AddSourceLogic = kea<MakeLogicType<AddSourceValues, AddSourceAction

try {
const response = await http.get(route, { query });

const { serviceName, indexPermissions, serviceType } = response;
setAddedSource(serviceName, indexPermissions, serviceType);
const {
serviceName,
indexPermissions,
serviceType,
preContentSourceId,
hasConfigureStep,
} = response;

// GitHub requires an intermediate configuration step, where we collect the repos to index.
if (hasConfigureStep && !values.oauthConfigCompleted) {
actions.setPreContentSourceId(preContentSourceId);
navigateToUrl(`${ADD_GITHUB_PATH}/configure${search}`);
} else {
setAddedSource(serviceName, indexPermissions, serviceType);
navigateToUrl(getSourcesPath(SOURCES_PATH, isOrganization));
}
} catch (e) {
flashAPIErrors(e);
} finally {
navigateToUrl(getSourcesPath(SOURCES_PATH, isOrganization));
}
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,7 @@
*/

import React, { useEffect, useState, FormEvent } from 'react';
import { useLocation } from 'react-router-dom';

import { Location } from 'history';
import { useActions, useValues } from 'kea';

import {
Expand All @@ -22,25 +20,17 @@ import {
import { EuiCheckboxGroupIdToSelectedMap } from '@elastic/eui/src/components/form/checkbox/checkbox_group';

import { Loading } from '../../../../../shared/loading';
import { parseQueryParams } from '../../../../../shared/query_params';

import { AddSourceLogic } from './add_source_logic';
import { CONFIG_OAUTH_LABEL, CONFIG_OAUTH_BUTTON } from './constants';

interface OauthQueryParams {
preContentSourceId: string;
}

interface ConfigureOauthProps {
header: React.ReactNode;
name: string;
onFormCreated(name: string): void;
}

export const ConfigureOauth: React.FC<ConfigureOauthProps> = ({ name, onFormCreated, header }) => {
const { search } = useLocation() as Location;

const { preContentSourceId } = (parseQueryParams(search) as unknown) as OauthQueryParams;
const [formLoading, setFormLoading] = useState(false);

const {
Expand All @@ -58,7 +48,7 @@ export const ConfigureOauth: React.FC<ConfigureOauthProps> = ({ name, onFormCrea
const checkboxOptions = githubOrganizations.map((item) => ({ id: item, label: item }));

useEffect(() => {
getPreContentSourceConfigData(preContentSourceId);
getPreContentSourceConfigData();
}, []);

const handleChange = (option: string) => setSelectedGithubOrganizations(option);
Expand Down Expand Up @@ -101,6 +91,7 @@ export const ConfigureOauth: React.FC<ConfigureOauthProps> = ({ name, onFormCrea
return (
<>
{header}
<EuiSpacer />
{sectionLoading ? <Loading /> : configfieldsForm}
</>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ export const CONFIG_CUSTOM_BUTTON = i18n.translate(
export const CONFIG_OAUTH_LABEL = i18n.translate(
'xpack.enterpriseSearch.workplaceSearch.contentSource.configOauth.label',
{
defaultMessage: 'Complete connection',
defaultMessage: 'Select GitHub organizations to sync',
}
);

Expand Down

0 comments on commit 86b5456

Please sign in to comment.