From d54adb76f800897c46d0995d30530bed9c85c604 Mon Sep 17 00:00:00 2001 From: kentkwee <79371980+kentkwee@users.noreply.github.com> Date: Tue, 11 Apr 2023 14:21:40 +0200 Subject: [PATCH] feature(redux-devtools-inspector-monitor): add option to sort state tree alphabetically and/or disable collections (#1264) Co-authored-by: Kent Kwee --- .changeset/plenty-gifts-watch.md | 7 +++ extension/src/app/Actions.tsx | 3 ++ extension/src/window/store/windowReducer.ts | 2 + .../redux-devtools-app/src/actions/index.ts | 23 ++++++++ .../src/components/Settings/StateTree.tsx | 52 +++++++++++++++++++ .../src/components/Settings/index.tsx | 2 + .../src/constants/actionTypes.ts | 1 + .../src/containers/Actions.tsx | 3 ++ .../src/containers/DevTools.tsx | 8 +++ packages/redux-devtools-app/src/index.tsx | 1 + .../redux-devtools-app/src/reducers/index.ts | 3 ++ .../src/reducers/stateTreeSettings.ts | 23 ++++++++ .../src/ActionPreview.tsx | 8 +++ .../src/DevtoolsInspector.tsx | 10 ++++ .../src/tabs/StateTab.tsx | 4 ++ 15 files changed, 150 insertions(+) create mode 100644 .changeset/plenty-gifts-watch.md create mode 100644 packages/redux-devtools-app/src/components/Settings/StateTree.tsx create mode 100644 packages/redux-devtools-app/src/reducers/stateTreeSettings.ts diff --git a/.changeset/plenty-gifts-watch.md b/.changeset/plenty-gifts-watch.md new file mode 100644 index 00000000..51f97d20 --- /dev/null +++ b/.changeset/plenty-gifts-watch.md @@ -0,0 +1,7 @@ +--- +'remotedev-redux-devtools-extension': minor +'@redux-devtools/inspector-monitor': minor +--- + +Option to sort State Tree keys alphabetically +Option to disable collapsing of object keys diff --git a/extension/src/app/Actions.tsx b/extension/src/app/Actions.tsx index bf1c6f39..4e032e5c 100644 --- a/extension/src/app/Actions.tsx +++ b/extension/src/app/Actions.tsx @@ -60,6 +60,7 @@ class Actions extends Component { liftedState, liftedDispatch, position, + stateTreeSettings, } = this.props; const { features } = options; return ( @@ -75,6 +76,7 @@ class Actions extends Component { monitorState={this.props.monitorState} dispatch={liftedDispatch} features={options.features} + stateTreeSettings={stateTreeSettings} /> {sliderIsOpen && options.connectionId && options.features.jump && ( @@ -149,6 +151,7 @@ const mapStateToProps = (state: StoreState) => { dispatcherIsOpen: state.monitor.dispatcherIsOpen, sliderIsOpen: state.monitor.sliderIsOpen, reports: state.reports.data, + stateTreeSettings: state.stateTreeSettings, }; }; diff --git a/extension/src/window/store/windowReducer.ts b/extension/src/window/store/windowReducer.ts index 9a14cd3b..458b2760 100644 --- a/extension/src/window/store/windowReducer.ts +++ b/extension/src/window/store/windowReducer.ts @@ -7,6 +7,7 @@ import { section, socket, theme, + stateTreeSettings, StoreState, } from '@redux-devtools/app'; import instances from './instancesReducer'; @@ -22,6 +23,7 @@ const rootReducer: Reducer = section, theme, connection, + stateTreeSettings, }); export default rootReducer; diff --git a/packages/redux-devtools-app/src/actions/index.ts b/packages/redux-devtools-app/src/actions/index.ts index 5f5fe4a0..34523522 100644 --- a/packages/redux-devtools-app/src/actions/index.ts +++ b/packages/redux-devtools-app/src/actions/index.ts @@ -25,6 +25,7 @@ import { GET_REPORT_SUCCESS, ERROR, SET_PERSIST, + CHANGE_STATE_TREE_SETTINGS, } from '../constants/actionTypes'; import { AUTH_ERROR, @@ -82,6 +83,27 @@ export function changeTheme(data: ChangeThemeData): ChangeThemeAction { return { type: CHANGE_THEME, ...data.formData }; } +interface ChangeStateTreeSettingsFormData { + readonly sortAlphabetically: boolean; + readonly disableCollection: boolean; +} + +interface ChangeStateTreeSettingsData { + readonly formData: ChangeStateTreeSettingsFormData; +} + +export interface ChangeStateTreeSettingsAction { + readonly type: typeof CHANGE_STATE_TREE_SETTINGS; + readonly sortAlphabetically: boolean; + readonly disableCollection: boolean; +} + +export function changeStateTreeSettings( + data: ChangeStateTreeSettingsData +): ChangeStateTreeSettingsAction { + return { type: CHANGE_STATE_TREE_SETTINGS, ...data.formData }; +} + export interface InitMonitorAction { type: '@@INIT_MONITOR'; newMonitorState: unknown; @@ -568,6 +590,7 @@ interface ReduxPersistRehydrateAction { export type StoreActionWithoutUpdateStateOrLiftedAction = | ChangeSectionAction | ChangeThemeAction + | ChangeStateTreeSettingsAction | MonitorActionAction | SelectInstanceAction | SelectMonitorAction diff --git a/packages/redux-devtools-app/src/components/Settings/StateTree.tsx b/packages/redux-devtools-app/src/components/Settings/StateTree.tsx new file mode 100644 index 00000000..4a70ab0e --- /dev/null +++ b/packages/redux-devtools-app/src/components/Settings/StateTree.tsx @@ -0,0 +1,52 @@ +import React, { Component } from 'react'; +import { connect, ResolveThunks } from 'react-redux'; +import { Container, Form } from '@redux-devtools/ui'; +import { changeStateTreeSettings } from '../../actions'; +import { StoreState } from '../../reducers'; + +type StateProps = ReturnType; +type DispatchProps = ResolveThunks; +type Props = StateProps & DispatchProps; + +export class StateTree extends Component { + render() { + const stateTree = this.props.theme; + const formData = { + sortAlphabetically: stateTree.sortAlphabetically, + disableCollection: stateTree.disableCollection, + }; + + return ( + +
+ + ); + } +} + +const mapStateToProps = (state: StoreState) => ({ + theme: state.stateTreeSettings, +}); + +const actionCreators = { + changeStateTreeSettings, +}; + +export default connect(mapStateToProps, actionCreators)(StateTree); diff --git a/packages/redux-devtools-app/src/components/Settings/index.tsx b/packages/redux-devtools-app/src/components/Settings/index.tsx index bdc8039c..fa24ad4c 100644 --- a/packages/redux-devtools-app/src/components/Settings/index.tsx +++ b/packages/redux-devtools-app/src/components/Settings/index.tsx @@ -2,6 +2,7 @@ import React, { Component } from 'react'; import { Tabs } from '@redux-devtools/ui'; import Connection from './Connection'; import Themes from './Themes'; +import StateTree from './StateTree'; interface State { selected: string; @@ -12,6 +13,7 @@ export default class Settings extends Component<{}, State> { tabs = [ { name: 'Connection', component: Connection }, { name: 'Themes', component: Themes }, + { name: 'State Tree', component: StateTree }, ]; state: State = { selected: 'Connection' }; diff --git a/packages/redux-devtools-app/src/constants/actionTypes.ts b/packages/redux-devtools-app/src/constants/actionTypes.ts index 98b1aa38..1f983bd8 100644 --- a/packages/redux-devtools-app/src/constants/actionTypes.ts +++ b/packages/redux-devtools-app/src/constants/actionTypes.ts @@ -1,5 +1,6 @@ export const CHANGE_SECTION = 'main/CHANGE_SECTION'; export const CHANGE_THEME = 'main/CHANGE_THEME'; +export const CHANGE_STATE_TREE_SETTINGS = 'main/CHANGE_STATE_TREE_SETTINGS'; export const UPDATE_STATE = 'devTools/UPDATE_STATE'; export const SET_STATE = 'devTools/SET_STATE'; diff --git a/packages/redux-devtools-app/src/containers/Actions.tsx b/packages/redux-devtools-app/src/containers/Actions.tsx index d56be9d1..502035f0 100644 --- a/packages/redux-devtools-app/src/containers/Actions.tsx +++ b/packages/redux-devtools-app/src/containers/Actions.tsx @@ -23,6 +23,7 @@ class Actions extends Component { options, liftedState, liftedDispatch, + stateTreeSettings, } = this.props; return ( @@ -37,6 +38,7 @@ class Actions extends Component { monitorState={this.props.monitorState} dispatch={liftedDispatch} features={options.features} + stateTreeSettings={stateTreeSettings} /> {sliderIsOpen && options.connectionId && options.features.jump && ( @@ -65,6 +67,7 @@ const mapStateToProps = (state: StoreState) => { dispatcherIsOpen: state.monitor.dispatcherIsOpen, sliderIsOpen: state.monitor.sliderIsOpen, reports: state.reports.data, + stateTreeSettings: state.stateTreeSettings, }; }; diff --git a/packages/redux-devtools-app/src/containers/DevTools.tsx b/packages/redux-devtools-app/src/containers/DevTools.tsx index 9915fbca..76f4e7f2 100644 --- a/packages/redux-devtools-app/src/containers/DevTools.tsx +++ b/packages/redux-devtools-app/src/containers/DevTools.tsx @@ -7,6 +7,7 @@ import { InitMonitorAction } from '../actions'; import { Features, State } from '../reducers/instances'; import { MonitorStateMonitorState } from '../reducers/monitor'; import { ThemeFromProvider } from '@redux-devtools/ui'; +import { StateTreeSettings } from '../reducers/stateTreeSettings'; interface Props { monitor: string; @@ -17,6 +18,7 @@ interface Props { ) => void; features: Features | undefined; theme: ThemeFromProvider; + stateTreeSettings: StateTreeSettings; } class DevTools extends Component { @@ -110,6 +112,12 @@ class DevTools extends Component { features={this.props.features} dispatch={this.dispatch} theme={this.props.theme} + sortStateTreeAlphabetically={ + this.props.stateTreeSettings.sortAlphabetically + } + disableStateTreeCollection={ + this.props.stateTreeSettings.disableCollection + } /> ); diff --git a/packages/redux-devtools-app/src/index.tsx b/packages/redux-devtools-app/src/index.tsx index 42d6e026..d4a8344f 100644 --- a/packages/redux-devtools-app/src/index.tsx +++ b/packages/redux-devtools-app/src/index.tsx @@ -65,5 +65,6 @@ export * from './reducers/reports'; export * from './reducers/section'; export * from './reducers/socket'; export * from './reducers/theme'; +export * from './reducers/stateTreeSettings'; export * from './utils/monitorActions'; export * from './utils/stringifyJSON'; diff --git a/packages/redux-devtools-app/src/reducers/index.ts b/packages/redux-devtools-app/src/reducers/index.ts index 210b1c49..815f84d6 100644 --- a/packages/redux-devtools-app/src/reducers/index.ts +++ b/packages/redux-devtools-app/src/reducers/index.ts @@ -8,10 +8,12 @@ import { instances, InstancesState } from './instances'; import { reports, ReportsState } from './reports'; import { theme, ThemeState } from './theme'; import { StoreAction } from '../actions'; +import { stateTreeSettings, StateTreeSettings } from './stateTreeSettings'; export interface StoreState { readonly section: SectionState; readonly theme: ThemeState; + readonly stateTreeSettings: StateTreeSettings; readonly connection: ConnectionState; readonly socket: SocketState; readonly monitor: MonitorState; @@ -23,6 +25,7 @@ export interface StoreState { export const rootReducer = combineReducers({ section, theme, + stateTreeSettings, connection, socket, monitor, diff --git a/packages/redux-devtools-app/src/reducers/stateTreeSettings.ts b/packages/redux-devtools-app/src/reducers/stateTreeSettings.ts new file mode 100644 index 00000000..4ba847b4 --- /dev/null +++ b/packages/redux-devtools-app/src/reducers/stateTreeSettings.ts @@ -0,0 +1,23 @@ +import { CHANGE_STATE_TREE_SETTINGS } from '../constants/actionTypes'; +import { StoreAction } from '../actions'; + +export interface StateTreeSettings { + readonly sortAlphabetically: boolean; + readonly disableCollection: boolean; +} + +export function stateTreeSettings( + state: StateTreeSettings = { + sortAlphabetically: false, + disableCollection: false, + }, + action: StoreAction +) { + if (action.type === CHANGE_STATE_TREE_SETTINGS) { + return { + sortAlphabetically: action.sortAlphabetically, + disableCollection: action.disableCollection, + }; + } + return state; +} diff --git a/packages/redux-devtools-inspector-monitor/src/ActionPreview.tsx b/packages/redux-devtools-inspector-monitor/src/ActionPreview.tsx index aef637df..77f80c84 100644 --- a/packages/redux-devtools-inspector-monitor/src/ActionPreview.tsx +++ b/packages/redux-devtools-inspector-monitor/src/ActionPreview.tsx @@ -21,6 +21,8 @@ export interface TabComponentProps> { base16Theme: Base16Theme; invertTheme: boolean; isWideLayout: boolean; + sortStateTreeAlphabetically: boolean; + disableStateTreeCollection: boolean; dataTypeKey: string | symbol | undefined; delta: Delta | null | undefined | false; action: A; @@ -70,6 +72,8 @@ interface Props> { onInspectPath: (path: (string | number)[]) => void; inspectedPath: (string | number)[]; onSelectTab: (tabName: string) => void; + sortStateTreeAlphabetically: boolean; + disableStateTreeCollection: boolean; } class ActionPreview> extends Component< @@ -101,6 +105,8 @@ class ActionPreview> extends Component< dataTypeKey, monitorState, updateMonitorState, + sortStateTreeAlphabetically, + disableStateTreeCollection, } = this.props; const renderedTabs: Tab[] = @@ -133,6 +139,8 @@ class ActionPreview> extends Component< base16Theme, invertTheme, isWideLayout, + sortStateTreeAlphabetically, + disableStateTreeCollection, dataTypeKey, delta, action, diff --git a/packages/redux-devtools-inspector-monitor/src/DevtoolsInspector.tsx b/packages/redux-devtools-inspector-monitor/src/DevtoolsInspector.tsx index 1590e70c..35a968c3 100644 --- a/packages/redux-devtools-inspector-monitor/src/DevtoolsInspector.tsx +++ b/packages/redux-devtools-inspector-monitor/src/DevtoolsInspector.tsx @@ -151,6 +151,8 @@ export interface ExternalProps> { hideMainButtons?: boolean; hideActionButtons?: boolean; invertTheme: boolean; + sortStateTreeAlphabetically: boolean; + disableStateTreeCollection: boolean; dataTypeKey?: string | symbol; tabs: Tab[] | ((tabs: Tab[]) => Tab[]); } @@ -177,6 +179,8 @@ export interface DevtoolsInspectorProps> diffPropertyFilter?: (name: string, context: DiffContext) => boolean; hideMainButtons?: boolean; hideActionButtons?: boolean; + sortStateTreeAlphabetically: boolean; + disableStateTreeCollection: boolean; invertTheme: boolean; dataTypeKey?: string | symbol; tabs: Tab[] | ((tabs: Tab[]) => Tab[]); @@ -220,6 +224,8 @@ class DevtoolsInspector> extends PureComponent< hideMainButtons: PropTypes.bool, hideActionButtons: PropTypes.bool, invertTheme: PropTypes.bool, + sortStateTreeAlphabetically: PropTypes.bool, + disableStateTreeCollection: PropTypes.bool, skippedActionIds: PropTypes.array, dataTypeKey: PropTypes.any, tabs: PropTypes.oneOfType([PropTypes.array, PropTypes.func]), @@ -305,6 +311,8 @@ class DevtoolsInspector> extends PureComponent< dataTypeKey, hideMainButtons, hideActionButtons, + sortStateTreeAlphabetically, + disableStateTreeCollection, } = this.props; const { selectedActionId, startActionId, searchValue, tabName } = monitorState; @@ -364,6 +372,8 @@ class DevtoolsInspector> extends PureComponent< selectedActionId, startActionId, dataTypeKey, + sortStateTreeAlphabetically, + disableStateTreeCollection, }} monitorState={this.props.monitorState} updateMonitorState={this.updateMonitorState} diff --git a/packages/redux-devtools-inspector-monitor/src/tabs/StateTab.tsx b/packages/redux-devtools-inspector-monitor/src/tabs/StateTab.tsx index dbc37f06..94c2807b 100644 --- a/packages/redux-devtools-inspector-monitor/src/tabs/StateTab.tsx +++ b/packages/redux-devtools-inspector-monitor/src/tabs/StateTab.tsx @@ -16,6 +16,8 @@ const StateTab: React.FunctionComponent< labelRenderer, dataTypeKey, isWideLayout, + sortStateTreeAlphabetically, + disableStateTreeCollection, }) => ( );