[Endpoint][SIEM] Adjust types related to subplugin's redux (#67768) (#68249)

This commit is contained in:
Robert Austin 2020-06-04 11:55:35 -04:00 committed by GitHub
parent e46beca751
commit 2ca71b1ced
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
59 changed files with 440 additions and 410 deletions

View file

@ -15,28 +15,9 @@ import {
AlertEvent, AlertEvent,
KbnConfigSchemaInputTypeOf, KbnConfigSchemaInputTypeOf,
AppLocation, AppLocation,
Immutable,
} from '../endpoint/types'; } from '../endpoint/types';
/**
* A deep readonly type that will make all children of a given object readonly recursively
*/
export type Immutable<T> = T extends undefined | null | boolean | string | number
? T
: unknown extends T
? unknown
: T extends Array<infer U>
? ImmutableArray<U>
: T extends Map<infer K, infer V>
? ImmutableMap<K, V>
: T extends Set<infer M>
? ImmutableSet<M>
: ImmutableObject<T>;
type ImmutableArray<T> = ReadonlyArray<Immutable<T>>;
type ImmutableMap<K, V> = ReadonlyMap<Immutable<K>, Immutable<V>>;
type ImmutableSet<T> = ReadonlySet<Immutable<T>>;
type ImmutableObject<T> = { readonly [K in keyof T]: Immutable<T[K]> };
/** /**
* Values for the Alert APIs 'order' and 'direction' parameters. * Values for the Alert APIs 'order' and 'direction' parameters.
*/ */

View file

@ -4,17 +4,20 @@
* you may not use this file except in compliance with the Elastic License. * you may not use this file except in compliance with the Elastic License.
*/ */
import { Reducer, AnyAction, Middleware, Dispatch } from 'redux'; import {
Reducer,
AnyAction,
Middleware,
Dispatch,
PreloadedState,
StateFromReducersMapObject,
CombinedState,
} from 'redux';
import { NavTab } from '../common/components/navigation/types'; import { NavTab } from '../common/components/navigation/types';
import { HostsState } from '../hosts/store'; import { State, SubPluginsInitReducer } from '../common/store';
import { NetworkState } from '../network/store';
import { TimelineState } from '../timelines/store/timeline/types';
import { ImmutableReducer, State } from '../common/store';
import { Immutable } from '../../common/endpoint/types'; import { Immutable } from '../../common/endpoint/types';
import { AlertListState } from '../../common/endpoint_alerts/types';
import { AppAction } from '../common/store/actions'; import { AppAction } from '../common/store/actions';
import { HostState } from '../endpoint_hosts/types';
import { ManagementState } from '../management/store/types';
export enum SiemPageName { export enum SiemPageName {
overview = 'overview', overview = 'overview',
@ -38,7 +41,7 @@ export type SiemNavTabKey =
export type SiemNavTab = Record<SiemNavTabKey, NavTab>; export type SiemNavTab = Record<SiemNavTabKey, NavTab>;
export interface SecuritySubPluginStore<K extends SecuritySubPluginKeyStore, T> { export interface SecuritySubPluginStore<K extends SecuritySubPluginKeyStore, T> {
initialState: Record<K, T>; initialState: Record<K, T | undefined>;
reducer: Record<K, Reducer<T, AnyAction>>; reducer: Record<K, Reducer<T, AnyAction>>;
middleware?: Array<Middleware<{}, State, Dispatch<AppAction | Immutable<AppAction>>>>; middleware?: Array<Middleware<{}, State, Dispatch<AppAction | Immutable<AppAction>>>>;
} }
@ -54,6 +57,10 @@ type SecuritySubPluginKeyStore =
| 'hostList' | 'hostList'
| 'alertList' | 'alertList'
| 'management'; | 'management';
/**
* Returned by the various 'SecuritySubPlugin' classes from the `start` method.
*/
export interface SecuritySubPluginWithStore<K extends SecuritySubPluginKeyStore, T> export interface SecuritySubPluginWithStore<K extends SecuritySubPluginKeyStore, T>
extends SecuritySubPlugin { extends SecuritySubPlugin {
store: SecuritySubPluginStore<K, T>; store: SecuritySubPluginStore<K, T>;
@ -61,22 +68,17 @@ export interface SecuritySubPluginWithStore<K extends SecuritySubPluginKeyStore,
export interface SecuritySubPlugins extends SecuritySubPlugin { export interface SecuritySubPlugins extends SecuritySubPlugin {
store: { store: {
initialState: { initialState: PreloadedState<
hosts: HostsState; CombinedState<
network: NetworkState; StateFromReducersMapObject<
timeline: TimelineState; /** SubPluginsInitReducer, being an interface, will not work in `StateFromReducersMapObject`.
alertList: Immutable<AlertListState>; * Picking its keys does the trick.
hostList: Immutable<HostState>; **/
management: ManagementState; Pick<SubPluginsInitReducer, keyof SubPluginsInitReducer>
}; >
reducer: { >
hosts: Reducer<HostsState, AnyAction>; >;
network: Reducer<NetworkState, AnyAction>; reducer: SubPluginsInitReducer;
timeline: Reducer<TimelineState, AnyAction>;
alertList: ImmutableReducer<AlertListState, AppAction>;
hostList: ImmutableReducer<HostState, AppAction>;
management: ImmutableReducer<ManagementState, AppAction>;
};
middlewares: Array<Middleware<{}, State, Dispatch<AppAction | Immutable<AppAction>>>>; middlewares: Array<Middleware<{}, State, Dispatch<AppAction | Immutable<AppAction>>>>;
}; };
} }

View file

@ -15,7 +15,7 @@ import { BrowserFields } from '../../containers/source';
import { dragAndDropModel, dragAndDropSelectors } from '../../store'; import { dragAndDropModel, dragAndDropSelectors } from '../../store';
import { timelineSelectors } from '../../../timelines/store/timeline'; import { timelineSelectors } from '../../../timelines/store/timeline';
import { IdToDataProvider } from '../../store/drag_and_drop/model'; import { IdToDataProvider } from '../../store/drag_and_drop/model';
import { State } from '../../store/reducer'; import { State } from '../../store/types';
import { DataProvider } from '../../../timelines/components/timeline/data_providers/data_provider'; import { DataProvider } from '../../../timelines/components/timeline/data_providers/data_provider';
import { reArrangeProviders } from '../../../timelines/components/timeline/data_providers/helpers'; import { reArrangeProviders } from '../../../timelines/components/timeline/data_providers/helpers';
import { ACTIVE_TIMELINE_REDUX_ID } from '../top_n'; import { ACTIVE_TIMELINE_REDUX_ID } from '../top_n';

View file

@ -12,7 +12,7 @@ import { apolloClientObservable, mockGlobalState, SUB_PLUGINS_REDUCER } from '..
import { createStore } from '../../store/store'; import { createStore } from '../../store/store';
import { ErrorToastDispatcher } from '.'; import { ErrorToastDispatcher } from '.';
import { State } from '../../store/reducer'; import { State } from '../../store/types';
describe('Error Toast Dispatcher', () => { describe('Error Toast Dispatcher', () => {
const state: State = mockGlobalState; const state: State = mockGlobalState;

View file

@ -15,10 +15,10 @@ import { depsStartMock } from './dependencies_start_mock';
import { MiddlewareActionSpyHelper, createSpyMiddleware } from '../../store/test_utils'; import { MiddlewareActionSpyHelper, createSpyMiddleware } from '../../store/test_utils';
import { apolloClientObservable } from '../test_providers'; import { apolloClientObservable } from '../test_providers';
import { createStore, State, substateMiddlewareFactory } from '../../store'; import { createStore, State, substateMiddlewareFactory } from '../../store';
import { hostMiddlewareFactory } from '../../../endpoint_hosts/store';
import { alertMiddlewareFactory } from '../../../endpoint_alerts/store/middleware'; import { alertMiddlewareFactory } from '../../../endpoint_alerts/store/middleware';
import { AppRootProvider } from './app_root_provider'; import { AppRootProvider } from './app_root_provider';
import { managementMiddlewareFactory } from '../../../management/store'; import { managementMiddlewareFactory } from '../../../management/store/middleware';
import { hostMiddlewareFactory } from '../../../endpoint_hosts/store/middleware';
import { SUB_PLUGINS_REDUCER, mockGlobalState } from '..'; import { SUB_PLUGINS_REDUCER, mockGlobalState } from '..';
type UiRender = (ui: React.ReactElement, options?: RenderOptions) => RenderResult; type UiRender = (ui: React.ReactElement, options?: RenderOptions) => RenderResult;
@ -56,8 +56,7 @@ export const createAppRootMockRenderer = (): AppContextTestRender => {
const coreStart = coreMock.createStart({ basePath: '/mock' }); const coreStart = coreMock.createStart({ basePath: '/mock' });
const depsStart = depsStartMock(); const depsStart = depsStartMock();
const middlewareSpy = createSpyMiddleware(); const middlewareSpy = createSpyMiddleware();
const state: State = mockGlobalState; const store = createStore(mockGlobalState, SUB_PLUGINS_REDUCER, apolloClientObservable, [
const store = createStore(state, SUB_PLUGINS_REDUCER, apolloClientObservable, [
substateMiddlewareFactory( substateMiddlewareFactory(
(globalState) => globalState.hostList, (globalState) => globalState.hostList,
hostMiddlewareFactory(coreStart, depsStart) hostMiddlewareFactory(coreStart, depsStart)
@ -76,7 +75,6 @@ export const createAppRootMockRenderer = (): AppContextTestRender => {
</AppRootProvider> </AppRootProvider>
); );
const render: UiRender = (ui, options) => { const render: UiRender = (ui, options) => {
// @ts-ignore
return reactRender(ui, { return reactRender(ui, {
wrapper: AppWrapper as React.ComponentType, wrapper: AppWrapper as React.ComponentType,
...options, ...options,

View file

@ -27,11 +27,10 @@ import { networkModel } from '../../network/store';
import { TimelineType, TimelineStatus } from '../../../common/types/timeline'; import { TimelineType, TimelineStatus } from '../../../common/types/timeline';
import { initialAlertListState } from '../../endpoint_alerts/store/reducer'; import { initialAlertListState } from '../../endpoint_alerts/store/reducer';
import { initialHostListState } from '../../endpoint_hosts/store/reducer'; import { initialHostListState } from '../../endpoint_hosts/store/reducer';
import { getManagementInitialState } from '../../management/store'; import { mockManagementState } from '../../management/store/reducer';
import { AlertListState } from '../../../common/endpoint_alerts/types';
const alertList = initialAlertListState(); import { HostState } from '../../endpoint_hosts/types';
const hostList = initialHostListState(); import { ManagementState } from '../../management/types';
const management = getManagementInitialState();
export const mockGlobalState: State = { export const mockGlobalState: State = {
app: { app: {
@ -233,7 +232,11 @@ export const mockGlobalState: State = {
}, },
}, },
}, },
alertList, /**
hostList, * These state's are wrapped in `Immutable`, but for compatibility with the overall app architecture,
management, * they are cast to mutable versions here.
*/
alertList: initialAlertListState as AlertListState,
hostList: initialHostListState as HostState,
management: mockManagementState as ManagementState,
}; };

View file

@ -7,9 +7,13 @@
import { hostsReducer } from '../../hosts/store'; import { hostsReducer } from '../../hosts/store';
import { networkReducer } from '../../network/store'; import { networkReducer } from '../../network/store';
import { timelineReducer } from '../../timelines/store/timeline/reducer'; import { timelineReducer } from '../../timelines/store/timeline/reducer';
import { hostListReducer } from '../../endpoint_hosts/store'; import { managementReducer } from '../../management/store/reducer';
import { alertListReducer } from '../../endpoint_alerts/store'; import { ManagementPluginReducer } from '../../management';
import { managementReducer } from '../../management/store'; import { SubPluginsInitReducer } from '../store';
import { EndpointAlertsPluginReducer } from '../../endpoint_alerts';
import { EndpointHostsPluginReducer } from '../../endpoint_hosts';
import { alertListReducer } from '../../endpoint_alerts/store/reducer';
import { hostListReducer } from '../../endpoint_hosts/store/reducer';
interface Global extends NodeJS.Global { interface Global extends NodeJS.Global {
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
@ -18,11 +22,15 @@ interface Global extends NodeJS.Global {
export const globalNode: Global = global; export const globalNode: Global = global;
export const SUB_PLUGINS_REDUCER = { export const SUB_PLUGINS_REDUCER: SubPluginsInitReducer = {
hosts: hostsReducer, hosts: hostsReducer,
network: networkReducer, network: networkReducer,
timeline: timelineReducer, timeline: timelineReducer,
hostList: hostListReducer, /**
alertList: alertListReducer, * These state's are wrapped in `Immutable`, but for compatibility with the overall app architecture,
management: managementReducer, * they are cast to mutable versions here.
*/
hostList: hostListReducer as EndpointHostsPluginReducer['hostList'],
alertList: alertListReducer as EndpointAlertsPluginReducer['alertList'],
management: managementReducer as ManagementPluginReducer['management'],
}; };

View file

@ -7,11 +7,9 @@
import { keys } from 'lodash/fp'; import { keys } from 'lodash/fp';
import memoizeOne from 'memoize-one'; import memoizeOne from 'memoize-one';
import { createSelector } from 'reselect'; import { createSelector } from 'reselect';
import { Note } from '../../lib/note'; import { Note } from '../../lib/note';
import { State } from '../reducer';
import { ErrorModel, NotesById } from './model'; import { ErrorModel, NotesById } from './model';
import { State } from '../types';
const selectNotesById = (state: State): NotesById => state.app.notesById; const selectNotesById = (state: State): NotesById => state.app.notesById;

View file

@ -5,10 +5,8 @@
*/ */
import { createSelector } from 'reselect'; import { createSelector } from 'reselect';
import { State } from '../reducer';
import { IdToDataProvider } from './model'; import { IdToDataProvider } from './model';
import { State } from '../types';
const selectDataProviders = (state: State): IdToDataProvider => state.dragAndDrop.dataProviders; const selectDataProviders = (state: State): IdToDataProvider => state.dragAndDrop.dataProviders;

View file

@ -8,18 +8,46 @@ export * from './model';
export * from './reducer'; export * from './reducer';
export * from './selectors'; export * from './selectors';
import { Middleware, Dispatch } from 'redux';
import { createStore, getStore } from './store'; import { createStore, getStore } from './store';
import { SubstateMiddlewareFactory } from './types'; import { ImmutableMiddleware, State } from './types';
import { AppAction } from './actions';
import { Immutable } from '../../../common/endpoint/types';
export { createStore, getStore }; export { createStore, getStore };
export const substateMiddlewareFactory: SubstateMiddlewareFactory = (selector, middleware) => { /**
* Takes a selector and an `ImmutableMiddleware`. The
* middleware's version of `getState` will receive
* the result of the selector instead of the global state.
*
* This allows middleware to have knowledge of only a subsection of state.
*
* `selector` returns an `Immutable` version of the substate.
* `middleware` must be an `ImmutableMiddleware`.
*
* Returns a regular middleware, meant to be used with `applyMiddleware`.
*/
export const substateMiddlewareFactory = <Substate = never>(
selector: (state: State) => Substate | Immutable<Substate>,
middleware: ImmutableMiddleware<Substate, AppAction>
): Middleware<{}, State, Dispatch<AppAction | Immutable<AppAction>>> => {
return (api) => { return (api) => {
const substateAPI = { const substateAPI = {
...api, ...api,
// Return just the substate instead of global state. // Return the substate instead of global state.
getState() { getState(): Immutable<Substate> {
return selector(api.getState()); /**
* The selector will receive the basic (mutable) version of state. This is because
* the top level state shape doesn't use `Immutable`. We cast the return value as `Immutable`
* so that the middleware won't be able to mutate state.
*
* Immutable enforces nothing structural about a type so casting
* a value as `Immutable` is safe as long as nothing else is going to mutate.
* Since the state came from the return value of a reducer, the reducer will (hopefully)
* not be mutating it.
*/
return selector(api.getState()) as Immutable<Substate>;
}, },
}; };
return middleware(substateAPI); return middleware(substateAPI);

View file

@ -6,7 +6,7 @@
import { createSelector } from 'reselect'; import { createSelector } from 'reselect';
import { State } from '../reducer'; import { State } from '../types';
import { InputsModel, InputsRange, GlobalQuery } from './model'; import { InputsModel, InputsRange, GlobalQuery } from './model';

View file

@ -4,47 +4,22 @@
* you may not use this file except in compliance with the Elastic License. * you may not use this file except in compliance with the Elastic License.
*/ */
import { combineReducers } from 'redux'; import { combineReducers, PreloadedState, AnyAction, Reducer } from 'redux';
import { appReducer, AppState, initialAppState } from './app'; import { appReducer, initialAppState } from './app';
import { dragAndDropReducer, DragAndDropState, initialDragAndDropState } from './drag_and_drop'; import { dragAndDropReducer, initialDragAndDropState } from './drag_and_drop';
import { createInitialInputsState, initialInputsState, inputsReducer, InputsState } from './inputs'; import { createInitialInputsState, inputsReducer } from './inputs';
import { HostsPluginState, HostsPluginReducer } from '../../hosts/store'; import { HostsPluginReducer } from '../../hosts/store';
import { NetworkPluginState, NetworkPluginReducer } from '../../network/store'; import { NetworkPluginReducer } from '../../network/store';
import { TimelinePluginState, TimelinePluginReducer } from '../../timelines/store/timeline'; import { TimelinePluginReducer } from '../../timelines/store/timeline';
import {
EndpointAlertsPluginState,
EndpointAlertsPluginReducer,
} from '../../endpoint_alerts/store';
import { EndpointHostsPluginState, EndpointHostsPluginReducer } from '../../endpoint_hosts/store';
import { ManagementPluginReducer, ManagementPluginState } from '../../management/store/types'; import { SecuritySubPlugins } from '../../app/types';
import { ManagementPluginReducer } from '../../management';
export interface State import { EndpointAlertsPluginReducer } from '../../endpoint_alerts';
extends HostsPluginState, import { EndpointHostsPluginReducer } from '../../endpoint_hosts';
NetworkPluginState, import { State } from './types';
TimelinePluginState, import { AppAction } from './actions';
EndpointAlertsPluginState,
EndpointHostsPluginState,
ManagementPluginState {
app: AppState;
dragAndDrop: DragAndDropState;
inputs: InputsState;
}
export const initialState: Pick<State, 'app' | 'dragAndDrop' | 'inputs'> = {
app: initialAppState,
dragAndDrop: initialDragAndDropState,
inputs: initialInputsState,
};
type SubPluginsInitState = HostsPluginState &
NetworkPluginState &
TimelinePluginState &
EndpointAlertsPluginState &
EndpointHostsPluginState &
ManagementPluginState;
export type SubPluginsInitReducer = HostsPluginReducer & export type SubPluginsInitReducer = HostsPluginReducer &
NetworkPluginReducer & NetworkPluginReducer &
@ -53,14 +28,28 @@ export type SubPluginsInitReducer = HostsPluginReducer &
EndpointHostsPluginReducer & EndpointHostsPluginReducer &
ManagementPluginReducer; ManagementPluginReducer;
export const createInitialState = (pluginsInitState: SubPluginsInitState): State => ({ /**
...initialState, * Factory for the 'initialState' that is used to preload state into the Security App's redux store.
*/
export const createInitialState = (
pluginsInitState: SecuritySubPlugins['store']['initialState']
): PreloadedState<State> => {
const preloadedState: PreloadedState<State> = {
app: initialAppState,
dragAndDrop: initialDragAndDropState,
...pluginsInitState, ...pluginsInitState,
inputs: createInitialInputsState(), inputs: createInitialInputsState(),
}); };
return preloadedState;
};
export const createReducer = (pluginsReducer: SubPluginsInitReducer) => /**
combineReducers<State>({ * Factory for the Security app's redux reducer.
*/
export const createReducer: (
pluginsReducer: SubPluginsInitReducer
) => Reducer<State, AppAction | AnyAction> = (pluginsReducer: SubPluginsInitReducer) =>
combineReducers({
app: appReducer, app: appReducer,
dragAndDrop: dragAndDropReducer, dragAndDrop: dragAndDropReducer,
inputs: inputsReducer, inputs: inputsReducer,

View file

@ -12,6 +12,7 @@ import {
Store, Store,
Middleware, Middleware,
Dispatch, Dispatch,
PreloadedState,
} from 'redux'; } from 'redux';
import { createEpicMiddleware } from 'redux-observable'; import { createEpicMiddleware } from 'redux-observable';
@ -21,11 +22,12 @@ import { telemetryMiddleware } from '../lib/telemetry';
import { appSelectors } from './app'; import { appSelectors } from './app';
import { timelineSelectors } from '../../timelines/store/timeline'; import { timelineSelectors } from '../../timelines/store/timeline';
import { inputsSelectors } from './inputs'; import { inputsSelectors } from './inputs';
import { State, SubPluginsInitReducer, createReducer } from './reducer'; import { SubPluginsInitReducer, createReducer } from './reducer';
import { createRootEpic } from './epic'; import { createRootEpic } from './epic';
import { AppApolloClient } from '../lib/lib'; import { AppApolloClient } from '../lib/lib';
import { AppAction } from './actions'; import { AppAction } from './actions';
import { Immutable } from '../../../common/endpoint/types'; import { Immutable } from '../../../common/endpoint/types';
import { State } from './types';
type ComposeType = typeof compose; type ComposeType = typeof compose;
declare global { declare global {
@ -33,10 +35,17 @@ declare global {
__REDUX_DEVTOOLS_EXTENSION_COMPOSE__: ComposeType; __REDUX_DEVTOOLS_EXTENSION_COMPOSE__: ComposeType;
} }
} }
/**
* The Redux store type for the Security app.
*/
export type SecurityAppStore = Store<State, Action>;
let store: Store<State, Action> | null = null; let store: Store<State, Action> | null = null;
export { SubPluginsInitReducer };
/**
* Factory for Security App's redux store.
*/
export const createStore = ( export const createStore = (
state: State, state: PreloadedState<State>,
pluginsReducer: SubPluginsInitReducer, pluginsReducer: SubPluginsInitReducer,
apolloClient: Observable<AppApolloClient>, apolloClient: Observable<AppApolloClient>,
additionalMiddleware?: Array<Middleware<{}, State, Dispatch<AppAction | Immutable<AppAction>>>> additionalMiddleware?: Array<Middleware<{}, State, Dispatch<AppAction | Immutable<AppAction>>>>

View file

@ -5,9 +5,8 @@
*/ */
import { Dispatch } from 'redux'; import { Dispatch } from 'redux';
import { State } from './reducer'; import { State, ImmutableMiddlewareFactory } from './types';
import { AppAction } from './actions'; import { AppAction } from './actions';
import { ImmutableMiddlewareFactory } from './types';
/** /**
* Utilities for testing Redux middleware * Utilities for testing Redux middleware

View file

@ -4,19 +4,40 @@
* you may not use this file except in compliance with the Elastic License. * you may not use this file except in compliance with the Elastic License.
*/ */
import { import { Dispatch, Action, Middleware, CombinedState } from 'redux';
Dispatch,
Action as ReduxAction,
AnyAction as ReduxAnyAction,
Action,
Middleware,
} from 'redux';
import { CoreStart } from '../../../../../../src/core/public'; import { CoreStart } from '../../../../../../src/core/public';
import { Immutable } from '../../../common/endpoint_alerts/types';
import { State } from './reducer';
import { StartPlugins } from '../../types'; import { StartPlugins } from '../../types';
import { AppAction } from './actions'; import { AppAction } from './actions';
import { Immutable } from '../../../common/endpoint/types';
import { AppState } from './app/reducer';
import { InputsState } from './inputs/reducer';
import { HostsPluginState } from '../../hosts/store';
import { DragAndDropState } from './drag_and_drop/reducer';
import { TimelinePluginState } from '../../timelines/store/timeline';
import { NetworkPluginState } from '../../network/store';
import { EndpointAlertsPluginState } from '../../endpoint_alerts';
import { EndpointHostsPluginState } from '../../endpoint_hosts';
import { ManagementPluginState } from '../../management';
/**
* The redux `State` type for the Security App.
* We use `CombinedState` to wrap our shape because we create our reducer using `combineReducers`.
* `combineReducers` returns a type wrapped in `CombinedState`.
* `CombinedState` is required for redux to know what keys to make optional when preloaded state into a store.
*/
export type State = CombinedState<
HostsPluginState &
NetworkPluginState &
TimelinePluginState &
EndpointAlertsPluginState &
EndpointHostsPluginState &
ManagementPluginState & {
app: AppState;
dragAndDrop: DragAndDropState;
inputs: InputsState;
}
>;
export type KueryFilterQueryKind = 'kuery' | 'lucene'; export type KueryFilterQueryKind = 'kuery' | 'lucene';
@ -67,60 +88,73 @@ export type ImmutableMiddlewareFactory<S = State> = (
* Middleware will be of the `ImmutableMiddleware` variety. Not able to directly * Middleware will be of the `ImmutableMiddleware` variety. Not able to directly
* change actions or state. * change actions or state.
*/ */
export type ImmutableMultipleMiddlewareFactory<S = State> = ( export type SecuritySubPluginMiddlewareFactory = (
coreStart: CoreStart, coreStart: CoreStart,
depsStart: Pick<StartPlugins, 'data' | 'ingestManager'> depsStart: Pick<StartPlugins, 'data' | 'ingestManager'>
) => Array<ImmutableMiddleware<S, AppAction>>; ) => Array<Middleware<{}, State, Dispatch<AppAction | Immutable<AppAction>>>>;
/**
* Simple type for a redux selector.
*/
type Selector<S, R> = (state: S) => R;
/**
* Takes a selector and an `ImmutableMiddleware`. The
* middleware's version of `getState` will receive
* the result of the selector instead of the global state.
*
* This allows middleware to have knowledge of only a subsection of state.
*
* `selector` returns an `Immutable` version of the substate.
* `middleware` must be an `ImmutableMiddleware`.
*
* Returns a regular middleware, meant to be used with `applyMiddleware`.
*/
export type SubstateMiddlewareFactory = <Substate>(
selector: Selector<State, Immutable<Substate>>,
middleware: ImmutableMiddleware<Substate, AppAction>
) => Middleware<{}, State, Dispatch<AppAction | Immutable<AppAction>>>;
/** /**
* Like `Reducer` from `redux` but it accepts immutable versions of `state` and `action`. * Like `Reducer` from `redux` but it accepts immutable versions of `state` and `action`.
* Use this type for all Reducers in order to help enforce our pattern of immutable state. * Use this type for all Reducers in order to help enforce our pattern of immutable state.
*/ */
export type ImmutableReducer<State, Action> = ( export type ImmutableReducer<S, A> = (
state: Immutable<State> | undefined, state: Immutable<S> | undefined,
action: Immutable<Action> action: Immutable<A>
) => State | Immutable<State>; ) => S | Immutable<S>;
/** /**
* A alternate interface for `redux`'s `combineReducers`. Will work with the same underlying implementation, * A alternate interface for `redux`'s `combineReducers`. Will work with the same underlying implementation,
* but will enforce that `Immutable` versions of `state` and `action` are received. * but will enforce that `Immutable` versions of `state` and `action` are received.
*/ */
export type ImmutableCombineReducers = <S, A extends ReduxAction = ReduxAnyAction>( export type ImmutableCombineReducers = <M extends ImmutableReducersMapObject<unknown, never>>(
reducers: ImmutableReducersMapObject<S, A> reducers: M
) => ImmutableReducer<S, A>; ) => ImmutableReducer<
CombinedState<StateFromImmutableReducersMapObject<M>>,
ActionFromImmutableReducersMapObject<M>
>;
/** /**
* Helper type for `ImmutableCombineReducers`. Infers the combined state type from an immutable reducer map.
*/
type StateFromImmutableReducersMapObject<M> = M extends ImmutableReducersMapObject<unknown, never>
? { [P in keyof M]: M[P] extends ImmutableReducer<infer S, infer _A> ? S : never }
: never;
/**
* Helper type for `ImmutableCombineReducers`. Infers the combined action type from an immutable reducer map.
*/
type ActionFromImmutableReducersMapObject<M> = M extends ImmutableReducersMapObject<unknown, never>
? ActionFromImmutableReducer<ImmutableReducerFromImmutableReducersMapObject<M>>
: never;
/**
* Helper type for `ImmutableCombineReducers`. Infers the combined reducer type from an immutable reducer map.
*/
type ImmutableReducerFromImmutableReducersMapObject<M> = M extends {
[P in keyof M]: infer R;
}
? R extends ImmutableReducer<infer _S, infer _A>
? R
: never
: never;
/**
* Helper type for `ImmutableCombineReducers`. Infers the action type for an immutable reducer.
*/
type ActionFromImmutableReducer<R> = R extends ImmutableReducer<infer _S, infer A> ? A : never;
/**
* Helper type for `ImmutableCombineReducers`.
* Like `redux`'s `ReducersMapObject` (which is used by `combineReducers`) but enforces that * Like `redux`'s `ReducersMapObject` (which is used by `combineReducers`) but enforces that
* the `state` and `action` received are `Immutable` versions. * the `state` and `action` received are `Immutable` versions.
*/ */
type ImmutableReducersMapObject<S, A extends ReduxAction = ReduxAction> = { type ImmutableReducersMapObject<S, A extends Action = Action> = {
[K in keyof S]: ImmutableReducer<S[K], A>; [K in keyof S]: ImmutableReducer<S[K], A>;
}; };
/** /**
* A better type for createStructuredSelector. This doesn't support the options object. * A better type for createStructuredSelector. This doesn't support the options object.
* https://github.com/reduxjs/reselect/pull/454
*/ */
export type CreateStructuredSelector = < export type CreateStructuredSelector = <
SelectorMap extends { [key: string]: (...args: never[]) => unknown } SelectorMap extends { [key: string]: (...args: never[]) => unknown }

View file

@ -4,9 +4,8 @@
* you may not use this file except in compliance with the Elastic License. * you may not use this file except in compliance with the Elastic License.
*/ */
import { Immutable } from '../../../common/endpoint_alerts/types';
import { HttpFetchQuery } from '../../../../../../src/core/public'; import { HttpFetchQuery } from '../../../../../../src/core/public';
import { Immutable } from '../../../common/endpoint/types';
export function cloneHttpFetchQuery(query: Immutable<HttpFetchQuery>): HttpFetchQuery { export function cloneHttpFetchQuery(query: Immutable<HttpFetchQuery>): HttpFetchQuery {
const clone: HttpFetchQuery = {}; const clone: HttpFetchQuery = {};

View file

@ -4,15 +4,32 @@
* you may not use this file except in compliance with the Elastic License. * you may not use this file except in compliance with the Elastic License.
*/ */
import { Reducer } from 'redux';
import { SecuritySubPluginWithStore } from '../app/types'; import { SecuritySubPluginWithStore } from '../app/types';
import { getEndpointAlertsRoutes } from './routes'; import { endpointAlertsRoutes } from './routes';
import { Immutable } from '../../common/endpoint/types'; import { alertListReducer } from './store/reducer';
import { initialAlertListState, alertListReducer } from './store/reducer';
import { AlertListState } from '../../common/endpoint_alerts/types'; import { AlertListState } from '../../common/endpoint_alerts/types';
import { alertMiddlewareFactory } from './store/middleware'; import { alertMiddlewareFactory } from './store/middleware';
import { substateMiddlewareFactory } from '../common/store'; import { substateMiddlewareFactory } from '../common/store';
import { CoreStart } from '../../../../../src/core/public'; import { CoreStart } from '../../../../../src/core/public';
import { StartPlugins } from '../types'; import { StartPlugins } from '../types';
import { AppAction } from '../common/store/actions';
/**
* Internally, our state is sometimes immutable, ignore that in our external
* interface.
*/
export interface EndpointAlertsPluginState {
alertList: AlertListState;
}
/**
* Internally, we use `ImmutableReducer`, but we present a regular reducer
* externally for compatibility w/ regular redux.
*/
export interface EndpointAlertsPluginReducer {
alertList: Reducer<AlertListState, AppAction>;
}
export class EndpointAlerts { export class EndpointAlerts {
public setup() {} public setup() {}
@ -20,20 +37,24 @@ export class EndpointAlerts {
public start( public start(
core: CoreStart, core: CoreStart,
plugins: StartPlugins plugins: StartPlugins
): SecuritySubPluginWithStore<'alertList', Immutable<AlertListState>> { ): SecuritySubPluginWithStore<'alertList', AlertListState> {
const { data, ingestManager } = plugins; const { data, ingestManager } = plugins;
const middleware = [ const middleware = [
substateMiddlewareFactory( substateMiddlewareFactory<AlertListState>(
(globalState) => globalState.alertList, (globalState) => globalState.alertList,
alertMiddlewareFactory(core, { data, ingestManager }) alertMiddlewareFactory(core, { data, ingestManager })
), ),
]; ];
return { return {
routes: getEndpointAlertsRoutes(), routes: endpointAlertsRoutes(),
store: { store: {
initialState: { alertList: initialAlertListState() }, initialState: { alertList: undefined },
reducer: { alertList: alertListReducer }, /**
* Cast the ImmutableReducer to a regular reducer for compatibility with
* the subplugin architecture (which expects plain redux reducers.)
*/
reducer: { alertList: alertListReducer } as EndpointAlertsPluginReducer,
middleware, middleware,
}, },
}; };

View file

@ -6,7 +6,7 @@
import { all } from 'deepmerge'; import { all } from 'deepmerge';
import { IIndexPattern } from 'src/plugins/data/public'; import { IIndexPattern } from 'src/plugins/data/public';
import { Immutable } from '../../../common/endpoint_alerts/types'; import { Immutable } from '../../../common/endpoint/types';
/** /**
* Model for the `IIndexPattern` interface exported by the `data` plugin. * Model for the `IIndexPattern` interface exported by the `data` plugin.

View file

@ -9,7 +9,7 @@ import { Route } from 'react-router-dom';
import { AlertIndex } from './view'; import { AlertIndex } from './view';
export const getEndpointAlertsRoutes = () => [ export const endpointAlertsRoutes = () => [
<Route path="/:pageName(endpoint-alerts)"> <Route path="/:pageName(endpoint-alerts)">
<AlertIndex /> <AlertIndex />
</Route>, </Route>,

View file

@ -5,8 +5,8 @@
*/ */
import { IIndexPattern } from 'src/plugins/data/public'; import { IIndexPattern } from 'src/plugins/data/public';
// import { Immutable } from '../../../common/types'; import { Immutable } from '../../../common/endpoint/types';
import { AlertDetails, AlertListData, Immutable } from '../../../common/endpoint_alerts/types'; import { AlertDetails, AlertListData } from '../../../common/endpoint_alerts/types';
interface ServerReturnedAlertsData { interface ServerReturnedAlertsData {
readonly type: 'serverReturnedAlertsData'; readonly type: 'serverReturnedAlertsData';

View file

@ -8,7 +8,7 @@ import { Store, createStore, applyMiddleware } from 'redux';
import { createBrowserHistory, History } from 'history'; import { createBrowserHistory, History } from 'history';
import { coreMock } from '../../../../../../src/core/public/mocks'; import { coreMock } from '../../../../../../src/core/public/mocks';
import { AlertListState, Immutable } from '../../../common/endpoint_alerts/types'; import { AlertListState } from '../../../common/endpoint_alerts/types';
import { depsStartMock, DepsStartMock } from '../../common/mock/endpoint'; import { depsStartMock, DepsStartMock } from '../../common/mock/endpoint';
import { alertListReducer } from './reducer'; import { alertListReducer } from './reducer';
@ -16,6 +16,7 @@ import { alertListReducer } from './reducer';
import { alertMiddlewareFactory } from './middleware'; import { alertMiddlewareFactory } from './middleware';
import { mockAlertResultList } from './mock_alert_result_list'; import { mockAlertResultList } from './mock_alert_result_list';
import { Immutable } from '../../../common/endpoint/types';
describe('alert details tests', () => { describe('alert details tests', () => {
let store: Store; let store: Store;

View file

@ -7,12 +7,13 @@
import { Store, createStore, applyMiddleware } from 'redux'; import { Store, createStore, applyMiddleware } from 'redux';
import { History, createBrowserHistory } from 'history'; import { History, createBrowserHistory } from 'history';
import { alertListReducer } from './reducer'; import { alertListReducer } from './reducer';
import { AlertListState, AlertResultList, Immutable } from '../../../common/endpoint_alerts/types'; import { AlertListState, AlertResultList } from '../../../common/endpoint_alerts/types';
import { alertMiddlewareFactory } from './middleware'; import { alertMiddlewareFactory } from './middleware';
import { coreMock } from 'src/core/public/mocks'; import { coreMock } from 'src/core/public/mocks';
import { DepsStartMock, depsStartMock } from '../../common/mock/endpoint'; import { DepsStartMock, depsStartMock } from '../../common/mock/endpoint';
import { isOnAlertPage } from './selectors'; import { isOnAlertPage } from './selectors';
import { mockAlertResultList } from './mock_alert_result_list'; import { mockAlertResultList } from './mock_alert_result_list';
import { Immutable } from '../../../common/endpoint/types';
describe('alert list tests', () => { describe('alert list tests', () => {
let store: Store; let store: Store;

View file

@ -1,20 +0,0 @@
/*
* 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 { AlertListState, Immutable } from '../../../common/endpoint_alerts/types';
import { ImmutableReducer } from '../../common/store';
import { AppAction } from '../../common/store/actions';
export { alertListReducer } from './reducer';
export { AlertAction } from './action';
export interface EndpointAlertsPluginState {
alertList: Immutable<AlertListState>;
}
export interface EndpointAlertsPluginReducer {
alertList: ImmutableReducer<AlertListState, AppAction>;
}

View file

@ -20,9 +20,8 @@ import {
uiQueryParams, uiQueryParams,
isAlertPageTabChange, isAlertPageTabChange,
} from './selectors'; } from './selectors';
import { Immutable } from '../../../common/endpoint/types';
export const alertMiddlewareFactory: ImmutableMiddlewareFactory<Immutable<AlertListState>> = ( export const alertMiddlewareFactory: ImmutableMiddlewareFactory<AlertListState> = (
coreStart, coreStart,
depsStart depsStart
) => { ) => {

View file

@ -4,12 +4,12 @@
* you may not use this file except in compliance with the Elastic License. * you may not use this file except in compliance with the Elastic License.
*/ */
import { Immutable, AlertListState } from '../../../common/endpoint_alerts/types'; import { Immutable } from '../../../common/endpoint/types';
import { AlertListState } from '../../../common/endpoint_alerts/types';
import { ImmutableReducer } from '../../common/store'; import { ImmutableReducer } from '../../common/store';
import { AppAction } from '../../common/store/actions'; import { AppAction } from '../../common/store/actions';
export const initialAlertListState = (): Immutable<AlertListState> => { export const initialAlertListState: Immutable<AlertListState> = {
return {
alerts: [], alerts: [],
alertDetails: undefined, alertDetails: undefined,
pageSize: 10, pageSize: 10,
@ -20,10 +20,9 @@ export const initialAlertListState = (): Immutable<AlertListState> => {
patterns: [], patterns: [],
}, },
}; };
};
export const alertListReducer: ImmutableReducer<AlertListState, AppAction> = ( export const alertListReducer: ImmutableReducer<AlertListState, AppAction> = (
state = initialAlertListState(), state = initialAlertListState,
action action
) => { ) => {
if (action.type === 'serverReturnedAlertsData') { if (action.type === 'serverReturnedAlertsData') {

View file

@ -12,10 +12,10 @@ import {
} from 'reselect'; } from 'reselect';
import { encode, decode } from 'rison-node'; import { encode, decode } from 'rison-node';
import { Immutable } from '../../../common/endpoint/types';
import { Query, TimeRange, Filter } from '../../../../../../src/plugins/data/public'; import { Query, TimeRange, Filter } from '../../../../../../src/plugins/data/public';
import { import {
Immutable,
AlertingIndexGetQueryInput, AlertingIndexGetQueryInput,
AlertListState, AlertListState,
AlertingIndexUIQueryParams, AlertingIndexUIQueryParams,

View file

@ -11,7 +11,7 @@ import { Store } from 'redux';
import { mockAlertDetailsResult } from '../store/mock_alert_result_list'; import { mockAlertDetailsResult } from '../store/mock_alert_result_list';
import { alertPageTestRender } from './test_helpers/render_alert_page'; import { alertPageTestRender } from './test_helpers/render_alert_page';
import { AppAction } from '../../common/store/actions'; import { AppAction } from '../../common/store/actions';
import { State } from '../../common/store/reducer'; import { State } from '../../common/store/types';
describe('when the alert details flyout is open', () => { describe('when the alert details flyout is open', () => {
let render: () => reactTestingLibrary.RenderResult; let render: () => reactTestingLibrary.RenderResult;

View file

@ -6,7 +6,8 @@
import React, { memo, useMemo } from 'react'; import React, { memo, useMemo } from 'react';
import { i18n } from '@kbn/i18n'; import { i18n } from '@kbn/i18n';
import { EuiAccordion, EuiDescriptionList } from '@elastic/eui'; import { EuiAccordion, EuiDescriptionList } from '@elastic/eui';
import { Immutable, AlertData } from '../../../../../common/endpoint_alerts/types'; import { Immutable } from '../../../../../common/endpoint/types';
import { AlertData } from '../../../../../common/endpoint_alerts/types';
import { FormattedDate } from '../../formatted_date'; import { FormattedDate } from '../../formatted_date';
export const FileAccordion = memo(({ alertData }: { alertData: Immutable<AlertData> }) => { export const FileAccordion = memo(({ alertData }: { alertData: Immutable<AlertData> }) => {

View file

@ -6,8 +6,9 @@
import React, { memo, useMemo } from 'react'; import React, { memo, useMemo } from 'react';
import { i18n } from '@kbn/i18n'; import { i18n } from '@kbn/i18n';
import { EuiAccordion, EuiDescriptionList } from '@elastic/eui'; import { EuiAccordion, EuiDescriptionList } from '@elastic/eui';
import { Immutable, AlertData } from '../../../../../common/endpoint_alerts/types'; import { AlertData } from '../../../../../common/endpoint_alerts/types';
import { FormattedDate } from '../../formatted_date'; import { FormattedDate } from '../../formatted_date';
import { Immutable } from '../../../../../common/endpoint/types';
export const GeneralAccordion = memo(({ alertData }: { alertData: Immutable<AlertData> }) => { export const GeneralAccordion = memo(({ alertData }: { alertData: Immutable<AlertData> }) => {
const columns = useMemo(() => { const columns = useMemo(() => {

View file

@ -6,7 +6,8 @@
import React, { memo, useMemo } from 'react'; import React, { memo, useMemo } from 'react';
import { i18n } from '@kbn/i18n'; import { i18n } from '@kbn/i18n';
import { EuiAccordion, EuiDescriptionList } from '@elastic/eui'; import { EuiAccordion, EuiDescriptionList } from '@elastic/eui';
import { Immutable, AlertData } from '../../../../../common/endpoint_alerts/types'; import { Immutable } from '../../../../../common/endpoint/types';
import { AlertData } from '../../../../../common/endpoint_alerts/types';
export const HashAccordion = memo(({ alertData }: { alertData: Immutable<AlertData> }) => { export const HashAccordion = memo(({ alertData }: { alertData: Immutable<AlertData> }) => {
const columns = useMemo(() => { const columns = useMemo(() => {

View file

@ -8,7 +8,8 @@ import { i18n } from '@kbn/i18n';
import { EuiAccordion, EuiDescriptionList, EuiHealth } from '@elastic/eui'; import { EuiAccordion, EuiDescriptionList, EuiHealth } from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n/react'; import { FormattedMessage } from '@kbn/i18n/react';
import { Immutable, AlertDetails } from '../../../../../common/endpoint_alerts/types'; import { Immutable } from '../../../../../common/endpoint/types';
import { AlertDetails } from '../../../../../common/endpoint_alerts/types';
export const HostAccordion = memo(({ alertData }: { alertData: Immutable<AlertDetails> }) => { export const HostAccordion = memo(({ alertData }: { alertData: Immutable<AlertDetails> }) => {
const columns = useMemo(() => { const columns = useMemo(() => {

View file

@ -6,7 +6,8 @@
import React, { memo, useMemo } from 'react'; import React, { memo, useMemo } from 'react';
import { i18n } from '@kbn/i18n'; import { i18n } from '@kbn/i18n';
import { EuiAccordion, EuiDescriptionList } from '@elastic/eui'; import { EuiAccordion, EuiDescriptionList } from '@elastic/eui';
import { Immutable, AlertData } from '../../../../../common/endpoint_alerts/types'; import { Immutable } from '../../../../../common/endpoint/types';
import { AlertData } from '../../../../../common/endpoint_alerts/types';
export const SourceProcessAccordion = memo(({ alertData }: { alertData: Immutable<AlertData> }) => { export const SourceProcessAccordion = memo(({ alertData }: { alertData: Immutable<AlertData> }) => {
const columns = useMemo(() => { const columns = useMemo(() => {

View file

@ -6,7 +6,8 @@
import React, { memo, useMemo } from 'react'; import React, { memo, useMemo } from 'react';
import { i18n } from '@kbn/i18n'; import { i18n } from '@kbn/i18n';
import { EuiAccordion, EuiDescriptionList } from '@elastic/eui'; import { EuiAccordion, EuiDescriptionList } from '@elastic/eui';
import { Immutable, AlertData } from '../../../../../common/endpoint_alerts/types'; import { Immutable } from '../../../../../common/endpoint/types';
import { AlertData } from '../../../../../common/endpoint_alerts/types';
export const SourceProcessTokenAccordion = memo( export const SourceProcessTokenAccordion = memo(
({ alertData }: { alertData: Immutable<AlertData> }) => { ({ alertData }: { alertData: Immutable<AlertData> }) => {

View file

@ -5,8 +5,9 @@
*/ */
import { useSelector } from 'react-redux'; import { useSelector } from 'react-redux';
import { Immutable, AlertListState } from '../../../../common/endpoint_alerts/types'; import { Immutable } from '../../../../common/endpoint/types';
import { State } from '../../../common/store/reducer'; import { AlertListState } from '../../../../common/endpoint_alerts/types';
import { State } from '../../../common/store/types';
export function useAlertListSelector<TSelected>( export function useAlertListSelector<TSelected>(
selector: ( selector: (

View file

@ -12,7 +12,7 @@ import { Store } from 'redux';
import { mockAlertResultList } from '../store/mock_alert_result_list'; import { mockAlertResultList } from '../store/mock_alert_result_list';
import { alertPageTestRender } from './test_helpers/render_alert_page'; import { alertPageTestRender } from './test_helpers/render_alert_page';
import { DepsStartMock } from '../../common/mock/endpoint'; import { DepsStartMock } from '../../common/mock/endpoint';
import { State } from '../../common/store/reducer'; import { State } from '../../common/store/types';
import { AppAction } from '../../common/store/actions'; import { AppAction } from '../../common/store/actions';
describe('when on the alerting page', () => { describe('when on the alerting page', () => {

View file

@ -4,15 +4,32 @@
* you may not use this file except in compliance with the Elastic License. * you may not use this file except in compliance with the Elastic License.
*/ */
import { Reducer } from 'redux';
import { SecuritySubPluginWithStore } from '../app/types'; import { SecuritySubPluginWithStore } from '../app/types';
import { getEndpointHostsRoutes } from './routes'; import { endpointHostsRoutes } from './routes';
import { initialHostListState, hostListReducer } from './store/reducer'; import { hostListReducer } from './store/reducer';
import { Immutable } from '../../common/endpoint/types';
import { HostState } from './types'; import { HostState } from './types';
import { hostMiddlewareFactory } from './store/middleware'; import { hostMiddlewareFactory } from './store/middleware';
import { CoreStart } from '../../../../../src/core/public'; import { CoreStart } from '../../../../../src/core/public';
import { StartPlugins } from '../types'; import { StartPlugins } from '../types';
import { substateMiddlewareFactory } from '../common/store'; import { substateMiddlewareFactory } from '../common/store';
import { AppAction } from '../common/store/actions';
/**
* Internally, our state is sometimes immutable, ignore that in our external
* interface.
*/
export interface EndpointHostsPluginState {
hostList: HostState;
}
/**
* Internally, we use `ImmutableReducer`, but we present a regular reducer
* externally for compatibility w/ regular redux.
*/
export interface EndpointHostsPluginReducer {
hostList: Reducer<HostState, AppAction>;
}
export class EndpointHosts { export class EndpointHosts {
public setup() {} public setup() {}
@ -20,7 +37,7 @@ export class EndpointHosts {
public start( public start(
core: CoreStart, core: CoreStart,
plugins: StartPlugins plugins: StartPlugins
): SecuritySubPluginWithStore<'hostList', Immutable<HostState>> { ): SecuritySubPluginWithStore<'hostList', HostState> {
const { data, ingestManager } = plugins; const { data, ingestManager } = plugins;
const middleware = [ const middleware = [
substateMiddlewareFactory( substateMiddlewareFactory(
@ -29,10 +46,14 @@ export class EndpointHosts {
), ),
]; ];
return { return {
routes: getEndpointHostsRoutes(), routes: endpointHostsRoutes(),
store: { store: {
initialState: { hostList: initialHostListState() }, initialState: { hostList: undefined },
reducer: { hostList: hostListReducer }, /**
* Cast the ImmutableReducer to a regular reducer for compatibility with
* the subplugin architecture (which expects plain redux reducers.)
*/
reducer: { hostList: hostListReducer } as EndpointHostsPluginReducer,
middleware, middleware,
}, },
}; };

View file

@ -9,7 +9,7 @@ import { Route } from 'react-router-dom';
import { HostList } from './view'; import { HostList } from './view';
export const getEndpointHostsRoutes = () => [ export const endpointHostsRoutes = () => [
<Route path="/:pageName(endpoint-hosts)"> <Route path="/:pageName(endpoint-hosts)">
<HostList /> <HostList />
</Route>, </Route>,

View file

@ -5,10 +5,11 @@
*/ */
import { createStore, Dispatch, Store } from 'redux'; import { createStore, Dispatch, Store } from 'redux';
import { HostAction, hostListReducer } from './index';
import { HostState } from '../types'; import { HostState } from '../types';
import { listData } from './selectors'; import { listData } from './selectors';
import { mockHostResultList } from './mock_host_result_list'; import { mockHostResultList } from './mock_host_result_list';
import { HostAction } from './action';
import { hostListReducer } from './reducer';
describe('HostList store concerns', () => { describe('HostList store concerns', () => {
let store: Store<HostState>; let store: Store<HostState>;

View file

@ -1,22 +0,0 @@
/*
* 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 { HostState } from '../types';
import { ImmutableReducer } from '../../common/store';
import { AppAction } from '../../common/store/actions';
import { Immutable } from '../../../common/endpoint/types';
export { hostListReducer } from './reducer';
export { HostAction } from './action';
export { hostMiddlewareFactory } from './middleware';
export interface EndpointHostsPluginState {
hostList: Immutable<HostState>;
}
export interface EndpointHostsPluginReducer {
hostList: ImmutableReducer<HostState, AppAction>;
}

View file

@ -7,7 +7,6 @@ import { CoreStart, HttpSetup } from 'kibana/public';
import { applyMiddleware, createStore, Store } from 'redux'; import { applyMiddleware, createStore, Store } from 'redux';
import { coreMock } from '../../../../../../src/core/public/mocks'; import { coreMock } from '../../../../../../src/core/public/mocks';
import { History, createBrowserHistory } from 'history'; import { History, createBrowserHistory } from 'history';
import { hostListReducer, hostMiddlewareFactory } from './index';
import { DepsStartMock, depsStartMock } from '../../common/mock/endpoint'; import { DepsStartMock, depsStartMock } from '../../common/mock/endpoint';
@ -17,6 +16,8 @@ import { AppAction } from '../../common/store/actions';
import { mockHostResultList } from './mock_host_result_list'; import { mockHostResultList } from './mock_host_result_list';
import { listData } from './selectors'; import { listData } from './selectors';
import { HostState } from '../types'; import { HostState } from '../types';
import { hostListReducer } from './reducer';
import { hostMiddlewareFactory } from './middleware';
describe('host list middleware', () => { describe('host list middleware', () => {
let fakeCoreStart: jest.Mocked<CoreStart>; let fakeCoreStart: jest.Mocked<CoreStart>;

View file

@ -4,14 +4,12 @@
* you may not use this file except in compliance with the Elastic License. * you may not use this file except in compliance with the Elastic License.
*/ */
import { HostResultList, Immutable } from '../../../common/endpoint/types'; import { HostResultList } from '../../../common/endpoint/types';
import { ImmutableMiddlewareFactory } from '../../common/store'; import { ImmutableMiddlewareFactory } from '../../common/store';
import { isOnHostPage, hasSelectedHost, uiQueryParams, listData } from './selectors'; import { isOnHostPage, hasSelectedHost, uiQueryParams, listData } from './selectors';
import { HostState } from '../types'; import { HostState } from '../types';
export const hostMiddlewareFactory: ImmutableMiddlewareFactory<Immutable<HostState>> = ( export const hostMiddlewareFactory: ImmutableMiddlewareFactory<HostState> = (coreStart) => {
coreStart
) => {
return ({ getState, dispatch }) => (next) => async (action) => { return ({ getState, dispatch }) => (next) => async (action) => {
next(action); next(action);
const state = getState(); const state = getState();

View file

@ -10,8 +10,7 @@ import { AppAction } from '../../common/store/actions';
import { ImmutableReducer } from '../../common/store'; import { ImmutableReducer } from '../../common/store';
import { Immutable } from '../../../common/endpoint/types'; import { Immutable } from '../../../common/endpoint/types';
export const initialHostListState = (): HostState => { export const initialHostListState: Immutable<HostState> = {
return {
hosts: [], hosts: [],
pageSize: 10, pageSize: 10,
pageIndex: 0, pageIndex: 0,
@ -26,10 +25,9 @@ export const initialHostListState = (): HostState => {
policyResponseError: undefined, policyResponseError: undefined,
location: undefined, location: undefined,
}; };
};
export const hostListReducer: ImmutableReducer<HostState, AppAction> = ( export const hostListReducer: ImmutableReducer<HostState, AppAction> = (
state = initialHostListState(), state = initialHostListState,
action action
) => { ) => {
if (action.type === 'serverReturnedHostList') { if (action.type === 'serverReturnedHostList') {

View file

@ -8,7 +8,7 @@ import { useSelector } from 'react-redux';
import { useMemo } from 'react'; import { useMemo } from 'react';
import { HostState } from '../types'; import { HostState } from '../types';
import { useKibana } from '../../../../../../src/plugins/kibana_react/public'; import { useKibana } from '../../../../../../src/plugins/kibana_react/public';
import { State } from '../../common/store/reducer'; import { State } from '../../common/store/types';
export function useHostSelector<TSelected>(selector: (state: HostState) => TSelected) { export function useHostSelector<TSelected>(selector: (state: HostState) => TSelected) {
return useSelector(function (state: State) { return useSelector(function (state: State) {

View file

@ -7,7 +7,7 @@
import { get } from 'lodash/fp'; import { get } from 'lodash/fp';
import { createSelector } from 'reselect'; import { createSelector } from 'reselect';
import { State } from '../../common/store/reducer'; import { State } from '../../common/store/types';
import { GenericHostsModel, HostsType, HostsTableType } from './model'; import { GenericHostsModel, HostsType, HostsTableType } from './model';

View file

@ -5,33 +5,53 @@
*/ */
import { CoreStart } from 'kibana/public'; import { CoreStart } from 'kibana/public';
import { managementReducer, getManagementInitialState, managementMiddlewareFactory } from './store'; import { Reducer, CombinedState } from 'redux';
import { getManagementRoutes } from './routes'; import { managementRoutes } from './routes';
import { StartPlugins } from '../types'; import { StartPlugins } from '../types';
import { MANAGEMENT_STORE_GLOBAL_NAMESPACE } from './common/constants';
import { SecuritySubPluginWithStore } from '../app/types'; import { SecuritySubPluginWithStore } from '../app/types';
import { Immutable } from '../../common/endpoint/types'; import { managementReducer } from './store/reducer';
import { ManagementStoreGlobalNamespace } from './types'; import { AppAction } from '../common/store/actions';
import { ManagementState } from './store/types'; import { managementMiddlewareFactory } from './store/middleware';
import { ManagementState } from './types';
export { getManagementUrl } from './common/routing'; export { getManagementUrl } from './common/routing';
/**
* Internally, our state is sometimes immutable, ignore that in our external
* interface.
*/
export interface ManagementPluginState {
management: ManagementState;
}
/**
* Internally, we use `ImmutableReducer`, but we present a regular reducer
* externally for compatibility w/ regular redux.
*/
export interface ManagementPluginReducer {
management: Reducer<CombinedState<ManagementState>, AppAction>;
}
export class Management { export class Management {
public setup() {} public setup() {}
public start( public start(
core: CoreStart, core: CoreStart,
plugins: StartPlugins plugins: StartPlugins
): SecuritySubPluginWithStore<ManagementStoreGlobalNamespace, Immutable<ManagementState>> { ): SecuritySubPluginWithStore<'management', ManagementState> {
return { return {
routes: getManagementRoutes(), routes: managementRoutes(),
store: { store: {
initialState: { initialState: {
[MANAGEMENT_STORE_GLOBAL_NAMESPACE]: getManagementInitialState(), management: undefined,
}, },
/**
* Cast the ImmutableReducer to a regular reducer for compatibility with
* the subplugin architecture (which expects plain redux reducers.)
*/
reducer: { reducer: {
[MANAGEMENT_STORE_GLOBAL_NAMESPACE]: managementReducer, management: managementReducer,
}, } as ManagementPluginReducer,
middleware: managementMiddlewareFactory(core, plugins), middleware: managementMiddlewareFactory(core, plugins),
}, },
}; };

View file

@ -16,13 +16,13 @@ import {
sendGetFleetAgentStatusForConfig, sendGetFleetAgentStatusForConfig,
sendPutDatasource, sendPutDatasource,
} from '../policy_list/services/ingest'; } from '../policy_list/services/ingest';
import { NewPolicyData, PolicyData, Immutable } from '../../../../../../common/endpoint/types'; import { NewPolicyData, PolicyData } from '../../../../../../common/endpoint/types';
import { factory as policyConfigFactory } from '../../../../../../common/endpoint/models/policy_config'; import { factory as policyConfigFactory } from '../../../../../../common/endpoint/models/policy_config';
import { ImmutableMiddlewareFactory } from '../../../../../common/store'; import { ImmutableMiddlewareFactory } from '../../../../../common/store';
export const policyDetailsMiddlewareFactory: ImmutableMiddlewareFactory<Immutable< export const policyDetailsMiddlewareFactory: ImmutableMiddlewareFactory<PolicyDetailsState> = (
PolicyDetailsState coreStart
>> = (coreStart) => { ) => {
const http = coreStart.http; const http = coreStart.http;
return ({ getState, dispatch }) => (next) => async (action) => { return ({ getState, dispatch }) => (next) => async (action) => {

View file

@ -4,13 +4,15 @@
* you may not use this file except in compliance with the Elastic License. * you may not use this file except in compliance with the Elastic License.
*/ */
import { fullPolicy, isOnPolicyDetailsPage } from './selectors'; import { fullPolicy, isOnPolicyDetailsPage } from './selectors';
import { PolicyDetailsState } from '../../types';
import { Immutable, PolicyConfig, UIPolicyConfig } from '../../../../../../common/endpoint/types'; import { Immutable, PolicyConfig, UIPolicyConfig } from '../../../../../../common/endpoint/types';
import { ImmutableReducer } from '../../../../../common/store'; import { ImmutableReducer } from '../../../../../common/store';
import { AppAction } from '../../../../../common/store/actions'; import { AppAction } from '../../../../../common/store/actions';
import { PolicyDetailsState } from '../../types';
export const initialPolicyDetailsState = (): PolicyDetailsState => { /**
return { * Return a fresh copy of initial state, since we mutate state in the reducer.
*/
export const initialPolicyDetailsState: () => Immutable<PolicyDetailsState> = () => ({
policyItem: undefined, policyItem: undefined,
isLoading: false, isLoading: false,
agentStatusSummary: { agentStatusSummary: {
@ -20,8 +22,7 @@ export const initialPolicyDetailsState = (): PolicyDetailsState => {
online: 0, online: 0,
total: 0, total: 0,
}, },
}; });
};
export const policyDetailsReducer: ImmutableReducer<PolicyDetailsState, AppAction> = ( export const policyDetailsReducer: ImmutableReducer<PolicyDetailsState, AppAction> = (
state = initialPolicyDetailsState(), state = initialPolicyDetailsState(),

View file

@ -10,7 +10,7 @@ import { Store, applyMiddleware, createStore } from 'redux';
import { coreMock } from '../../../../../../../../../src/core/public/mocks'; import { coreMock } from '../../../../../../../../../src/core/public/mocks';
import { DATASOURCE_SAVED_OBJECT_TYPE } from '../../../../../../../ingest_manager/common'; import { DATASOURCE_SAVED_OBJECT_TYPE } from '../../../../../../../ingest_manager/common';
import { policyListReducer, initialPolicyListState } from './reducer'; import { policyListReducer } from './reducer';
import { policyListMiddlewareFactory } from './middleware'; import { policyListMiddlewareFactory } from './middleware';
import { isOnPolicyListPage, selectIsLoading, urlSearchParams } from './selectors'; import { isOnPolicyListPage, selectIsLoading, urlSearchParams } from './selectors';
@ -39,7 +39,7 @@ describe('policy list store concerns', () => {
store = createStore( store = createStore(
policyListReducer, policyListReducer,
initialPolicyListState(), undefined,
applyMiddleware(policyListMiddlewareFactory(fakeCoreStart, depsStart), actionSpyMiddleware) applyMiddleware(policyListMiddlewareFactory(fakeCoreStart, depsStart), actionSpyMiddleware)
); );
}); });

View file

@ -8,10 +8,9 @@ import { GetPolicyListResponse, PolicyListState } from '../../types';
import { sendGetEndpointSpecificDatasources } from './services/ingest'; import { sendGetEndpointSpecificDatasources } from './services/ingest';
import { isOnPolicyListPage, urlSearchParams } from './selectors'; import { isOnPolicyListPage, urlSearchParams } from './selectors';
import { ImmutableMiddlewareFactory } from '../../../../../common/store'; import { ImmutableMiddlewareFactory } from '../../../../../common/store';
import { Immutable } from '../../../../../../common/endpoint/types';
import { initialPolicyListState } from './reducer'; import { initialPolicyListState } from './reducer';
export const policyListMiddlewareFactory: ImmutableMiddlewareFactory<Immutable<PolicyListState>> = ( export const policyListMiddlewareFactory: ImmutableMiddlewareFactory<PolicyListState> = (
coreStart coreStart
) => { ) => {
const http = coreStart.http; const http = coreStart.http;
@ -20,7 +19,6 @@ export const policyListMiddlewareFactory: ImmutableMiddlewareFactory<Immutable<P
next(action); next(action);
const state = getState(); const state = getState();
const initialState = initialPolicyListState();
if (action.type === 'userChangedUrl' && isOnPolicyListPage(state)) { if (action.type === 'userChangedUrl' && isOnPolicyListPage(state)) {
const { page_index: pageIndex, page_size: pageSize } = urlSearchParams(state); const { page_index: pageIndex, page_size: pageSize } = urlSearchParams(state);
let response: GetPolicyListResponse; let response: GetPolicyListResponse;
@ -43,10 +41,10 @@ export const policyListMiddlewareFactory: ImmutableMiddlewareFactory<Immutable<P
dispatch({ dispatch({
type: 'serverReturnedPolicyListData', type: 'serverReturnedPolicyListData',
payload: { payload: {
policyItems: response ? response.items : initialState.policyItems, policyItems: response ? response.items : initialPolicyListState().policyItems,
pageIndex, pageIndex,
pageSize, pageSize,
total: response ? response.total : initialState.total, total: response ? response.total : initialPolicyListState().total,
}, },
}); });
} }

View file

@ -4,14 +4,17 @@
* you may not use this file except in compliance with the Elastic License. * you may not use this file except in compliance with the Elastic License.
*/ */
import { PolicyListState } from '../../types';
import { isOnPolicyListPage } from './selectors'; import { isOnPolicyListPage } from './selectors';
import { ImmutableReducer } from '../../../../../common/store'; import { ImmutableReducer } from '../../../../../common/store';
import { AppAction } from '../../../../../common/store/actions'; import { AppAction } from '../../../../../common/store/actions';
import { Immutable } from '../../../../../../common/endpoint/types'; import { Immutable } from '../../../../../../common/endpoint/types';
import { PolicyListState } from '../../types';
export const initialPolicyListState = (): PolicyListState => { /**
return { * Return the initial state.
* In case `state` was mutated, we return a fresh initial state object.
*/
export const initialPolicyListState: () => Immutable<PolicyListState> = () => ({
policyItems: [], policyItems: [],
isLoading: false, isLoading: false,
apiError: undefined, apiError: undefined,
@ -19,8 +22,7 @@ export const initialPolicyListState = (): PolicyListState => {
pageSize: 10, pageSize: 10,
total: 0, total: 0,
location: undefined, location: undefined,
}; });
};
export const policyListReducer: ImmutableReducer<PolicyListState, AppAction> = ( export const policyListReducer: ImmutableReducer<PolicyListState, AppAction> = (
state = initialPolicyListState(), state = initialPolicyListState(),

View file

@ -12,7 +12,7 @@ import { MANAGEMENT_ROUTING_ROOT_PATH } from './common/constants';
/** /**
* Returns the React Router Routes for the management area * Returns the React Router Routes for the management area
*/ */
export const getManagementRoutes = () => [ export const managementRoutes = () => [
// Mounts the Management interface on `/management` // Mounts the Management interface on `/management`
<Route path={MANAGEMENT_ROUTING_ROOT_PATH} component={ManagementContainer} />, <Route path={MANAGEMENT_ROUTING_ROOT_PATH} component={ManagementContainer} />,
]; ];

View file

@ -1,8 +0,0 @@
/*
* 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 { managementReducer, getManagementInitialState } from './reducer';
export { managementMiddlewareFactory } from './middleware';

View file

@ -4,30 +4,23 @@
* you may not use this file except in compliance with the Elastic License. * you may not use this file except in compliance with the Elastic License.
*/ */
import { ImmutableMultipleMiddlewareFactory, substateMiddlewareFactory } from '../../common/store'; import {
substateMiddlewareFactory,
SecuritySubPluginMiddlewareFactory,
State,
} from '../../common/store';
import { policyListMiddlewareFactory } from '../pages/policy/store/policy_list'; import { policyListMiddlewareFactory } from '../pages/policy/store/policy_list';
import { policyDetailsMiddlewareFactory } from '../pages/policy/store/policy_details'; import { policyDetailsMiddlewareFactory } from '../pages/policy/store/policy_details';
import {
MANAGEMENT_STORE_GLOBAL_NAMESPACE,
MANAGEMENT_STORE_POLICY_DETAILS_NAMESPACE,
MANAGEMENT_STORE_POLICY_LIST_NAMESPACE,
} from '../common/constants';
// @ts-ignore export const managementMiddlewareFactory: SecuritySubPluginMiddlewareFactory = (
export const managementMiddlewareFactory: ImmutableMultipleMiddlewareFactory = (
coreStart, coreStart,
depsStart depsStart
) => { ) => {
const listSelector = (state: State) => state.management.policyList;
const detailSelector = (state: State) => state.management.policyDetails;
return [ return [
substateMiddlewareFactory( substateMiddlewareFactory(listSelector, policyListMiddlewareFactory(coreStart, depsStart)),
(globalState) => substateMiddlewareFactory(detailSelector, policyDetailsMiddlewareFactory(coreStart, depsStart)),
globalState[MANAGEMENT_STORE_GLOBAL_NAMESPACE][MANAGEMENT_STORE_POLICY_LIST_NAMESPACE],
policyListMiddlewareFactory(coreStart, depsStart)
),
substateMiddlewareFactory(
(globalState) =>
globalState[MANAGEMENT_STORE_GLOBAL_NAMESPACE][MANAGEMENT_STORE_POLICY_DETAILS_NAMESPACE],
policyDetailsMiddlewareFactory(coreStart, depsStart)
),
]; ];
}; };

View file

@ -4,42 +4,34 @@
* you may not use this file except in compliance with the Elastic License. * you may not use this file except in compliance with the Elastic License.
*/ */
import { combineReducers as reduxCombineReducers } from 'redux'; import { combineReducers } from 'redux';
import { import {
initialPolicyDetailsState,
policyDetailsReducer, policyDetailsReducer,
initialPolicyDetailsState,
} from '../pages/policy/store/policy_details/reducer'; } from '../pages/policy/store/policy_details/reducer';
import { import {
initialPolicyListState,
policyListReducer, policyListReducer,
initialPolicyListState,
} from '../pages/policy/store/policy_list/reducer'; } from '../pages/policy/store/policy_list/reducer';
import { import {
MANAGEMENT_STORE_POLICY_DETAILS_NAMESPACE, MANAGEMENT_STORE_POLICY_DETAILS_NAMESPACE,
MANAGEMENT_STORE_POLICY_LIST_NAMESPACE, MANAGEMENT_STORE_POLICY_LIST_NAMESPACE,
} from '../common/constants'; } from '../common/constants';
import { ImmutableCombineReducers } from '../../common/store'; import { ImmutableCombineReducers } from '../../common/store';
import { AppAction } from '../../common/store/actions'; import { Immutable } from '../../../common/endpoint/types';
import { ManagementState } from './types'; import { ManagementState } from '../types';
// Change the type of `combinerReducers` locally const immutableCombineReducers: ImmutableCombineReducers = combineReducers;
const combineReducers: ImmutableCombineReducers = reduxCombineReducers;
/** export const mockManagementState: Immutable<ManagementState> = {
* Returns the initial state of the store for the SIEM Management section policyList: initialPolicyListState(),
*/ policyDetails: initialPolicyDetailsState(),
export const getManagementInitialState = (): ManagementState => {
return {
[MANAGEMENT_STORE_POLICY_LIST_NAMESPACE]: initialPolicyListState(),
[MANAGEMENT_STORE_POLICY_DETAILS_NAMESPACE]: initialPolicyDetailsState(),
};
}; };
/** /**
* Redux store reducer for the SIEM Management section * Redux store reducer for the SIEM Management section
*/ */
export const managementReducer = combineReducers<ManagementState, AppAction>({ export const managementReducer = immutableCombineReducers({
// @ts-ignore
[MANAGEMENT_STORE_POLICY_LIST_NAMESPACE]: policyListReducer, [MANAGEMENT_STORE_POLICY_LIST_NAMESPACE]: policyListReducer,
// @ts-ignore
[MANAGEMENT_STORE_POLICY_DETAILS_NAMESPACE]: policyDetailsReducer, [MANAGEMENT_STORE_POLICY_DETAILS_NAMESPACE]: policyDetailsReducer,
}); });

View file

@ -1,26 +0,0 @@
/*
* 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 { Immutable } from '../../../common/endpoint/types';
import { PolicyDetailsState, PolicyListState } from '../pages/policy/types';
import { ImmutableReducer } from '../../common/store';
import { AppAction } from '../../common/store/actions';
/**
* Redux store state for the Management section
*/
export interface ManagementState {
policyDetails: Immutable<PolicyDetailsState>;
policyList: Immutable<PolicyListState>;
}
export interface ManagementPluginState {
management: ManagementState;
}
export interface ManagementPluginReducer {
management: ImmutableReducer<ManagementState, AppAction>;
}

View file

@ -4,7 +4,9 @@
* you may not use this file except in compliance with the Elastic License. * you may not use this file except in compliance with the Elastic License.
*/ */
import { CombinedState } from 'redux';
import { SiemPageName } from '../app/types'; import { SiemPageName } from '../app/types';
import { PolicyListState, PolicyDetailsState } from './pages/policy/types';
/** /**
* The type for the management store global namespace. Used mostly internally to reference * The type for the management store global namespace. Used mostly internally to reference
@ -12,6 +14,11 @@ import { SiemPageName } from '../app/types';
*/ */
export type ManagementStoreGlobalNamespace = 'management'; export type ManagementStoreGlobalNamespace = 'management';
export type ManagementState = CombinedState<{
policyList: PolicyListState;
policyDetails: PolicyDetailsState;
}>;
/** /**
* The management list of sub-tabs. Changes to these will impact the Router routes. * The management list of sub-tabs. Changes to these will impact the Router routes.
*/ */

View file

@ -8,7 +8,7 @@ import { createSelector } from 'reselect';
import { get } from 'lodash/fp'; import { get } from 'lodash/fp';
import { FlowTargetSourceDest } from '../../graphql/types'; import { FlowTargetSourceDest } from '../../graphql/types';
import { State } from '../../common/store/reducer'; import { State } from '../../common/store/types';
import { initialNetworkState } from './reducer'; import { initialNetworkState } from './reducer';
import { import {
IpDetailsTableType, IpDetailsTableType,

View file

@ -14,7 +14,7 @@ import {
TimelineType, TimelineType,
TimelineStatus, TimelineStatus,
} from '../../../graphql/types'; } from '../../../graphql/types';
import { KueryFilterQuery, SerializedFilterQuery } from '../../../common/store/model'; import { KueryFilterQuery, SerializedFilterQuery } from '../../../common/store/types';
export const DEFAULT_PAGE_COUNT = 2; // Eui Pager will not render unless this is a minimum of 2 pages export const DEFAULT_PAGE_COUNT = 2; // Eui Pager will not render unless this is a minimum of 2 pages
export type KqlMode = 'filter' | 'search'; export type KqlMode = 'filter' | 'search';

View file

@ -7,7 +7,7 @@
import { createSelector } from 'reselect'; import { createSelector } from 'reselect';
import { isFromKueryExpressionValid } from '../../../common/lib/keury'; import { isFromKueryExpressionValid } from '../../../common/lib/keury';
import { State } from '../../../common/store/reducer'; import { State } from '../../../common/store/types';
import { TimelineModel } from './model'; import { TimelineModel } from './model';
import { AutoSavedWarningMsg, TimelineById } from './types'; import { AutoSavedWarningMsg, TimelineById } from './types';