From c0df075a4d40b0eb74f10d52140c9738a5125fcd Mon Sep 17 00:00:00 2001 From: Philippe Oberti Date: Mon, 16 Sep 2024 23:37:36 +0200 Subject: [PATCH] [kbn-expandable-flyout] - refactor internal redux store (#192644) (cherry picked from commit d776e390b013b57badafa7951c19f279cdf0f59d) --- packages/kbn-expandable-flyout/index.ts | 2 +- .../src/components/preview_section.test.tsx | 24 ++- .../src/hooks/use_expandable_flyout_api.ts | 4 +- .../src/hooks/use_expandable_flyout_state.ts | 2 +- .../src/index.stories.tsx | 140 ++++++++------ .../kbn-expandable-flyout/src/index.test.tsx | 82 ++++---- .../src/provider.test.tsx | 38 ++-- .../kbn-expandable-flyout/src/provider.tsx | 10 +- .../src/{ => store}/actions.ts | 2 +- .../reducers.test.ts} | 182 ++++++++++-------- .../src/{reducer.ts => store/reducers.ts} | 6 +- .../src/{ => store}/redux.ts | 13 +- .../src/{ => store}/state.ts | 21 +- .../src/test/provider.tsx | 10 +- 14 files changed, 308 insertions(+), 228 deletions(-) rename packages/kbn-expandable-flyout/src/{ => store}/actions.ts (98%) rename packages/kbn-expandable-flyout/src/{reducer.test.ts => store/reducers.test.ts} (78%) rename packages/kbn-expandable-flyout/src/{reducer.ts => store/reducers.ts} (96%) rename packages/kbn-expandable-flyout/src/{ => store}/redux.ts (77%) rename packages/kbn-expandable-flyout/src/{ => store}/state.ts (79%) diff --git a/packages/kbn-expandable-flyout/index.ts b/packages/kbn-expandable-flyout/index.ts index d2d304bd6aa2c..f06be45a68914 100644 --- a/packages/kbn-expandable-flyout/index.ts +++ b/packages/kbn-expandable-flyout/index.ts @@ -12,7 +12,7 @@ export { ExpandableFlyout } from './src'; export { useExpandableFlyoutApi } from './src/hooks/use_expandable_flyout_api'; export { useExpandableFlyoutState } from './src/hooks/use_expandable_flyout_state'; -export { type FlyoutState as ExpandableFlyoutState } from './src/state'; +export { type FlyoutPanels as ExpandableFlyoutState } from './src/store/state'; export { ExpandableFlyoutProvider } from './src/provider'; export { withExpandableFlyoutProvider } from './src/with_provider'; diff --git a/packages/kbn-expandable-flyout/src/components/preview_section.test.tsx b/packages/kbn-expandable-flyout/src/components/preview_section.test.tsx index 831e916f84f05..ba2b8987cc0a8 100644 --- a/packages/kbn-expandable-flyout/src/components/preview_section.test.tsx +++ b/packages/kbn-expandable-flyout/src/components/preview_section.test.tsx @@ -16,18 +16,24 @@ import { PREVIEW_SECTION_TEST_ID, } from './test_ids'; import { TestProvider } from '../test/provider'; -import { State } from '../state'; +import { State } from '../store/state'; describe('PreviewSection', () => { - const context = { - right: {}, - left: {}, - preview: [ - { - id: 'key', + const context: State = { + panels: { + byId: { + flyout: { + right: undefined, + left: undefined, + preview: [ + { + id: 'key', + }, + ], + }, }, - ], - } as unknown as State; + }, + }; const component =
{'component'}
; const left = 500; diff --git a/packages/kbn-expandable-flyout/src/hooks/use_expandable_flyout_api.ts b/packages/kbn-expandable-flyout/src/hooks/use_expandable_flyout_api.ts index 5ae8a4e474887..e1fe482f448f9 100644 --- a/packages/kbn-expandable-flyout/src/hooks/use_expandable_flyout_api.ts +++ b/packages/kbn-expandable-flyout/src/hooks/use_expandable_flyout_api.ts @@ -21,8 +21,8 @@ import { openPreviewPanelAction, openRightPanelAction, previousPreviewPanelAction, -} from '../actions'; -import { useDispatch } from '../redux'; +} from '../store/actions'; +import { useDispatch } from '../store/redux'; import { FlyoutPanelProps, type ExpandableFlyoutApi } from '../types'; export type { ExpandableFlyoutApi }; diff --git a/packages/kbn-expandable-flyout/src/hooks/use_expandable_flyout_state.ts b/packages/kbn-expandable-flyout/src/hooks/use_expandable_flyout_state.ts index f4fbb0f1f2a3f..49cac7d97a895 100644 --- a/packages/kbn-expandable-flyout/src/hooks/use_expandable_flyout_state.ts +++ b/packages/kbn-expandable-flyout/src/hooks/use_expandable_flyout_state.ts @@ -9,7 +9,7 @@ import { REDUX_ID_FOR_MEMORY_STORAGE } from '../constants'; import { useExpandableFlyoutContext } from '../context'; -import { selectPanelsById, useSelector } from '../redux'; +import { selectPanelsById, useSelector } from '../store/redux'; /** * This hook allows you to access the flyout state, read open right, left and preview panels. diff --git a/packages/kbn-expandable-flyout/src/index.stories.tsx b/packages/kbn-expandable-flyout/src/index.stories.tsx index dab81e62f9a0e..a7b1e95e43805 100644 --- a/packages/kbn-expandable-flyout/src/index.stories.tsx +++ b/packages/kbn-expandable-flyout/src/index.stories.tsx @@ -21,7 +21,7 @@ import { } from '@elastic/eui'; import { ExpandableFlyout } from '.'; import { TestProvider } from './test/provider'; -import { State } from './state'; +import { State } from './store/state'; export default { component: ExpandableFlyout, @@ -103,13 +103,15 @@ const registeredPanels = [ export const Right: Story = () => { const state: State = { - byId: { - memory: { - right: { - id: 'right', + panels: { + byId: { + memory: { + right: { + id: 'right', + }, + left: undefined, + preview: undefined, }, - left: undefined, - preview: undefined, }, }, }; @@ -126,15 +128,17 @@ export const Right: Story = () => { export const Left: Story = () => { const state: State = { - byId: { - memory: { - right: { - id: 'right', - }, - left: { - id: 'left', + panels: { + byId: { + memory: { + right: { + id: 'right', + }, + left: { + id: 'left', + }, + preview: undefined, }, - preview: undefined, }, }, }; @@ -151,19 +155,21 @@ export const Left: Story = () => { export const Preview: Story = () => { const state: State = { - byId: { - memory: { - right: { - id: 'right', - }, - left: { - id: 'left', - }, - preview: [ - { - id: 'preview1', + panels: { + byId: { + memory: { + right: { + id: 'right', + }, + left: { + id: 'left', }, - ], + preview: [ + { + id: 'preview1', + }, + ], + }, }, }, }; @@ -180,22 +186,24 @@ export const Preview: Story = () => { export const MultiplePreviews: Story = () => { const state: State = { - byId: { - memory: { - right: { - id: 'right', - }, - left: { - id: 'left', - }, - preview: [ - { - id: 'preview1', + panels: { + byId: { + memory: { + right: { + id: 'right', }, - { - id: 'preview2', + left: { + id: 'left', }, - ], + preview: [ + { + id: 'preview1', + }, + { + id: 'preview2', + }, + ], + }, }, }, }; @@ -212,13 +220,15 @@ export const MultiplePreviews: Story = () => { export const CollapsedPushVsOverlay: Story = () => { const state: State = { - byId: { - memory: { - right: { - id: 'right', + panels: { + byId: { + memory: { + right: { + id: 'right', + }, + left: undefined, + preview: undefined, }, - left: undefined, - preview: undefined, }, }, }; @@ -232,15 +242,17 @@ export const CollapsedPushVsOverlay: Story = () => { export const ExpandedPushVsOverlay: Story = () => { const state: State = { - byId: { - memory: { - right: { - id: 'right', - }, - left: { - id: 'left', + panels: { + byId: { + memory: { + right: { + id: 'right', + }, + left: { + id: 'left', + }, + preview: undefined, }, - preview: undefined, }, }, }; @@ -254,15 +266,17 @@ export const ExpandedPushVsOverlay: Story = () => { export const DisableTypeSelection: Story = () => { const state: State = { - byId: { - memory: { - right: { - id: 'right', - }, - left: { - id: 'left', + panels: { + byId: { + memory: { + right: { + id: 'right', + }, + left: { + id: 'left', + }, + preview: undefined, }, - preview: undefined, }, }, }; diff --git a/packages/kbn-expandable-flyout/src/index.test.tsx b/packages/kbn-expandable-flyout/src/index.test.tsx index 1ec37bcd547c0..14146e2da4541 100644 --- a/packages/kbn-expandable-flyout/src/index.test.tsx +++ b/packages/kbn-expandable-flyout/src/index.test.tsx @@ -18,7 +18,7 @@ import { SETTINGS_MENU_BUTTON_TEST_ID, RIGHT_SECTION_TEST_ID, } from './components/test_ids'; -import { type State } from './state'; +import { type State } from './store/state'; import { TestProvider } from './test/provider'; import { REDUX_ID_FOR_MEMORY_STORAGE } from './constants'; @@ -33,7 +33,9 @@ const registeredPanels: Panel[] = [ describe('ExpandableFlyout', () => { it(`shouldn't render flyout if no panels`, () => { const state: State = { - byId: {}, + panels: { + byId: {}, + }, }; const result = render( @@ -47,13 +49,15 @@ describe('ExpandableFlyout', () => { it('should render right section', () => { const state = { - byId: { - [id]: { - right: { - id: 'key', + panels: { + byId: { + [id]: { + right: { + id: 'key', + }, + left: undefined, + preview: undefined, }, - left: undefined, - preview: undefined, }, }, }; @@ -69,13 +73,15 @@ describe('ExpandableFlyout', () => { it('should render left section', () => { const state = { - byId: { - [id]: { - right: undefined, - left: { - id: 'key', + panels: { + byId: { + [id]: { + right: undefined, + left: { + id: 'key', + }, + preview: undefined, }, - preview: undefined, }, }, }; @@ -91,15 +97,17 @@ describe('ExpandableFlyout', () => { it('should render preview section', () => { const state = { - byId: { - [id]: { - right: undefined, - left: undefined, - preview: [ - { - id: 'key', - }, - ], + panels: { + byId: { + [id]: { + right: undefined, + left: undefined, + preview: [ + { + id: 'key', + }, + ], + }, }, }, }; @@ -115,13 +123,15 @@ describe('ExpandableFlyout', () => { it('should not render flyout when right has value but does not matches registered panels', () => { const state = { - byId: { - [id]: { - right: { - id: 'key1', + panels: { + byId: { + [id]: { + right: { + id: 'key1', + }, + left: undefined, + preview: undefined, }, - left: undefined, - preview: undefined, }, }, }; @@ -138,13 +148,15 @@ describe('ExpandableFlyout', () => { it('should render the menu to change display options', () => { const state = { - byId: { - [id]: { - right: { - id: 'key', + panels: { + byId: { + [id]: { + right: { + id: 'key', + }, + left: undefined, + preview: undefined, }, - left: undefined, - preview: undefined, }, }, }; diff --git a/packages/kbn-expandable-flyout/src/provider.test.tsx b/packages/kbn-expandable-flyout/src/provider.test.tsx index 5bf71f31653e9..5aa386090aa30 100644 --- a/packages/kbn-expandable-flyout/src/provider.test.tsx +++ b/packages/kbn-expandable-flyout/src/provider.test.tsx @@ -11,8 +11,8 @@ import React from 'react'; import { render } from '@testing-library/react'; import { TestProvider } from './test/provider'; import { UrlSynchronizer } from './provider'; -import * as actions from './actions'; -import { State } from './state'; +import * as actions from './store/actions'; +import { State } from './store/state'; import { of } from 'rxjs'; const mockGet = jest.fn(); @@ -28,14 +28,16 @@ describe('UrlSynchronizer', () => { const urlChangedAction = jest.spyOn(actions, 'urlChangedAction'); const initialState: State = { - byId: { - [urlKey]: { - right: { id: 'key1' }, - left: { id: 'key11' }, - preview: undefined, + panels: { + byId: { + [urlKey]: { + right: { id: 'key1' }, + left: { id: 'key11' }, + preview: undefined, + }, }, + needsSync: true, }, - needsSync: true, }; render( @@ -55,8 +57,10 @@ describe('UrlSynchronizer', () => { change$: mockChange$, }); const initialState: State = { - byId: {}, - needsSync: true, + panels: { + byId: {}, + needsSync: true, + }, }; render( @@ -81,14 +85,16 @@ describe('UrlSynchronizer', () => { change$: mockChange$, }); const initialState: State = { - byId: { - [urlKey]: { - right: { id: 'key1' }, - left: { id: 'key2' }, - preview: undefined, + panels: { + byId: { + [urlKey]: { + right: { id: 'key1' }, + left: { id: 'key2' }, + preview: undefined, + }, }, + needsSync: true, }, - needsSync: true, }; render( diff --git a/packages/kbn-expandable-flyout/src/provider.tsx b/packages/kbn-expandable-flyout/src/provider.tsx index 15bcabc11fc10..cad83bb0ee808 100644 --- a/packages/kbn-expandable-flyout/src/provider.tsx +++ b/packages/kbn-expandable-flyout/src/provider.tsx @@ -12,10 +12,10 @@ import React, { FC, PropsWithChildren, useEffect, useMemo } from 'react'; import { Provider as ReduxProvider } from 'react-redux'; import { useHistory } from 'react-router-dom'; import { ExpandableFlyoutContextProvider, useExpandableFlyoutContext } from './context'; -import { FlyoutState } from './state'; +import { FlyoutPanels } from './store/state'; import { useExpandableFlyoutState } from './hooks/use_expandable_flyout_state'; -import { Context, selectNeedsSync, store, useDispatch, useSelector } from './redux'; -import { urlChangedAction } from './actions'; +import { Context, selectNeedsSync, store, useDispatch, useSelector } from './store/redux'; +import { urlChangedAction } from './store/actions'; /** * Dispatches actions when url state changes and initializes the state when the app is loaded with flyout url parameters @@ -43,7 +43,7 @@ export const UrlSynchronizer = () => { return; } - const currentValue = urlStorage.get(urlKey); + const currentValue = urlStorage.get(urlKey); // Dispatch current value to redux store as it does not happen automatically if (currentValue) { @@ -56,7 +56,7 @@ export const UrlSynchronizer = () => { ); } - const subscription = urlStorage.change$(urlKey).subscribe((value) => { + const subscription = urlStorage.change$(urlKey).subscribe((value) => { dispatch(urlChangedAction({ ...value, preview: value?.preview?.at(-1), id: urlKey })); }); diff --git a/packages/kbn-expandable-flyout/src/actions.ts b/packages/kbn-expandable-flyout/src/store/actions.ts similarity index 98% rename from packages/kbn-expandable-flyout/src/actions.ts rename to packages/kbn-expandable-flyout/src/store/actions.ts index 6b127da797271..237a3d0226b05 100644 --- a/packages/kbn-expandable-flyout/src/actions.ts +++ b/packages/kbn-expandable-flyout/src/store/actions.ts @@ -8,7 +8,7 @@ */ import { createAction } from '@reduxjs/toolkit'; -import { FlyoutPanelProps } from './types'; +import { FlyoutPanelProps } from '../types'; export enum ActionType { openFlyout = 'open_flyout', diff --git a/packages/kbn-expandable-flyout/src/reducer.test.ts b/packages/kbn-expandable-flyout/src/store/reducers.test.ts similarity index 78% rename from packages/kbn-expandable-flyout/src/reducer.test.ts rename to packages/kbn-expandable-flyout/src/store/reducers.test.ts index 6cb56f86c6794..aafd72196d0f5 100644 --- a/packages/kbn-expandable-flyout/src/reducer.test.ts +++ b/packages/kbn-expandable-flyout/src/store/reducers.test.ts @@ -7,9 +7,9 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import { FlyoutPanelProps } from './types'; -import { reducer } from './reducer'; -import { initialState, State } from './state'; +import { FlyoutPanelProps } from '../types'; +import { panelsReducer } from './reducers'; +import { initialPanelsState, PanelsState } from './state'; import { closeLeftPanelAction, closePanelsAction, @@ -49,17 +49,18 @@ const previewPanel2: FlyoutPanelProps = { id: 'preview2', state: { id: 'state' }, }; -describe('reducer', () => { + +describe('panelsReducer', () => { describe('should handle openFlyout action', () => { it('should add panels to empty state', () => { - const state: State = initialState; + const state: PanelsState = initialPanelsState; const action = openPanelsAction({ right: rightPanel1, left: leftPanel1, preview: previewPanel1, id: id1, }); - const newState: State = reducer(state, action); + const newState: PanelsState = panelsReducer(state, action); expect(newState).toEqual({ byId: { @@ -74,7 +75,7 @@ describe('reducer', () => { }); it('should override all panels in the state', () => { - const state: State = { + const state: PanelsState = { byId: { [id1]: { left: leftPanel1, @@ -89,7 +90,7 @@ describe('reducer', () => { preview: previewPanel2, id: id1, }); - const newState: State = reducer(state, action); + const newState: PanelsState = panelsReducer(state, action); expect(newState).toEqual({ byId: { @@ -104,7 +105,7 @@ describe('reducer', () => { }); it('should remove all panels despite only passing a single section ', () => { - const state: State = { + const state: PanelsState = { byId: { [id1]: { left: leftPanel1, @@ -117,7 +118,7 @@ describe('reducer', () => { right: rightPanel2, id: id1, }); - const newState: State = reducer(state, action); + const newState: PanelsState = panelsReducer(state, action); expect(newState).toEqual({ byId: { @@ -132,7 +133,7 @@ describe('reducer', () => { }); it('should add panels to a new key', () => { - const state: State = { + const state: PanelsState = { byId: { [id1]: { left: leftPanel1, @@ -145,7 +146,7 @@ describe('reducer', () => { right: rightPanel2, id: id2, }); - const newState: State = reducer(state, action); + const newState: PanelsState = panelsReducer(state, action); expect(newState).toEqual({ byId: { @@ -167,9 +168,9 @@ describe('reducer', () => { describe('should handle openRightPanel action', () => { it('should add right panel to empty state', () => { - const state: State = initialState; + const state: PanelsState = initialPanelsState; const action = openRightPanelAction({ right: rightPanel1, id: id1 }); - const newState: State = reducer(state, action); + const newState: PanelsState = panelsReducer(state, action); expect(newState).toEqual({ byId: { @@ -184,7 +185,7 @@ describe('reducer', () => { }); it('should replace right panel', () => { - const state: State = { + const state: PanelsState = { byId: { [id1]: { left: leftPanel1, @@ -194,7 +195,7 @@ describe('reducer', () => { }, }; const action = openRightPanelAction({ right: rightPanel2, id: id1 }); - const newState: State = reducer(state, action); + const newState: PanelsState = panelsReducer(state, action); expect(newState).toEqual({ byId: { @@ -209,7 +210,7 @@ describe('reducer', () => { }); it('should add right panel to a different key', () => { - const state: State = { + const state: PanelsState = { byId: { [id1]: { left: leftPanel1, @@ -219,7 +220,7 @@ describe('reducer', () => { }, }; const action = openRightPanelAction({ right: rightPanel2, id: id2 }); - const newState: State = reducer(state, action); + const newState: PanelsState = panelsReducer(state, action); expect(newState).toEqual({ byId: { @@ -241,9 +242,9 @@ describe('reducer', () => { describe('should handle openLeftPanel action', () => { it('should add left panel to empty state', () => { - const state: State = initialState; + const state: PanelsState = initialPanelsState; const action = openLeftPanelAction({ left: leftPanel1, id: id1 }); - const newState: State = reducer(state, action); + const newState: PanelsState = panelsReducer(state, action); expect(newState).toEqual({ byId: { @@ -258,7 +259,7 @@ describe('reducer', () => { }); it('should replace only left panel', () => { - const state: State = { + const state: PanelsState = { byId: { [id1]: { left: leftPanel1, @@ -268,7 +269,7 @@ describe('reducer', () => { }, }; const action = openLeftPanelAction({ left: leftPanel2, id: id1 }); - const newState: State = reducer(state, action); + const newState: PanelsState = panelsReducer(state, action); expect(newState).toEqual({ byId: { @@ -283,7 +284,7 @@ describe('reducer', () => { }); it('should add left panel to a different key', () => { - const state: State = { + const state: PanelsState = { byId: { [id1]: { left: leftPanel1, @@ -293,7 +294,7 @@ describe('reducer', () => { }, }; const action = openLeftPanelAction({ left: leftPanel2, id: id2 }); - const newState: State = reducer(state, action); + const newState: PanelsState = panelsReducer(state, action); expect(newState).toEqual({ byId: { @@ -315,9 +316,9 @@ describe('reducer', () => { describe('should handle openPreviewPanel action', () => { it('should add preview panel to empty state', () => { - const state: State = initialState; + const state: PanelsState = initialPanelsState; const action = openPreviewPanelAction({ preview: previewPanel1, id: id1 }); - const newState: State = reducer(state, action); + const newState: PanelsState = panelsReducer(state, action); expect(newState).toEqual({ byId: { @@ -332,7 +333,7 @@ describe('reducer', () => { }); it('should add preview panel to the list of preview panels', () => { - const state: State = { + const state: PanelsState = { byId: { [id1]: { left: leftPanel1, @@ -342,7 +343,7 @@ describe('reducer', () => { }, }; const action = openPreviewPanelAction({ preview: previewPanel2, id: id1 }); - const newState: State = reducer(state, action); + const newState: PanelsState = panelsReducer(state, action); expect(newState).toEqual({ byId: { @@ -357,7 +358,7 @@ describe('reducer', () => { }); it('should add preview panel to a different key', () => { - const state: State = { + const state: PanelsState = { byId: { [id1]: { left: leftPanel1, @@ -367,7 +368,7 @@ describe('reducer', () => { }, }; const action = openPreviewPanelAction({ preview: previewPanel2, id: id2 }); - const newState: State = reducer(state, action); + const newState: PanelsState = panelsReducer(state, action); expect(newState).toEqual({ byId: { @@ -389,15 +390,18 @@ describe('reducer', () => { describe('should handle closeRightPanel action', () => { it('should return empty state when removing right panel from empty state', () => { - const state: State = initialState; + const state: PanelsState = initialPanelsState; const action = closeRightPanelAction({ id: id1 }); - const newState: State = reducer(state, action); + const newState: PanelsState = panelsReducer(state, action); - expect(newState).toEqual({ ...state, needsSync: true }); + expect(newState).toEqual({ + ...state, + needsSync: true, + }); }); it(`should return unmodified state when removing right panel when no right panel exist`, () => { - const state: State = { + const state: PanelsState = { byId: { [id1]: { left: leftPanel1, @@ -407,13 +411,16 @@ describe('reducer', () => { }, }; const action = closeRightPanelAction({ id: id1 }); - const newState: State = reducer(state, action); + const newState: PanelsState = panelsReducer(state, action); - expect(newState).toEqual({ ...state, needsSync: true }); + expect(newState).toEqual({ + ...state, + needsSync: true, + }); }); it('should remove right panel', () => { - const state: State = { + const state: PanelsState = { byId: { [id1]: { left: leftPanel1, @@ -424,7 +431,7 @@ describe('reducer', () => { }; const action = closeRightPanelAction({ id: id1 }); - const newState: State = reducer(state, action); + const newState: PanelsState = panelsReducer(state, action); expect(newState).toEqual({ byId: { @@ -439,7 +446,7 @@ describe('reducer', () => { }); it('should not remove right panel for a different key', () => { - const state: State = { + const state: PanelsState = { byId: { [id1]: { left: leftPanel1, @@ -450,7 +457,7 @@ describe('reducer', () => { }; const action = closeRightPanelAction({ id: id2 }); - const newState: State = reducer(state, action); + const newState: PanelsState = panelsReducer(state, action); expect(newState).toEqual({ byId: { @@ -467,15 +474,18 @@ describe('reducer', () => { describe('should handle closeLeftPanel action', () => { it('should return empty state when removing left panel on empty state', () => { - const state: State = initialState; + const state: PanelsState = initialPanelsState; const action = closeLeftPanelAction({ id: id1 }); - const newState: State = reducer(state, action); + const newState: PanelsState = panelsReducer(state, action); - expect(newState).toEqual({ ...state, needsSync: true }); + expect(newState).toEqual({ + ...state, + needsSync: true, + }); }); it(`should return unmodified state when removing left panel when no left panel exist`, () => { - const state: State = { + const state: PanelsState = { byId: { [id1]: { left: undefined, @@ -485,13 +495,16 @@ describe('reducer', () => { }, }; const action = closeLeftPanelAction({ id: id1 }); - const newState: State = reducer(state, action); + const newState: PanelsState = panelsReducer(state, action); - expect(newState).toEqual({ ...state, needsSync: true }); + expect(newState).toEqual({ + ...state, + needsSync: true, + }); }); it('should remove left panel', () => { - const state: State = { + const state: PanelsState = { byId: { [id1]: { left: leftPanel1, @@ -501,7 +514,7 @@ describe('reducer', () => { }, }; const action = closeLeftPanelAction({ id: id1 }); - const newState: State = reducer(state, action); + const newState: PanelsState = panelsReducer(state, action); expect(newState).toEqual({ byId: { @@ -516,7 +529,7 @@ describe('reducer', () => { }); it('should not remove left panel for a different key', () => { - const state: State = { + const state: PanelsState = { byId: { [id1]: { left: leftPanel1, @@ -526,7 +539,7 @@ describe('reducer', () => { }, }; const action = closeLeftPanelAction({ id: id2 }); - const newState: State = reducer(state, action); + const newState: PanelsState = panelsReducer(state, action); expect(newState).toEqual({ byId: { @@ -543,15 +556,18 @@ describe('reducer', () => { describe('should handle closePreviewPanel action', () => { it('should return empty state when removing preview panel on empty state', () => { - const state: State = initialState; + const state: PanelsState = initialPanelsState; const action = closePreviewPanelAction({ id: id1 }); - const newState: State = reducer(state, action); + const newState: PanelsState = panelsReducer(state, action); - expect(newState).toEqual({ ...state, needsSync: true }); + expect(newState).toEqual({ + ...state, + needsSync: true, + }); }); it(`should return unmodified state when removing preview panel when no preview panel exist`, () => { - const state: State = { + const state: PanelsState = { byId: { [id1]: { left: leftPanel1, @@ -561,13 +577,16 @@ describe('reducer', () => { }, }; const action = closePreviewPanelAction({ id: id1 }); - const newState: State = reducer(state, action); + const newState: PanelsState = panelsReducer(state, action); - expect(newState).toEqual({ ...state, needsSync: true }); + expect(newState).toEqual({ + ...state, + needsSync: true, + }); }); it('should remove all preview panels', () => { - const state: State = { + const state: PanelsState = { byId: { [id1]: { left: rightPanel1, @@ -577,7 +596,7 @@ describe('reducer', () => { }, }; const action = closePreviewPanelAction({ id: id1 }); - const newState: State = reducer(state, action); + const newState: PanelsState = panelsReducer(state, action); expect(newState).toEqual({ byId: { @@ -592,7 +611,7 @@ describe('reducer', () => { }); it('should not remove preview panels for a different key', () => { - const state: State = { + const state: PanelsState = { byId: { [id1]: { left: leftPanel1, @@ -602,7 +621,7 @@ describe('reducer', () => { }, }; const action = closePreviewPanelAction({ id: id2 }); - const newState: State = reducer(state, action); + const newState: PanelsState = panelsReducer(state, action); expect(newState).toEqual({ byId: { @@ -619,15 +638,18 @@ describe('reducer', () => { describe('should handle previousPreviewPanel action', () => { it('should return empty state when previous preview panel on an empty state', () => { - const state: State = initialState; + const state: PanelsState = initialPanelsState; const action = previousPreviewPanelAction({ id: id1 }); - const newState: State = reducer(state, action); + const newState: PanelsState = panelsReducer(state, action); - expect(newState).toEqual({ ...initialState, needsSync: false }); + expect(newState).toEqual({ + ...initialPanelsState, + needsSync: false, + }); }); it(`should return unmodified state when previous preview panel when no preview panel exist`, () => { - const state: State = { + const state: PanelsState = { byId: { [id1]: { left: leftPanel1, @@ -637,13 +659,16 @@ describe('reducer', () => { }, }; const action = previousPreviewPanelAction({ id: id1 }); - const newState: State = reducer(state, action); + const newState: PanelsState = panelsReducer(state, action); - expect(newState).toEqual({ ...state, needsSync: false }); + expect(newState).toEqual({ + ...state, + needsSync: false, + }); }); it('should remove only last preview panel', () => { - const state: State = { + const state: PanelsState = { byId: { [id1]: { left: rightPanel1, @@ -653,7 +678,7 @@ describe('reducer', () => { }, }; const action = previousPreviewPanelAction({ id: id1 }); - const newState: State = reducer(state, action); + const newState: PanelsState = panelsReducer(state, action); expect(newState).toEqual({ byId: { @@ -668,7 +693,7 @@ describe('reducer', () => { }); it('should not remove the last preview panel for a different key', () => { - const state: State = { + const state: PanelsState = { byId: { [id1]: { left: leftPanel1, @@ -678,7 +703,7 @@ describe('reducer', () => { }, }; const action = previousPreviewPanelAction({ id: id2 }); - const newState: State = reducer(state, action); + const newState: PanelsState = panelsReducer(state, action); expect(newState).toEqual({ byId: { @@ -695,15 +720,18 @@ describe('reducer', () => { describe('should handle closeFlyout action', () => { it('should return empty state when closing flyout on an empty state', () => { - const state: State = initialState; + const state: PanelsState = initialPanelsState; const action = closePanelsAction({ id: id1 }); - const newState: State = reducer(state, action); + const newState: PanelsState = panelsReducer(state, action); - expect(newState).toEqual({ ...initialState, needsSync: true }); + expect(newState).toEqual({ + ...initialPanelsState, + needsSync: true, + }); }); it('should remove all panels', () => { - const state: State = { + const state: PanelsState = { byId: { [id1]: { left: leftPanel1, @@ -713,7 +741,7 @@ describe('reducer', () => { }, }; const action = closePanelsAction({ id: id1 }); - const newState: State = reducer(state, action); + const newState: PanelsState = panelsReducer(state, action); expect(newState).toEqual({ byId: { @@ -728,7 +756,7 @@ describe('reducer', () => { }); it('should not remove panels for a different key', () => { - const state: State = { + const state: PanelsState = { byId: { [id1]: { left: leftPanel1, @@ -738,7 +766,7 @@ describe('reducer', () => { }, }; const action = closePanelsAction({ id: id2 }); - const newState: State = reducer(state, action); + const newState: PanelsState = panelsReducer(state, action); expect(newState).toEqual({ byId: { diff --git a/packages/kbn-expandable-flyout/src/reducer.ts b/packages/kbn-expandable-flyout/src/store/reducers.ts similarity index 96% rename from packages/kbn-expandable-flyout/src/reducer.ts rename to packages/kbn-expandable-flyout/src/store/reducers.ts index 49c4c4b9774b1..8971fd55f7571 100644 --- a/packages/kbn-expandable-flyout/src/reducer.ts +++ b/packages/kbn-expandable-flyout/src/store/reducers.ts @@ -21,9 +21,9 @@ import { openPreviewPanelAction, urlChangedAction, } from './actions'; -import { initialState } from './state'; +import { initialPanelsState } from './state'; -export const reducer = createReducer(initialState, (builder) => { +export const panelsReducer = createReducer(initialPanelsState, (builder) => { builder.addCase(openPanelsAction, (state, { payload: { preview, left, right, id } }) => { if (id in state.byId) { state.byId[id].right = right; @@ -72,7 +72,7 @@ export const reducer = createReducer(initialState, (builder) => { if (id in state.byId) { if (state.byId[id].preview) { const previewIdenticalToLastOne = deepEqual(preview, state.byId[id].preview?.at(-1)); - // Only append preview when it does not match the last item in state.byId[id].preview + // Only append preview when it does not match the last item in state.data.byId[id].preview if (!previewIdenticalToLastOne) { state.byId[id].preview?.push(preview); } diff --git a/packages/kbn-expandable-flyout/src/redux.ts b/packages/kbn-expandable-flyout/src/store/redux.ts similarity index 77% rename from packages/kbn-expandable-flyout/src/redux.ts rename to packages/kbn-expandable-flyout/src/store/redux.ts index 5cc80517c5c9f..0e81ba74de2de 100644 --- a/packages/kbn-expandable-flyout/src/redux.ts +++ b/packages/kbn-expandable-flyout/src/store/redux.ts @@ -11,13 +11,14 @@ import { createContext } from 'react'; import { createDispatchHook, createSelectorHook, ReactReduxContextValue } from 'react-redux'; import { configureStore } from '@reduxjs/toolkit'; import { createSelector } from 'reselect'; -import { reducer } from './reducer'; +import { panelsReducer } from './reducers'; import { initialState, State } from './state'; export const store = configureStore({ - reducer, + reducer: { + panels: panelsReducer, + }, devTools: process.env.NODE_ENV !== 'production', - enhancers: [], }); export const Context = createContext>({ @@ -30,7 +31,7 @@ export const useSelector = createSelectorHook(Context); const stateSelector = (state: State) => state; +const panelsSelector = createSelector(stateSelector, (state) => state.panels); export const selectPanelsById = (id: string) => - createSelector(stateSelector, (state) => state.byId[id] || {}); - -export const selectNeedsSync = () => createSelector(stateSelector, (state) => state.needsSync); + createSelector(panelsSelector, (state) => state.byId[id] || {}); +export const selectNeedsSync = () => createSelector(panelsSelector, (state) => state.needsSync); diff --git a/packages/kbn-expandable-flyout/src/state.ts b/packages/kbn-expandable-flyout/src/store/state.ts similarity index 79% rename from packages/kbn-expandable-flyout/src/state.ts rename to packages/kbn-expandable-flyout/src/store/state.ts index 40cf03f43d868..12f1b0135460b 100644 --- a/packages/kbn-expandable-flyout/src/state.ts +++ b/packages/kbn-expandable-flyout/src/store/state.ts @@ -7,9 +7,9 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import { FlyoutPanelProps } from './types'; +import { FlyoutPanelProps } from '../..'; -export interface FlyoutState { +export interface FlyoutPanels { /** * Panel to render in the left section */ @@ -24,12 +24,12 @@ export interface FlyoutState { preview: FlyoutPanelProps[] | undefined; } -export interface State { +export interface PanelsState { /** * Store the panels for multiple flyouts */ byId: { - [id: string]: FlyoutState; + [id: string]: FlyoutPanels; }; /** * Is the flyout in sync with external storage (eg. url)? @@ -39,7 +39,18 @@ export interface State { needsSync?: boolean; } -export const initialState: State = { +export const initialPanelsState: PanelsState = { byId: {}, needsSync: false, }; + +export interface State { + /** + * All panels related information + */ + panels: PanelsState; +} + +export const initialState: State = { + panels: initialPanelsState, +}; diff --git a/packages/kbn-expandable-flyout/src/test/provider.tsx b/packages/kbn-expandable-flyout/src/test/provider.tsx index bf0ca914927b2..b6914099e2e42 100644 --- a/packages/kbn-expandable-flyout/src/test/provider.tsx +++ b/packages/kbn-expandable-flyout/src/test/provider.tsx @@ -12,9 +12,9 @@ import { configureStore } from '@reduxjs/toolkit'; import React, { FC, PropsWithChildren } from 'react'; import { I18nProvider } from '@kbn/i18n-react'; import { ExpandableFlyoutContextProvider } from '../context'; -import { reducer } from '../reducer'; -import { Context } from '../redux'; -import { initialState, State } from '../state'; +import { panelsReducer } from '../store/reducers'; +import { Context } from '../store/redux'; +import { initialState, State } from '../store/state'; interface TestProviderProps { state?: State; @@ -27,7 +27,9 @@ export const TestProvider: FC> = ({ urlKey, }) => { const store = configureStore({ - reducer, + reducer: { + panels: panelsReducer, + }, devTools: false, preloadedState: state, enhancers: [],