mirror of
https://github.com/reduxjs/redux-devtools.git
synced 2024-11-22 01:26:48 +03:00
feature(redux-devtools-inspector-monitor): add option to sort state tree alphabetically and/or disable collections (#1264)
Co-authored-by: Kent Kwee <kent.kwee@tngtech.com>
This commit is contained in:
parent
c52cfbe469
commit
d54adb76f8
7
.changeset/plenty-gifts-watch.md
Normal file
7
.changeset/plenty-gifts-watch.md
Normal file
|
@ -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
|
|
@ -60,6 +60,7 @@ class Actions extends Component<Props> {
|
|||
liftedState,
|
||||
liftedDispatch,
|
||||
position,
|
||||
stateTreeSettings,
|
||||
} = this.props;
|
||||
const { features } = options;
|
||||
return (
|
||||
|
@ -75,6 +76,7 @@ class Actions extends Component<Props> {
|
|||
monitorState={this.props.monitorState}
|
||||
dispatch={liftedDispatch}
|
||||
features={options.features}
|
||||
stateTreeSettings={stateTreeSettings}
|
||||
/>
|
||||
{sliderIsOpen && options.connectionId && options.features.jump && (
|
||||
<SliderMonitor liftedState={liftedState} dispatch={liftedDispatch} />
|
||||
|
@ -149,6 +151,7 @@ const mapStateToProps = (state: StoreState) => {
|
|||
dispatcherIsOpen: state.monitor.dispatcherIsOpen,
|
||||
sliderIsOpen: state.monitor.sliderIsOpen,
|
||||
reports: state.reports.data,
|
||||
stateTreeSettings: state.stateTreeSettings,
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
@ -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<StoreState, WindowStoreAction> =
|
|||
section,
|
||||
theme,
|
||||
connection,
|
||||
stateTreeSettings,
|
||||
});
|
||||
|
||||
export default rootReducer;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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<typeof mapStateToProps>;
|
||||
type DispatchProps = ResolveThunks<typeof actionCreators>;
|
||||
type Props = StateProps & DispatchProps;
|
||||
|
||||
export class StateTree extends Component<Props> {
|
||||
render() {
|
||||
const stateTree = this.props.theme;
|
||||
const formData = {
|
||||
sortAlphabetically: stateTree.sortAlphabetically,
|
||||
disableCollection: stateTree.disableCollection,
|
||||
};
|
||||
|
||||
return (
|
||||
<Container>
|
||||
<Form
|
||||
schema={{
|
||||
type: 'object',
|
||||
properties: {
|
||||
sortAlphabetically: {
|
||||
title: 'Sort Alphabetically',
|
||||
type: 'boolean',
|
||||
},
|
||||
disableCollection: {
|
||||
title: 'Disable collapsing of nodes',
|
||||
type: 'boolean',
|
||||
},
|
||||
},
|
||||
}}
|
||||
formData={formData}
|
||||
noSubmit
|
||||
onChange={this.props.changeStateTreeSettings}
|
||||
/>
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = (state: StoreState) => ({
|
||||
theme: state.stateTreeSettings,
|
||||
});
|
||||
|
||||
const actionCreators = {
|
||||
changeStateTreeSettings,
|
||||
};
|
||||
|
||||
export default connect(mapStateToProps, actionCreators)(StateTree);
|
|
@ -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' };
|
||||
|
||||
|
|
|
@ -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';
|
||||
|
|
|
@ -23,6 +23,7 @@ class Actions extends Component<Props> {
|
|||
options,
|
||||
liftedState,
|
||||
liftedDispatch,
|
||||
stateTreeSettings,
|
||||
} = this.props;
|
||||
return (
|
||||
<Container>
|
||||
|
@ -37,6 +38,7 @@ class Actions extends Component<Props> {
|
|||
monitorState={this.props.monitorState}
|
||||
dispatch={liftedDispatch}
|
||||
features={options.features}
|
||||
stateTreeSettings={stateTreeSettings}
|
||||
/>
|
||||
{sliderIsOpen && options.connectionId && options.features.jump && (
|
||||
<SliderMonitor liftedState={liftedState} dispatch={liftedDispatch} />
|
||||
|
@ -65,6 +67,7 @@ const mapStateToProps = (state: StoreState) => {
|
|||
dispatcherIsOpen: state.monitor.dispatcherIsOpen,
|
||||
sliderIsOpen: state.monitor.sliderIsOpen,
|
||||
reports: state.reports.data,
|
||||
stateTreeSettings: state.stateTreeSettings,
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
@ -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<Props> {
|
||||
|
@ -110,6 +112,12 @@ class DevTools extends Component<Props> {
|
|||
features={this.props.features}
|
||||
dispatch={this.dispatch}
|
||||
theme={this.props.theme}
|
||||
sortStateTreeAlphabetically={
|
||||
this.props.stateTreeSettings.sortAlphabetically
|
||||
}
|
||||
disableStateTreeCollection={
|
||||
this.props.stateTreeSettings.disableCollection
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -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';
|
||||
|
|
|
@ -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<StoreState, StoreAction>({
|
||||
section,
|
||||
theme,
|
||||
stateTreeSettings,
|
||||
connection,
|
||||
socket,
|
||||
monitor,
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -21,6 +21,8 @@ export interface TabComponentProps<S, A extends Action<unknown>> {
|
|||
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<S, A extends Action<unknown>> {
|
|||
onInspectPath: (path: (string | number)[]) => void;
|
||||
inspectedPath: (string | number)[];
|
||||
onSelectTab: (tabName: string) => void;
|
||||
sortStateTreeAlphabetically: boolean;
|
||||
disableStateTreeCollection: boolean;
|
||||
}
|
||||
|
||||
class ActionPreview<S, A extends Action<unknown>> extends Component<
|
||||
|
@ -101,6 +105,8 @@ class ActionPreview<S, A extends Action<unknown>> extends Component<
|
|||
dataTypeKey,
|
||||
monitorState,
|
||||
updateMonitorState,
|
||||
sortStateTreeAlphabetically,
|
||||
disableStateTreeCollection,
|
||||
} = this.props;
|
||||
|
||||
const renderedTabs: Tab<S, A>[] =
|
||||
|
@ -133,6 +139,8 @@ class ActionPreview<S, A extends Action<unknown>> extends Component<
|
|||
base16Theme,
|
||||
invertTheme,
|
||||
isWideLayout,
|
||||
sortStateTreeAlphabetically,
|
||||
disableStateTreeCollection,
|
||||
dataTypeKey,
|
||||
delta,
|
||||
action,
|
||||
|
|
|
@ -151,6 +151,8 @@ export interface ExternalProps<S, A extends Action<unknown>> {
|
|||
hideMainButtons?: boolean;
|
||||
hideActionButtons?: boolean;
|
||||
invertTheme: boolean;
|
||||
sortStateTreeAlphabetically: boolean;
|
||||
disableStateTreeCollection: boolean;
|
||||
dataTypeKey?: string | symbol;
|
||||
tabs: Tab<S, A>[] | ((tabs: Tab<S, A>[]) => Tab<S, A>[]);
|
||||
}
|
||||
|
@ -177,6 +179,8 @@ export interface DevtoolsInspectorProps<S, A extends Action<unknown>>
|
|||
diffPropertyFilter?: (name: string, context: DiffContext) => boolean;
|
||||
hideMainButtons?: boolean;
|
||||
hideActionButtons?: boolean;
|
||||
sortStateTreeAlphabetically: boolean;
|
||||
disableStateTreeCollection: boolean;
|
||||
invertTheme: boolean;
|
||||
dataTypeKey?: string | symbol;
|
||||
tabs: Tab<S, A>[] | ((tabs: Tab<S, A>[]) => Tab<S, A>[]);
|
||||
|
@ -220,6 +224,8 @@ class DevtoolsInspector<S, A extends Action<unknown>> 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<S, A extends Action<unknown>> extends PureComponent<
|
|||
dataTypeKey,
|
||||
hideMainButtons,
|
||||
hideActionButtons,
|
||||
sortStateTreeAlphabetically,
|
||||
disableStateTreeCollection,
|
||||
} = this.props;
|
||||
const { selectedActionId, startActionId, searchValue, tabName } =
|
||||
monitorState;
|
||||
|
@ -364,6 +372,8 @@ class DevtoolsInspector<S, A extends Action<unknown>> extends PureComponent<
|
|||
selectedActionId,
|
||||
startActionId,
|
||||
dataTypeKey,
|
||||
sortStateTreeAlphabetically,
|
||||
disableStateTreeCollection,
|
||||
}}
|
||||
monitorState={this.props.monitorState}
|
||||
updateMonitorState={this.updateMonitorState}
|
||||
|
|
|
@ -16,6 +16,8 @@ const StateTab: React.FunctionComponent<
|
|||
labelRenderer,
|
||||
dataTypeKey,
|
||||
isWideLayout,
|
||||
sortStateTreeAlphabetically,
|
||||
disableStateTreeCollection,
|
||||
}) => (
|
||||
<JSONTree
|
||||
labelRenderer={labelRenderer}
|
||||
|
@ -26,6 +28,8 @@ const StateTab: React.FunctionComponent<
|
|||
}
|
||||
invertTheme={invertTheme}
|
||||
hideRoot
|
||||
sortObjectKeys={sortStateTreeAlphabetically}
|
||||
{...(disableStateTreeCollection ? { collectionLimit: 0 } : {})}
|
||||
/>
|
||||
);
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user