Skip to content

Commit

Permalink
middleware stuff
Browse files Browse the repository at this point in the history
  • Loading branch information
parkiino committed Feb 12, 2020
1 parent 2e3edde commit c2a6d5c
Show file tree
Hide file tree
Showing 6 changed files with 90 additions and 33 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,12 @@ import { EndpointList } from './view/managing';
export function renderApp(coreStart: CoreStart, { appBasePath, element }: AppMountParameters) {
coreStart.http.get('/api/endpoint/hello-world');

const [store, stopSagas] = appStoreFactory(coreStart);
const store = appStoreFactory(coreStart);

ReactDOM.render(<AppRoot basename={appBasePath} store={store} />, element);

return () => {
ReactDOM.unmountComponentAtNode(element);
stopSagas();
};
}

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

export { endpointListReducer } from './reducer';
export { EndpointListAction } from './action';
export { endpointListSaga } from './saga';
export { managementMiddlewareFactory } from './middleware';
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
* 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 { MiddlewareFactory } from '../../types';
import { pageIndex, pageSize } from './selectors';
import { ManagementState } from '../../types';
import { AppAction } from '../action';

export const managementMiddlewareFactory: MiddlewareFactory<ManagementState> = coreStart => {
return ({ getState, dispatch }) => next => async (action: AppAction) => {
next(action);
if (
(action.type === 'userNavigatedToPage' && action.payload === 'managementPage') ||
action.type === 'userPaginatedEndpointListTable'
) {
const managementPageIndex = pageIndex(getState());
const managementPageSize = pageSize(getState());
const response = await coreStart.http.post('/api/endpoint/endpoints', {
body: JSON.stringify({
paging_properties: [
{ page_index: managementPageIndex },
{ page_size: managementPageSize },
],
}),
});
response.request_page_index = managementPageIndex;
dispatch({
type: 'serverReturnedEndpointList',
payload: response,
});
dispatch({ type: 'serverReturnedAlertsData', payload: response });
}
};
};
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,9 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { CoreStart, HttpSetup } from 'kibana/public';
import { applyMiddleware, combineReducers, createStore, Dispatch, Store } from 'redux';
import { createSagaMiddleware, SagaContext } from '../../lib';
import { endpointListSaga } from './saga';
import { applyMiddleware, createStore, Dispatch, Store } from 'redux';
import { coreMock } from '../../../../../../../../src/core/public/mocks';
import { endpointListReducer } from './index';
import { endpointListReducer, managementMiddlewareFactory } from './index';
import { EndpointMetadata, EndpointResultList } from '../../../../../common/types';
import { ManagementState } from '../../types';
import { AppAction } from '../action';
Expand All @@ -17,12 +15,10 @@ describe('endpoint list saga', () => {
const sleep = (ms = 100) => new Promise(wakeup => setTimeout(wakeup, ms));
let fakeCoreStart: jest.Mocked<CoreStart>;
let fakeHttpServices: jest.Mocked<HttpSetup>;
let store: Store<{ endpointList: ManagementState }>;
let store: Store<ManagementState>;
let getState: typeof store['getState'];
let dispatch: Dispatch<AppAction>;
let stopSagas: () => void;
const globalStoreReducer = combineReducers({
endpointList: endpointListReducer,
});
// https://github.com/elastic/endpoint-app-team/issues/131
const generateEndpoint = (): EndpointMetadata => {
return {
Expand Down Expand Up @@ -59,22 +55,14 @@ describe('endpoint list saga', () => {
total: 10,
};
};
const endpointListSagaFactory = () => {
return async (sagaContext: SagaContext) => {
await endpointListSaga(sagaContext, fakeCoreStart).catch((e: Error) => {
// eslint-disable-next-line no-console
console.error(e);
return Promise.reject(e);
});
};
};
beforeEach(() => {
fakeCoreStart = coreMock.createStart({ basePath: '/mock' });
fakeHttpServices = fakeCoreStart.http as jest.Mocked<HttpSetup>;
const sagaMiddleware = createSagaMiddleware(endpointListSagaFactory());
store = createStore(globalStoreReducer, applyMiddleware(sagaMiddleware));
sagaMiddleware.start();
stopSagas = sagaMiddleware.stop;
store = createStore(
endpointListReducer,
applyMiddleware(managementMiddlewareFactory(fakeCoreStart))
);
getState = store.getState;
dispatch = store.dispatch;
});
afterEach(() => {
Expand All @@ -91,6 +79,6 @@ describe('endpoint list saga', () => {
paging_properties: [{ page_index: 0 }, { page_size: 10 }],
}),
});
expect(listData(store.getState().endpointList)).toEqual(apiResponse.endpoints);
expect(listData(store.getState())).toEqual(apiResponse.endpoints);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
*/

import { CoreStart } from 'kibana/public';
import { SagaContext } from '../../lib';
import { AppAction } from '../action';
import { pageIndex, pageSize } from './selectors';

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,59 @@
* you may not use this file except in compliance with the Elastic License.
*/

import { createStore, compose, applyMiddleware, Store } from 'redux';
import {
createStore,
compose,
applyMiddleware,
Store,
MiddlewareAPI,
Dispatch,
Middleware,
} from 'redux';
import { CoreStart } from 'kibana/public';
import { appSagaFactory } from './saga';
import { appReducer } from './reducer';
import { alertMiddlewareFactory } from './alerts/middleware';
import { managementMiddlewareFactory } from './endpoint_list';
import { GlobalState } from '../types';
import { AppAction } from './action';

const composeWithReduxDevTools = (window as any).__REDUX_DEVTOOLS_EXTENSION_COMPOSE__
? (window as any).__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({ name: 'EndpointApp' })
: compose;

export const appStoreFactory = (coreStart: CoreStart): [Store, () => void] => {
const sagaReduxMiddleware = appSagaFactory(coreStart);
export type Selector<S, R> = (state: S) => R;

/**
* Wrap Redux Middleware and adjust 'getState()' to return the namespace from 'GlobalState that applies to the given Middleware concern.
*
* @param selector
* @param middleware
*/
export const substateMiddlewareFactory = <Substate>(
selector: Selector<GlobalState, Substate>,
middleware: Middleware<{}, Substate, Dispatch<AppAction>>
): Middleware<{}, GlobalState, Dispatch<AppAction>> => {
return api => {
const substateAPI: MiddlewareAPI<Dispatch<AppAction>, Substate> = {
...api,
getState() {
return selector(api.getState());
},
};
return middleware(substateAPI);
};
};

export const appStoreFactory = (coreStart: CoreStart): Store => {
const store = createStore(
appReducer,
composeWithReduxDevTools(
applyMiddleware(alertMiddlewareFactory(coreStart), sagaReduxMiddleware)
applyMiddleware(
alertMiddlewareFactory(coreStart),
substateMiddlewareFactory(s => s.endpointList, managementMiddlewareFactory(coreStart))
)
)
);

sagaReduxMiddleware.start();
return [store, sagaReduxMiddleware.stop];
return store;
};

0 comments on commit c2a6d5c

Please sign in to comment.