- {getActiveButtons(hasSkippedActions).map((btn) => (
-
- ({
- Commit: onCommit,
- Sweep: onSweep,
- }[btn]())
- }
- {...styling(
- ['selectorButton', 'selectorButtonSmall'],
- false,
- true
- )}
- >
- {btn}
+ actionForm,
+ onActionFormChange,
+}) => {
+ const { isNoopFilterActive } = actionForm;
+
+ return (
+ <>
+
+
onSearch(e.target.value)}
+ placeholder="filter..."
+ />
+ {!hideMainButtons && (
+
+
+
+ {getActiveButtons(hasSkippedActions).map((btn) => (
+
+ ({
+ Commit: onCommit,
+ Sweep: onSweep,
+ }[btn]())
+ }
+ {...styling(
+ ['selectorButton', 'selectorButtonSmall'],
+ false,
+ true
+ )}
+ >
+ {btn}
+
+ ))}
- ))}
+
-
+ )}
- )}
-
-);
+
+
+
+ >
+ );
+};
ActionListHeader.propTypes = {
styling: PropTypes.func.isRequired,
@@ -70,6 +98,11 @@ ActionListHeader.propTypes = {
hideMainButtons: PropTypes.bool,
hasSkippedActions: PropTypes.bool.isRequired,
hasStagedActions: PropTypes.bool.isRequired,
+ actionForm: PropTypes.shape({
+ searchValue: PropTypes.string.isRequired,
+ isNoopFilterActive: PropTypes.bool.isRequired,
+ }).isRequired,
+ onActionFormChange: PropTypes.func.isRequired,
};
export default ActionListHeader;
diff --git a/packages/redux-devtools-inspector-monitor/src/DevtoolsInspector.tsx b/packages/redux-devtools-inspector-monitor/src/DevtoolsInspector.tsx
index aa9803fa..3681fc5a 100644
--- a/packages/redux-devtools-inspector-monitor/src/DevtoolsInspector.tsx
+++ b/packages/redux-devtools-inspector-monitor/src/DevtoolsInspector.tsx
@@ -22,6 +22,8 @@ import ActionPreview, { Tab } from './ActionPreview';
import getInspectedState from './utils/getInspectedState';
import createDiffPatcher from './createDiffPatcher';
import {
+ ActionForm,
+ changeActionFormValues,
DevtoolsInspectorAction,
DevtoolsInspectorState,
reducer,
@@ -249,6 +251,10 @@ class DevtoolsInspector
> extends PureComponent<
this.props.dispatch(updateMonitorState(monitorState));
};
+ handleActionFormChange = (formValues: Partial) => {
+ this.props.dispatch(changeActionFormValues(formValues));
+ };
+
updateSizeMode() {
const isWideLayout = this.inspectorRef!.offsetWidth > 500;
@@ -301,7 +307,7 @@ class DevtoolsInspector> extends PureComponent<
hideMainButtons,
hideActionButtons,
} = this.props;
- const { selectedActionId, startActionId, searchValue, tabName } =
+ const { selectedActionId, startActionId, actionForm, tabName } =
monitorState;
const inspectedPathType =
tabName === 'Action' ? 'inspectedActionPath' : 'inspectedStatePath';
@@ -323,7 +329,6 @@ class DevtoolsInspector> extends PureComponent<
actions,
actionIds,
isWideLayout,
- searchValue,
selectedActionId,
startActionId,
skippedActionIds,
@@ -332,7 +337,10 @@ class DevtoolsInspector> extends PureComponent<
hideActionButtons,
styling,
}}
+ actionForm={actionForm}
+ computedStates={computedStates}
onSearch={this.handleSearch}
+ onActionFormChange={this.handleActionFormChange}
onSelect={this.handleSelectAction}
onToggleAction={this.handleToggleAction}
onJumpToState={this.handleJumpToState}
@@ -400,7 +408,7 @@ class DevtoolsInspector> extends PureComponent<
};
handleSearch = (val: string) => {
- this.updateMonitorState({ searchValue: val });
+ this.handleActionFormChange({ searchValue: val });
};
handleSelectAction = (
diff --git a/packages/redux-devtools-inspector-monitor/src/redux.ts b/packages/redux-devtools-inspector-monitor/src/redux.ts
index 93b2835d..b82c742b 100644
--- a/packages/redux-devtools-inspector-monitor/src/redux.ts
+++ b/packages/redux-devtools-inspector-monitor/src/redux.ts
@@ -4,17 +4,38 @@ import { DevtoolsInspectorProps } from './DevtoolsInspector';
const UPDATE_MONITOR_STATE =
'@@redux-devtools-inspector-monitor/UPDATE_MONITOR_STATE';
+const ACTION_FORM_VALUE_CHANGE =
+ '@@redux-devtools-inspector-monitor/ACTION_FORM_VALUE_CHANGE';
+
+export interface ActionForm {
+ searchValue: string;
+ isNoopFilterActive: boolean;
+}
export interface UpdateMonitorStateAction {
type: typeof UPDATE_MONITOR_STATE;
monitorState: Partial;
}
+
+export interface ChangeActionFormAction {
+ type: typeof ACTION_FORM_VALUE_CHANGE;
+ formValues: Partial;
+}
+
export function updateMonitorState(
monitorState: Partial
): UpdateMonitorStateAction {
return { type: UPDATE_MONITOR_STATE, monitorState };
}
-export type DevtoolsInspectorAction = UpdateMonitorStateAction;
+export function changeActionFormValues(
+ formValues: Partial
+): ChangeActionFormAction {
+ return { type: ACTION_FORM_VALUE_CHANGE, formValues };
+}
+
+export type DevtoolsInspectorAction =
+ | UpdateMonitorStateAction
+ | ChangeActionFormAction;
export interface DevtoolsInspectorState {
selectedActionId: number | null;
@@ -22,7 +43,7 @@ export interface DevtoolsInspectorState {
inspectedActionPath: (string | number)[];
inspectedStatePath: (string | number)[];
tabName: string;
- searchValue?: string;
+ actionForm: ActionForm;
}
export const DEFAULT_STATE: DevtoolsInspectorState = {
@@ -31,18 +52,33 @@ export const DEFAULT_STATE: DevtoolsInspectorState = {
inspectedActionPath: [],
inspectedStatePath: [],
tabName: 'Diff',
+ actionForm: {
+ searchValue: '',
+ isNoopFilterActive: false,
+ },
};
-function reduceUpdateState(
+function internalMonitorActionReducer(
state: DevtoolsInspectorState,
action: DevtoolsInspectorAction
-) {
- return action.type === UPDATE_MONITOR_STATE
- ? {
+): DevtoolsInspectorState {
+ switch (action.type) {
+ case UPDATE_MONITOR_STATE:
+ return {
...state,
...action.monitorState,
- }
- : state;
+ };
+ case ACTION_FORM_VALUE_CHANGE:
+ return {
+ ...state,
+ actionForm: {
+ ...state.actionForm,
+ ...action.formValues,
+ },
+ };
+ default:
+ return state;
+ }
}
export function reducer>(
@@ -51,6 +87,6 @@ export function reducer>(
action: DevtoolsInspectorAction
) {
return {
- ...reduceUpdateState(state, action),
+ ...internalMonitorActionReducer(state, action),
};
}
diff --git a/packages/redux-devtools-inspector-monitor/src/utils/createStylingFromTheme.ts b/packages/redux-devtools-inspector-monitor/src/utils/createStylingFromTheme.ts
index a8e5f88f..0ef71768 100644
--- a/packages/redux-devtools-inspector-monitor/src/utils/createStylingFromTheme.ts
+++ b/packages/redux-devtools-inspector-monitor/src/utils/createStylingFromTheme.ts
@@ -83,6 +83,10 @@ const getSheetFromColorMap = (map: ColorMap) => ({
'border-color': map.LIST_BORDER_COLOR,
},
+ actionListHeaderSecondRow: {
+ padding: '5px 10px',
+ },
+
actionListRows: {
overflow: 'auto',
diff --git a/packages/redux-devtools-inspector-monitor/src/utils/filters.ts b/packages/redux-devtools-inspector-monitor/src/utils/filters.ts
new file mode 100644
index 00000000..a4cfe451
--- /dev/null
+++ b/packages/redux-devtools-inspector-monitor/src/utils/filters.ts
@@ -0,0 +1,75 @@
+import type { Action } from 'redux';
+import type { LiftedState, PerformAction } from '@redux-devtools/core';
+import { ActionForm } from '../redux';
+
+type ComputedStates = LiftedState<
+ S,
+ Action,
+ unknown
+>['computedStates'];
+
+function isNoopAction(
+ actionId: number,
+ computedStates: ComputedStates
+): boolean {
+ return (
+ actionId === 0 ||
+ computedStates[actionId]?.state === computedStates[actionId - 1]?.state
+ );
+}
+
+function filterStateChangingAction(
+ actionIds: number[],
+ computedStates: ComputedStates
+): number[] {
+ return actionIds.filter(
+ (actionId) => !isNoopAction(actionId, computedStates)
+ );
+}
+
+function filterActionsBySearchValue>(
+ searchValue: string | undefined,
+ actionIds: number[],
+ actions: Record>
+): number[] {
+ const lowerSearchValue = searchValue && searchValue.toLowerCase();
+
+ if (!lowerSearchValue) {
+ return actionIds;
+ }
+
+ return actionIds.filter((id) => {
+ const type = actions[id].action.type;
+
+ return (
+ type != null &&
+ `${type as string}`.toLowerCase().includes(lowerSearchValue)
+ );
+ });
+}
+
+export interface FilterActionsPayload> {
+ readonly actionIds: number[];
+ readonly actions: Record>;
+ readonly computedStates: ComputedStates;
+ readonly actionForm: ActionForm;
+}
+
+export function filterActions>({
+ actionIds,
+ actions,
+ computedStates,
+ actionForm,
+}: FilterActionsPayload): number[] {
+ let output = filterActionsBySearchValue(
+ actionForm.searchValue,
+ actionIds,
+ actions
+ );
+
+ if (actionForm.isNoopFilterActive) {
+ output = filterStateChangingAction(actionIds, computedStates);
+ }
+
+ return output;
+}