mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
[Enterprise Search] Add reusable FlashMessages helper (#75901)
* Set up basic shared FlashMessages & FlashMessagesLogic * Add top-level FlashMessagesProvider and history listener - This ensures that: - Our FlashMessagesLogic is a global state that persists throughout the entire app and only unmounts when the app itself does (allowing for persistent messages if needed) - history.listen enables the same behavior as previously, where flash messages would be cleared between page views * Set up queued messages that appear on page nav/load * [AS] Add FlashMessages component to Engines Overview + add Kea/Redux context/state to mountWithContext (in order for tests to pass) * Fix missing type exports, replace previous IFlashMessagesProps * [WS] Remove flashMessages state in OverviewLogic - in favor of either connecting it or using FlashMessagesLogic directly in the future * PR feedback: DRY out EUI callout color type def * PR Feedback: make flashMessages method names more explicit * PR Feedback: Shorter FlashMessagesLogic type names * PR feedback: Typing Co-authored-by: Byron Hulcher <byronhulcher@gmail.com> Co-authored-by: Byron Hulcher <byronhulcher@gmail.com>
This commit is contained in:
parent
1bd8f41275
commit
a7b0f7a102
14 changed files with 434 additions and 29 deletions
|
@ -8,6 +8,10 @@ import React from 'react';
|
|||
import { act } from 'react-dom/test-utils';
|
||||
import { mount, ReactWrapper } from 'enzyme';
|
||||
|
||||
import { Provider } from 'react-redux';
|
||||
import { Store } from 'redux';
|
||||
import { getContext, resetContext } from 'kea';
|
||||
|
||||
import { I18nProvider } from '@kbn/i18n/react';
|
||||
import { KibanaContext } from '../';
|
||||
import { mockKibanaContext } from './kibana_context.mock';
|
||||
|
@ -24,11 +28,14 @@ import { mockLicenseContext } from './license_context.mock';
|
|||
* const wrapper = mountWithContext(<Component />, { config: { host: 'someOverride' } });
|
||||
*/
|
||||
export const mountWithContext = (children: React.ReactNode, context?: object) => {
|
||||
resetContext({ createStore: true });
|
||||
const store = getContext().store as Store;
|
||||
|
||||
return mount(
|
||||
<I18nProvider>
|
||||
<KibanaContext.Provider value={{ ...mockKibanaContext, ...context }}>
|
||||
<LicenseContext.Provider value={{ ...mockLicenseContext, ...context }}>
|
||||
{children}
|
||||
<Provider store={store}>{children}</Provider>
|
||||
</LicenseContext.Provider>
|
||||
</KibanaContext.Provider>
|
||||
</I18nProvider>
|
||||
|
|
|
@ -16,6 +16,7 @@ import { FormattedMessage } from '@kbn/i18n/react';
|
|||
|
||||
import { SetAppSearchChrome as SetPageChrome } from '../../../shared/kibana_chrome';
|
||||
import { SendAppSearchTelemetry as SendTelemetry } from '../../../shared/telemetry';
|
||||
import { FlashMessages } from '../../../shared/flash_messages';
|
||||
import { LicenseContext, ILicenseContext, hasPlatinumLicense } from '../../../shared/licensing';
|
||||
import { KibanaContext, IKibanaContext } from '../../../index';
|
||||
|
||||
|
@ -88,6 +89,7 @@ export const EngineOverview: React.FC = () => {
|
|||
|
||||
<EngineOverviewHeader />
|
||||
<EuiPageContent panelPaddingSize="s" className="engineOverview">
|
||||
<FlashMessages />
|
||||
<EuiPageContentHeader>
|
||||
<EuiTitle size="s">
|
||||
<h2>
|
||||
|
|
|
@ -22,6 +22,7 @@ import {
|
|||
} from 'src/core/public';
|
||||
import { ClientConfigType, ClientData, PluginsSetup } from '../plugin';
|
||||
import { LicenseProvider } from './shared/licensing';
|
||||
import { FlashMessagesProvider } from './shared/flash_messages';
|
||||
import { HttpProvider } from './shared/http';
|
||||
import { IExternalUrl } from './shared/enterprise_search_url';
|
||||
import { IInitialAppData } from '../../common/types';
|
||||
|
@ -69,6 +70,7 @@ export const renderApp = (
|
|||
<LicenseProvider license$={plugins.licensing.license$}>
|
||||
<Provider store={store}>
|
||||
<HttpProvider http={core.http} errorConnecting={errorConnecting} />
|
||||
<FlashMessagesProvider history={params.history} />
|
||||
<Router history={params.history}>
|
||||
<App {...initialData} />
|
||||
</Router>
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import '../../__mocks__/kea.mock';
|
||||
|
||||
import { useValues } from 'kea';
|
||||
import React from 'react';
|
||||
import { shallow } from 'enzyme';
|
||||
import { EuiCallOut } from '@elastic/eui';
|
||||
|
||||
import { FlashMessages } from './';
|
||||
|
||||
describe('FlashMessages', () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
it('does not render if no messages exist', () => {
|
||||
(useValues as jest.Mock).mockImplementationOnce(() => ({ messages: [] }));
|
||||
|
||||
const wrapper = shallow(<FlashMessages />);
|
||||
|
||||
expect(wrapper.isEmptyRender()).toBe(true);
|
||||
});
|
||||
|
||||
it('renders an array of flash messages & types', () => {
|
||||
const mockMessages = [
|
||||
{ type: 'success', message: 'Hello world!!' },
|
||||
{
|
||||
type: 'error',
|
||||
message: 'Whoa nelly!',
|
||||
description: <div data-test-subj="error">Something went wrong</div>,
|
||||
},
|
||||
{ type: 'info', message: 'Everything is fine, nothing is ruined' },
|
||||
{ type: 'warning', message: 'Uh oh' },
|
||||
{ type: 'info', message: 'Testing multiples of same type' },
|
||||
];
|
||||
(useValues as jest.Mock).mockImplementationOnce(() => ({ messages: mockMessages }));
|
||||
|
||||
const wrapper = shallow(<FlashMessages />);
|
||||
|
||||
expect(wrapper.find(EuiCallOut)).toHaveLength(5);
|
||||
expect(wrapper.find(EuiCallOut).first().prop('color')).toEqual('success');
|
||||
expect(wrapper.find('[data-test-subj="error"]')).toHaveLength(1);
|
||||
expect(wrapper.find(EuiCallOut).last().prop('iconType')).toEqual('iInCircle');
|
||||
});
|
||||
|
||||
it('renders any children', () => {
|
||||
(useValues as jest.Mock).mockImplementationOnce(() => ({ messages: [{ type: 'success' }] }));
|
||||
|
||||
const wrapper = shallow(
|
||||
<FlashMessages>
|
||||
<button data-test-subj="testing">
|
||||
Some action - you could even clear flash messages here
|
||||
</button>
|
||||
</FlashMessages>
|
||||
);
|
||||
|
||||
expect(wrapper.find('[data-test-subj="testing"]').text()).toContain('Some action');
|
||||
});
|
||||
});
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* 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, { Fragment } from 'react';
|
||||
import { useValues } from 'kea';
|
||||
import { EuiCallOut, EuiCallOutProps, EuiSpacer } from '@elastic/eui';
|
||||
|
||||
import { FlashMessagesLogic, IFlashMessagesValues } from './flash_messages_logic';
|
||||
|
||||
const FLASH_MESSAGE_TYPES = {
|
||||
success: { color: 'success' as EuiCallOutProps['color'], icon: 'check' },
|
||||
info: { color: 'primary' as EuiCallOutProps['color'], icon: 'iInCircle' },
|
||||
warning: { color: 'warning' as EuiCallOutProps['color'], icon: 'alert' },
|
||||
error: { color: 'danger' as EuiCallOutProps['color'], icon: 'cross' },
|
||||
};
|
||||
|
||||
export const FlashMessages: React.FC = ({ children }) => {
|
||||
const { messages } = useValues(FlashMessagesLogic) as IFlashMessagesValues;
|
||||
|
||||
// If we have no messages to display, do not render the element at all
|
||||
if (!messages.length) return null;
|
||||
|
||||
return (
|
||||
<div data-test-subj="FlashMessages">
|
||||
{messages.map(({ type, message, description }, index) => (
|
||||
<Fragment key={index}>
|
||||
<EuiCallOut
|
||||
color={FLASH_MESSAGE_TYPES[type].color}
|
||||
iconType={FLASH_MESSAGE_TYPES[type].icon}
|
||||
title={message}
|
||||
>
|
||||
{description}
|
||||
</EuiCallOut>
|
||||
<EuiSpacer />
|
||||
</Fragment>
|
||||
))}
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
};
|
|
@ -0,0 +1,136 @@
|
|||
/*
|
||||
* 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 { FlashMessagesLogic, IFlashMessage } from './flash_messages_logic';
|
||||
|
||||
describe('FlashMessagesLogic', () => {
|
||||
const DEFAULT_VALUES = {
|
||||
messages: [],
|
||||
queuedMessages: [],
|
||||
historyListener: null,
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
resetContext({});
|
||||
});
|
||||
|
||||
it('has expected default values', () => {
|
||||
FlashMessagesLogic.mount();
|
||||
expect(FlashMessagesLogic.values).toEqual(DEFAULT_VALUES);
|
||||
});
|
||||
|
||||
describe('setFlashMessages()', () => {
|
||||
it('sets an array of messages', () => {
|
||||
const messages: IFlashMessage[] = [
|
||||
{ type: 'success', message: 'Hello world!!' },
|
||||
{ type: 'error', message: 'Whoa nelly!', description: 'Uh oh' },
|
||||
{ type: 'info', message: 'Everything is fine, nothing is ruined' },
|
||||
];
|
||||
|
||||
FlashMessagesLogic.mount();
|
||||
FlashMessagesLogic.actions.setFlashMessages(messages);
|
||||
|
||||
expect(FlashMessagesLogic.values.messages).toEqual(messages);
|
||||
});
|
||||
|
||||
it('automatically converts to an array if a single message obj is passed in', () => {
|
||||
const message = { type: 'success', message: 'I turn into an array!' } as IFlashMessage;
|
||||
|
||||
FlashMessagesLogic.mount();
|
||||
FlashMessagesLogic.actions.setFlashMessages(message);
|
||||
|
||||
expect(FlashMessagesLogic.values.messages).toEqual([message]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('clearFlashMessages()', () => {
|
||||
it('sets messages back to an empty array', () => {
|
||||
FlashMessagesLogic.mount();
|
||||
FlashMessagesLogic.actions.setFlashMessages('test' as any);
|
||||
FlashMessagesLogic.actions.clearFlashMessages();
|
||||
|
||||
expect(FlashMessagesLogic.values.messages).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('setQueuedMessages()', () => {
|
||||
it('sets an array of messages', () => {
|
||||
const queuedMessage: IFlashMessage = { type: 'error', message: 'You deleted a thing' };
|
||||
|
||||
FlashMessagesLogic.mount();
|
||||
FlashMessagesLogic.actions.setQueuedMessages(queuedMessage);
|
||||
|
||||
expect(FlashMessagesLogic.values.queuedMessages).toEqual([queuedMessage]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('clearQueuedMessages()', () => {
|
||||
it('sets queued messages back to an empty array', () => {
|
||||
FlashMessagesLogic.mount();
|
||||
FlashMessagesLogic.actions.setQueuedMessages('test' as any);
|
||||
FlashMessagesLogic.actions.clearQueuedMessages();
|
||||
|
||||
expect(FlashMessagesLogic.values.queuedMessages).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('history listener logic', () => {
|
||||
describe('setHistoryListener()', () => {
|
||||
it('sets the historyListener value', () => {
|
||||
FlashMessagesLogic.mount();
|
||||
FlashMessagesLogic.actions.setHistoryListener('test' as any);
|
||||
|
||||
expect(FlashMessagesLogic.values.historyListener).toEqual('test');
|
||||
});
|
||||
});
|
||||
|
||||
describe('listenToHistory()', () => {
|
||||
it('listens for history changes and clears messages on change', () => {
|
||||
FlashMessagesLogic.mount();
|
||||
FlashMessagesLogic.actions.setQueuedMessages(['queuedMessages'] as any);
|
||||
jest.spyOn(FlashMessagesLogic.actions, 'clearFlashMessages');
|
||||
jest.spyOn(FlashMessagesLogic.actions, 'setFlashMessages');
|
||||
jest.spyOn(FlashMessagesLogic.actions, 'clearQueuedMessages');
|
||||
jest.spyOn(FlashMessagesLogic.actions, 'setHistoryListener');
|
||||
|
||||
const mockListener = jest.fn(() => jest.fn());
|
||||
const history = { listen: mockListener } as any;
|
||||
FlashMessagesLogic.actions.listenToHistory(history);
|
||||
|
||||
expect(mockListener).toHaveBeenCalled();
|
||||
expect(FlashMessagesLogic.actions.setHistoryListener).toHaveBeenCalled();
|
||||
|
||||
const mockHistoryChange = (mockListener.mock.calls[0] as any)[0];
|
||||
mockHistoryChange();
|
||||
expect(FlashMessagesLogic.actions.clearFlashMessages).toHaveBeenCalled();
|
||||
expect(FlashMessagesLogic.actions.setFlashMessages).toHaveBeenCalledWith([
|
||||
'queuedMessages',
|
||||
]);
|
||||
expect(FlashMessagesLogic.actions.clearQueuedMessages).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('beforeUnmount', () => {
|
||||
it('removes history listener on unmount', () => {
|
||||
const mockUnlistener = jest.fn();
|
||||
const unmount = FlashMessagesLogic.mount();
|
||||
|
||||
FlashMessagesLogic.actions.setHistoryListener(mockUnlistener);
|
||||
unmount();
|
||||
|
||||
expect(mockUnlistener).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('does not crash if no listener exists', () => {
|
||||
const unmount = FlashMessagesLogic.mount();
|
||||
unmount();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
* 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 { ReactNode } from 'react';
|
||||
import { History } from 'history';
|
||||
|
||||
import { IKeaLogic, TKeaReducers, IKeaParams } from '../types';
|
||||
|
||||
export interface IFlashMessage {
|
||||
type: 'success' | 'info' | 'warning' | 'error';
|
||||
message: ReactNode;
|
||||
description?: ReactNode;
|
||||
}
|
||||
|
||||
export interface IFlashMessagesValues {
|
||||
messages: IFlashMessage[];
|
||||
queuedMessages: IFlashMessage[];
|
||||
historyListener: Function | null;
|
||||
}
|
||||
export interface IFlashMessagesActions {
|
||||
setFlashMessages(messages: IFlashMessage | IFlashMessage[]): void;
|
||||
clearFlashMessages(): void;
|
||||
setQueuedMessages(messages: IFlashMessage | IFlashMessage[]): void;
|
||||
clearQueuedMessages(): void;
|
||||
listenToHistory(history: History): void;
|
||||
setHistoryListener(historyListener: Function): void;
|
||||
}
|
||||
|
||||
const convertToArray = (messages: IFlashMessage | IFlashMessage[]) =>
|
||||
!Array.isArray(messages) ? [messages] : messages;
|
||||
|
||||
export const FlashMessagesLogic = kea({
|
||||
actions: (): IFlashMessagesActions => ({
|
||||
setFlashMessages: (messages) => ({ messages: convertToArray(messages) }),
|
||||
clearFlashMessages: () => null,
|
||||
setQueuedMessages: (messages) => ({ messages: convertToArray(messages) }),
|
||||
clearQueuedMessages: () => null,
|
||||
listenToHistory: (history) => history,
|
||||
setHistoryListener: (historyListener) => ({ historyListener }),
|
||||
}),
|
||||
reducers: (): TKeaReducers<IFlashMessagesValues, IFlashMessagesActions> => ({
|
||||
messages: [
|
||||
[],
|
||||
{
|
||||
setFlashMessages: (_, { messages }) => messages,
|
||||
clearFlashMessages: () => [],
|
||||
},
|
||||
],
|
||||
queuedMessages: [
|
||||
[],
|
||||
{
|
||||
setQueuedMessages: (_, { messages }) => messages,
|
||||
clearQueuedMessages: () => [],
|
||||
},
|
||||
],
|
||||
historyListener: [
|
||||
null,
|
||||
{
|
||||
setHistoryListener: (_, { historyListener }) => historyListener,
|
||||
},
|
||||
],
|
||||
}),
|
||||
listeners: ({ values, actions }): Partial<IFlashMessagesActions> => ({
|
||||
listenToHistory: (history) => {
|
||||
// On React Router navigation, clear previous flash messages and load any queued messages
|
||||
const unlisten = history.listen(() => {
|
||||
actions.clearFlashMessages();
|
||||
actions.setFlashMessages(values.queuedMessages);
|
||||
actions.clearQueuedMessages();
|
||||
});
|
||||
actions.setHistoryListener(unlisten);
|
||||
},
|
||||
}),
|
||||
events: ({ values }) => ({
|
||||
beforeUnmount: () => {
|
||||
const { historyListener: removeHistoryListener } = values;
|
||||
if (removeHistoryListener) removeHistoryListener();
|
||||
},
|
||||
}),
|
||||
} as IKeaParams<IFlashMessagesValues, IFlashMessagesActions>) as IKeaLogic<
|
||||
IFlashMessagesValues,
|
||||
IFlashMessagesActions
|
||||
>;
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import '../../__mocks__/shallow_usecontext.mock';
|
||||
import '../../__mocks__/kea.mock';
|
||||
|
||||
import React from 'react';
|
||||
import { shallow } from 'enzyme';
|
||||
import { useValues, useActions } from 'kea';
|
||||
|
||||
import { mockHistory } from '../../__mocks__';
|
||||
|
||||
import { FlashMessagesProvider } from './';
|
||||
|
||||
describe('FlashMessagesProvider', () => {
|
||||
const props = { history: mockHistory as any };
|
||||
const listenToHistory = jest.fn();
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
(useActions as jest.Mock).mockImplementationOnce(() => ({ listenToHistory }));
|
||||
});
|
||||
|
||||
it('does not render', () => {
|
||||
const wrapper = shallow(<FlashMessagesProvider {...props} />);
|
||||
|
||||
expect(wrapper.isEmptyRender()).toBe(true);
|
||||
});
|
||||
|
||||
it('listens to history on mount', () => {
|
||||
shallow(<FlashMessagesProvider {...props} />);
|
||||
|
||||
expect(listenToHistory).toHaveBeenCalledWith(mockHistory);
|
||||
});
|
||||
|
||||
it('does not add another history listener if one already exists', () => {
|
||||
(useValues as jest.Mock).mockImplementationOnce(() => ({ historyListener: 'exists' as any }));
|
||||
|
||||
shallow(<FlashMessagesProvider {...props} />);
|
||||
|
||||
expect(listenToHistory).not.toHaveBeenCalledWith(props);
|
||||
});
|
||||
});
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* 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 } from 'react';
|
||||
import { useValues, useActions } from 'kea';
|
||||
import { History } from 'history';
|
||||
|
||||
import {
|
||||
FlashMessagesLogic,
|
||||
IFlashMessagesValues,
|
||||
IFlashMessagesActions,
|
||||
} from './flash_messages_logic';
|
||||
|
||||
interface IFlashMessagesProviderProps {
|
||||
history: History;
|
||||
}
|
||||
|
||||
export const FlashMessagesProvider: React.FC<IFlashMessagesProviderProps> = ({ history }) => {
|
||||
const { historyListener } = useValues(FlashMessagesLogic) as IFlashMessagesValues;
|
||||
const { listenToHistory } = useActions(FlashMessagesLogic) as IFlashMessagesActions;
|
||||
|
||||
useEffect(() => {
|
||||
if (!historyListener) listenToHistory(history);
|
||||
}, []);
|
||||
|
||||
return null;
|
||||
};
|
|
@ -0,0 +1,14 @@
|
|||
/*
|
||||
* 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 { FlashMessages } from './flash_messages';
|
||||
export {
|
||||
FlashMessagesLogic,
|
||||
IFlashMessage,
|
||||
IFlashMessagesValues,
|
||||
IFlashMessagesActions,
|
||||
} from './flash_messages_logic';
|
||||
export { FlashMessagesProvider } from './flash_messages_provider';
|
|
@ -4,14 +4,7 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
export interface IFlashMessagesProps {
|
||||
info?: string[];
|
||||
warning?: string[];
|
||||
error?: string[];
|
||||
success?: string[];
|
||||
isWrapped?: boolean;
|
||||
children?: React.ReactNode;
|
||||
}
|
||||
export { IFlashMessage } from './flash_messages';
|
||||
|
||||
export interface IKeaLogic<IKeaValues, IKeaActions> {
|
||||
mount(): Function;
|
||||
|
|
|
@ -22,7 +22,6 @@ export const mockLogicValues = {
|
|||
personalSourcesCount: 0,
|
||||
sourcesCount: 0,
|
||||
dataLoading: true,
|
||||
flashMessages: {},
|
||||
} as IOverviewValues;
|
||||
|
||||
export const mockLogicActions = {
|
||||
|
|
|
@ -76,15 +76,6 @@ describe('OverviewLogic', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('setFlashMessages', () => {
|
||||
it('will set `flashMessages`', () => {
|
||||
const flashMessages = { error: ['error'] };
|
||||
OverviewLogic.actions.setFlashMessages(flashMessages);
|
||||
|
||||
expect(OverviewLogic.values.flashMessages).toEqual(flashMessages);
|
||||
});
|
||||
});
|
||||
|
||||
describe('initializeOverview', () => {
|
||||
it('calls API and sets values', async () => {
|
||||
const setServerDataSpy = jest.spyOn(OverviewLogic.actions, 'setServerData');
|
||||
|
|
|
@ -8,7 +8,7 @@ import { kea } from 'kea';
|
|||
import { HttpLogic } from '../../../shared/http';
|
||||
|
||||
import { IAccount, IOrganization } from '../../types';
|
||||
import { IFlashMessagesProps, IKeaLogic, TKeaReducers, IKeaParams } from '../../../shared/types';
|
||||
import { IKeaLogic, TKeaReducers, IKeaParams } from '../../../shared/types';
|
||||
|
||||
import { IFeedActivity } from './recent_activity';
|
||||
|
||||
|
@ -30,19 +30,16 @@ export interface IOverviewServerData {
|
|||
|
||||
export interface IOverviewActions {
|
||||
setServerData(serverData: IOverviewServerData): void;
|
||||
setFlashMessages(flashMessages: IFlashMessagesProps): void;
|
||||
initializeOverview(): void;
|
||||
}
|
||||
|
||||
export interface IOverviewValues extends IOverviewServerData {
|
||||
dataLoading: boolean;
|
||||
flashMessages: IFlashMessagesProps;
|
||||
}
|
||||
|
||||
export const OverviewLogic = kea({
|
||||
actions: (): IOverviewActions => ({
|
||||
setServerData: (serverData) => serverData,
|
||||
setFlashMessages: (flashMessages) => ({ flashMessages }),
|
||||
initializeOverview: () => null,
|
||||
}),
|
||||
reducers: (): TKeaReducers<IOverviewValues, IOverviewActions> => ({
|
||||
|
@ -70,12 +67,6 @@ export const OverviewLogic = kea({
|
|||
setServerData: (_, { canCreateInvitations }) => canCreateInvitations,
|
||||
},
|
||||
],
|
||||
flashMessages: [
|
||||
{},
|
||||
{
|
||||
setFlashMessages: (_, { flashMessages }) => flashMessages,
|
||||
},
|
||||
],
|
||||
hasUsers: [
|
||||
false,
|
||||
{
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue