Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[7.x] [Enterprise Search] Adds app logic file to Workplace Search (#76009) #76040

Merged
merged 1 commit into from
Aug 26, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ export const DEFAULT_INITIAL_APP_DATA = {
},
},
workplaceSearch: {
canCreateInvitations: true,
isFederatedAuth: false,
organization: {
name: 'ACME Donuts',
defaultOrgName: 'My Organization',
Expand Down
7 changes: 2 additions & 5 deletions x-pack/plugins/enterprise_search/common/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,14 @@
*/

import { IAccount as IAppSearchAccount } from './app_search';
import { IAccount as IWorkplaceSearchAccount, IOrganization } from './workplace_search';
import { IWorkplaceSearchInitialData } from './workplace_search';

export interface IInitialAppData {
readOnlyMode?: boolean;
ilmEnabled?: boolean;
configuredLimits?: IConfiguredLimits;
appSearch?: IAppSearchAccount;
workplaceSearch?: {
organization: IOrganization;
fpAccount: IWorkplaceSearchAccount;
};
workplaceSearch?: IWorkplaceSearchInitialData;
}

export interface IConfiguredLimits {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,10 @@ export interface IOrganization {
name: string;
defaultOrgName: string;
}

export interface IWorkplaceSearchInitialData {
canCreateInvitations: boolean;
isFederatedAuth: boolean;
organization: IOrganization;
fpAccount: IAccount;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* 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 { resetContext } from 'kea';

import { DEFAULT_INITIAL_APP_DATA } from '../../../common/__mocks__';
import { AppLogic } from './app_logic';

describe('AppLogic', () => {
beforeEach(() => {
resetContext({});
AppLogic.mount();
});

const DEFAULT_VALUES = {
hasInitialized: false,
};

it('has expected default values', () => {
expect(AppLogic.values).toEqual(DEFAULT_VALUES);
});

describe('initializeAppData()', () => {
it('sets values based on passed props', () => {
AppLogic.actions.initializeAppData(DEFAULT_INITIAL_APP_DATA);

expect(AppLogic.values).toEqual({
hasInitialized: true,
});
});
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
* 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 { kea } from 'kea';

import { IInitialAppData } from '../../../common/types';
import { IWorkplaceSearchInitialData } from '../../../common/types/workplace_search';
import { IKeaLogic } from '../shared/types';

export interface IAppValues extends IWorkplaceSearchInitialData {
hasInitialized: boolean;
}
export interface IAppActions {
initializeAppData(props: IInitialAppData): void;
}

export const AppLogic = kea({
actions: (): IAppActions => ({
initializeAppData: ({ workplaceSearch }) => workplaceSearch,
}),
reducers: () => ({
hasInitialized: [
false,
{
initializeAppData: () => true,
},
],
}),
}) as IKeaLogic<IAppValues, IAppActions>;
Original file line number Diff line number Diff line change
Expand Up @@ -10,39 +10,76 @@ import '../__mocks__/kea.mock';
import React, { useContext } from 'react';
import { Redirect } from 'react-router-dom';
import { shallow } from 'enzyme';
import { useValues } from 'kea';
import { useValues, useActions } from 'kea';

import { Overview } from './views/overview';
import { SetupGuide } from './views/setup_guide';
import { ErrorState } from './views/error_state';
import { Overview } from './views/overview';

import { WorkplaceSearch } from './';
import { WorkplaceSearch, WorkplaceSearchUnconfigured, WorkplaceSearchConfigured } from './';

describe('Workplace Search', () => {
it('redirects to Setup Guide when enterpriseSearchUrl is not set', () => {
(useContext as jest.Mock).mockImplementationOnce(() => ({
config: { host: '' },
}));
describe('WorkplaceSearch', () => {
it('renders WorkplaceSearchUnconfigured when config.host is not set', () => {
(useContext as jest.Mock).mockImplementationOnce(() => ({ config: { host: '' } }));
const wrapper = shallow(<WorkplaceSearch />);

expect(wrapper.find(Redirect)).toHaveLength(1);
expect(wrapper.find(Overview)).toHaveLength(0);
expect(wrapper.find(WorkplaceSearchUnconfigured)).toHaveLength(1);
});

it('renders the Overview when enterpriseSearchUrl is set', () => {
(useContext as jest.Mock).mockImplementationOnce(() => ({
config: { host: 'https://foo.bar' },
}));
it('renders WorkplaceSearchConfigured when config.host set', () => {
(useContext as jest.Mock).mockImplementationOnce(() => ({ config: { host: 'some.url' } }));
const wrapper = shallow(<WorkplaceSearch />);

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

describe('WorkplaceSearchUnconfigured', () => {
it('renders the Setup Guide and redirects to the Setup Guide', () => {
const wrapper = shallow(<WorkplaceSearchUnconfigured />);

expect(wrapper.find(SetupGuide)).toHaveLength(1);
expect(wrapper.find(Redirect)).toHaveLength(1);
});
});

describe('WorkplaceSearchConfigured', () => {
beforeEach(() => {
// Mock resets
(useValues as jest.Mock).mockImplementation(() => ({}));
(useActions as jest.Mock).mockImplementation(() => ({ initializeAppData: () => {} }));
});

it('renders with layout', () => {
const wrapper = shallow(<WorkplaceSearchConfigured />);

expect(wrapper.find(Overview)).toHaveLength(1);
expect(wrapper.find(Redirect)).toHaveLength(0);
});

it('renders ErrorState when the app cannot connect to Enterprise Search', () => {
(useValues as jest.Mock).mockImplementationOnce(() => ({ errorConnecting: true }));
const wrapper = shallow(<WorkplaceSearch />);
it('initializes app data with passed props', () => {
const initializeAppData = jest.fn();
(useActions as jest.Mock).mockImplementation(() => ({ initializeAppData }));

shallow(<WorkplaceSearchConfigured readOnlyMode={true} />);

expect(initializeAppData).toHaveBeenCalledWith({ readOnlyMode: true });
});

it('does not re-initialize app data', () => {
const initializeAppData = jest.fn();
(useActions as jest.Mock).mockImplementation(() => ({ initializeAppData }));
(useValues as jest.Mock).mockImplementation(() => ({ hasInitialized: true }));

shallow(<WorkplaceSearchConfigured />);

expect(initializeAppData).not.toHaveBeenCalled();
});

it('renders ErrorState', () => {
(useValues as jest.Mock).mockImplementation(() => ({ errorConnecting: true }));

const wrapper = shallow(<WorkplaceSearchConfigured />);

expect(wrapper.find(ErrorState).exists()).toBe(true);
expect(wrapper.find(Overview)).toHaveLength(0);
expect(wrapper.find(ErrorState)).toHaveLength(2);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@
* you may not use this file except in compliance with the Elastic License.
*/

import React, { useContext } from 'react';
import React, { useContext, useEffect } from 'react';
import { Route, Redirect, Switch } from 'react-router-dom';
import { useValues } from 'kea';
import { useActions, useValues } from 'kea';

import { IInitialAppData } from '../../../common/types';
import { KibanaContext, IKibanaContext } from '../index';
import { HttpLogic, IHttpLogicValues } from '../shared/http';
import { AppLogic, IAppActions, IAppValues } from './app_logic';
import { Layout } from '../shared/layout';
import { WorkplaceSearchNav } from './components/layout/nav';

Expand All @@ -20,21 +21,19 @@ import { SetupGuide } from './views/setup_guide';
import { ErrorState } from './views/error_state';
import { Overview } from './views/overview';

export const WorkplaceSearch: React.FC<IInitialAppData> = () => {
export const WorkplaceSearch: React.FC<IInitialAppData> = (props) => {
const { config } = useContext(KibanaContext) as IKibanaContext;
return !config.host ? <WorkplaceSearchUnconfigured /> : <WorkplaceSearchConfigured {...props} />;
};

export const WorkplaceSearchConfigured: React.FC<IInitialAppData> = (props) => {
const { hasInitialized } = useValues(AppLogic) as IAppValues;
const { initializeAppData } = useActions(AppLogic) as IAppActions;
const { errorConnecting } = useValues(HttpLogic) as IHttpLogicValues;

if (!config.host)
return (
<Switch>
<Route exact path={SETUP_GUIDE_PATH}>
<SetupGuide />
</Route>
<Route>
<Redirect to={SETUP_GUIDE_PATH} />
</Route>
</Switch>
);
useEffect(() => {
if (!hasInitialized) initializeAppData(props);
}, [hasInitialized]);

return (
<Switch>
Expand All @@ -61,3 +60,14 @@ export const WorkplaceSearch: React.FC<IInitialAppData> = () => {
</Switch>
);
};

export const WorkplaceSearchUnconfigured: React.FC = () => (
<Switch>
<Route exact path={SETUP_GUIDE_PATH}>
<SetupGuide />
</Route>
<Route>
<Redirect to={SETUP_GUIDE_PATH} />
</Route>
</Switch>
);
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ describe('callEnterpriseSearchConfigAPI', () => {
onboarding_complete: true,
},
workplace_search: {
can_create_invitations: true,
is_federated_auth: false,
organization: {
name: 'ACME Donuts',
default_org_name: 'My Organization',
Expand Down Expand Up @@ -136,6 +138,8 @@ describe('callEnterpriseSearchConfigAPI', () => {
},
},
workplaceSearch: {
canCreateInvitations: false,
isFederatedAuth: false,
organization: {
name: undefined,
defaultOrgName: undefined,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,8 @@ export const callEnterpriseSearchConfigAPI = async ({
},
},
workplaceSearch: {
canCreateInvitations: !!data?.settings?.workplace_search?.can_create_invitations,
isFederatedAuth: !!data?.settings?.workplace_search?.is_federated_auth,
organization: {
name: data?.settings?.workplace_search?.organization?.name,
defaultOrgName: data?.settings?.workplace_search?.organization?.default_org_name,
Expand Down