mirror of
https://github.com/reduxjs/redux-devtools.git
synced 2024-11-22 09:36:43 +03:00
feat(redux-devtools-log-monitor): convert to TypeScript (#613)
* Stash * And that * finish * fix up dependencies
This commit is contained in:
parent
c154405c6c
commit
2faa16319b
|
@ -1,7 +1,8 @@
|
||||||
{
|
{
|
||||||
"presets": ["@babel/preset-env", "@babel/preset-react"],
|
"presets": [
|
||||||
"plugins": [
|
"@babel/preset-env",
|
||||||
"@babel/plugin-proposal-class-properties",
|
"@babel/preset-react",
|
||||||
"@babel/plugin-proposal-export-default-from"
|
"@babel/preset-typescript"
|
||||||
]
|
],
|
||||||
|
"plugins": ["@babel/plugin-proposal-class-properties"]
|
||||||
}
|
}
|
||||||
|
|
1
packages/redux-devtools-log-monitor/.eslintignore
Normal file
1
packages/redux-devtools-log-monitor/.eslintignore
Normal file
|
@ -0,0 +1 @@
|
||||||
|
lib
|
13
packages/redux-devtools-log-monitor/.eslintrc.js
Normal file
13
packages/redux-devtools-log-monitor/.eslintrc.js
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
module.exports = {
|
||||||
|
extends: '../../.eslintrc',
|
||||||
|
overrides: [
|
||||||
|
{
|
||||||
|
files: ['*.ts', '*.tsx'],
|
||||||
|
extends: '../../eslintrc.ts.react.base.json',
|
||||||
|
parserOptions: {
|
||||||
|
tsconfigRootDir: __dirname,
|
||||||
|
project: ['./tsconfig.json'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
|
@ -2,21 +2,6 @@
|
||||||
"name": "redux-devtools-log-monitor",
|
"name": "redux-devtools-log-monitor",
|
||||||
"version": "2.0.1",
|
"version": "2.0.1",
|
||||||
"description": "The default tree view monitor for Redux DevTools",
|
"description": "The default tree view monitor for Redux DevTools",
|
||||||
"main": "lib/index.js",
|
|
||||||
"files": [
|
|
||||||
"lib",
|
|
||||||
"src"
|
|
||||||
],
|
|
||||||
"scripts": {
|
|
||||||
"clean": "rimraf lib",
|
|
||||||
"build": "babel src --out-dir lib",
|
|
||||||
"prepare": "npm run build",
|
|
||||||
"prepublishOnly": "npm run test && npm run clean && npm run build"
|
|
||||||
},
|
|
||||||
"repository": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "https://github.com/reduxjs/redux-devtools"
|
|
||||||
},
|
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"redux",
|
"redux",
|
||||||
"devtools",
|
"devtools",
|
||||||
|
@ -26,31 +11,53 @@
|
||||||
"time travel",
|
"time travel",
|
||||||
"live edit"
|
"live edit"
|
||||||
],
|
],
|
||||||
"author": "Dan Abramov <dan.abramov@me.com> (http://github.com/gaearon)",
|
"homepage": "https://github.com/reduxjs/redux-devtools/tree/master/packages/redux-devtools-log-monitor",
|
||||||
"license": "MIT",
|
|
||||||
"bugs": {
|
"bugs": {
|
||||||
"url": "https://github.com/reduxjs/redux-devtools/issues"
|
"url": "https://github.com/reduxjs/redux-devtools/issues"
|
||||||
},
|
},
|
||||||
"homepage": "https://github.com/reduxjs/redux-devtools",
|
"license": "MIT",
|
||||||
"devDependencies": {
|
"author": "Dan Abramov <dan.abramov@me.com> (http://github.com/gaearon)",
|
||||||
"@babel/cli": "^7.10.5",
|
"files": [
|
||||||
"@babel/core": "^7.11.1",
|
"lib",
|
||||||
"@babel/plugin-proposal-class-properties": "^7.10.4",
|
"src"
|
||||||
"@babel/plugin-proposal-export-default-from": "^7.10.4",
|
],
|
||||||
"@babel/preset-env": "^7.11.0",
|
"main": "lib/index.js",
|
||||||
"@babel/preset-react": "^7.10.4",
|
"types": "lib/index.d.ts",
|
||||||
"babel-loader": "^8.1.0",
|
"repository": {
|
||||||
"rimraf": "^3.0.2"
|
"type": "git",
|
||||||
|
"url": "https://github.com/reduxjs/redux-devtools"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"scripts": {
|
||||||
"react": "^16.3.0",
|
"build": "npm run build:types && npm run build:js",
|
||||||
"redux-devtools": "^3.4.0"
|
"build:types": "tsc --emitDeclarationOnly",
|
||||||
|
"build:js": "babel src --out-dir lib --extensions \".ts,.tsx\" --source-maps inline",
|
||||||
|
"clean": "rimraf lib",
|
||||||
|
"lint": "eslint . --ext .ts,.tsx",
|
||||||
|
"lint:fix": "eslint . --ext .ts,.tsx --fix",
|
||||||
|
"type-check": "tsc --noEmit",
|
||||||
|
"type-check:watch": "npm run type-check -- --watch",
|
||||||
|
"preversion": "npm run type-check && npm run lint && npm run test",
|
||||||
|
"prepublishOnly": "npm run clean && npm run build"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@types/lodash.debounce": "^4.0.6",
|
||||||
|
"@types/prop-types": "^15.7.3",
|
||||||
|
"@types/redux-devtools-themes": "^1.0.0",
|
||||||
"lodash.debounce": "^4.0.8",
|
"lodash.debounce": "^4.0.8",
|
||||||
"prop-types": "^15.7.2",
|
"prop-types": "^15.7.2",
|
||||||
"react-json-tree": "^0.12.1",
|
"react-json-tree": "^0.12.1",
|
||||||
"react-pure-render": "^1.0.2",
|
|
||||||
"redux-devtools-themes": "^1.0.0"
|
"redux-devtools-themes": "^1.0.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/react": "^16.9.46",
|
||||||
|
"react": "^16.13.1",
|
||||||
|
"redux": "^4.0.5",
|
||||||
|
"redux-devtools": "^3.6.1"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/react": "^16.9.46",
|
||||||
|
"react": "^16.3.0",
|
||||||
|
"redux": "^4.0.5",
|
||||||
|
"redux-devtools": "^3.4.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,17 +1,26 @@
|
||||||
import React, { Component } from 'react';
|
import React, { PureComponent } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import shouldPureComponentUpdate from 'react-pure-render/function';
|
import { Action, Dispatch } from 'redux';
|
||||||
import * as themes from 'redux-devtools-themes';
|
import * as themes from 'redux-devtools-themes';
|
||||||
import { ActionCreators } from 'redux-devtools';
|
import { Base16Theme } from 'redux-devtools-themes';
|
||||||
import { updateScrollTop, startConsecutiveToggle } from './actions';
|
import { ActionCreators, LiftedAction, LiftedState } from 'redux-devtools';
|
||||||
import reducer from './reducers';
|
import {
|
||||||
|
updateScrollTop,
|
||||||
|
startConsecutiveToggle,
|
||||||
|
LogMonitorAction,
|
||||||
|
} from './actions';
|
||||||
|
import reducer, { LogMonitorState } from './reducers';
|
||||||
import LogMonitorButtonBar from './LogMonitorButtonBar';
|
import LogMonitorButtonBar from './LogMonitorButtonBar';
|
||||||
import LogMonitorEntryList from './LogMonitorEntryList';
|
import LogMonitorEntryList from './LogMonitorEntryList';
|
||||||
import debounce from 'lodash.debounce';
|
import debounce from 'lodash.debounce';
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/unbound-method
|
||||||
const { toggleAction, setActionsActive } = ActionCreators;
|
const { toggleAction, setActionsActive } = ActionCreators;
|
||||||
|
|
||||||
const styles = {
|
const styles: {
|
||||||
|
container: React.CSSProperties;
|
||||||
|
elements: React.CSSProperties;
|
||||||
|
} = {
|
||||||
container: {
|
container: {
|
||||||
fontFamily: 'monaco, Consolas, Lucida Console, monospace',
|
fontFamily: 'monaco, Consolas, Lucida Console, monospace',
|
||||||
position: 'relative',
|
position: 'relative',
|
||||||
|
@ -32,7 +41,23 @@ const styles = {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export default class LogMonitor extends Component {
|
export interface LogMonitorProps<S, A extends Action<unknown>>
|
||||||
|
extends LiftedState<S, A, LogMonitorState> {
|
||||||
|
dispatch: Dispatch<LogMonitorAction | LiftedAction<S, A, LogMonitorState>>;
|
||||||
|
|
||||||
|
preserveScrollTop: boolean;
|
||||||
|
select: (state: S) => unknown;
|
||||||
|
theme: keyof typeof themes | Base16Theme;
|
||||||
|
expandActionRoot: boolean;
|
||||||
|
expandStateRoot: boolean;
|
||||||
|
markStateDiff: boolean;
|
||||||
|
hideMainButtons?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class LogMonitor<
|
||||||
|
S,
|
||||||
|
A extends Action<unknown>
|
||||||
|
> extends PureComponent<LogMonitorProps<S, A>> {
|
||||||
static update = reducer;
|
static update = reducer;
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
|
@ -56,7 +81,7 @@ export default class LogMonitor extends Component {
|
||||||
};
|
};
|
||||||
|
|
||||||
static defaultProps = {
|
static defaultProps = {
|
||||||
select: (state) => state,
|
select: (state: unknown) => state,
|
||||||
theme: 'nicinabox',
|
theme: 'nicinabox',
|
||||||
preserveScrollTop: true,
|
preserveScrollTop: true,
|
||||||
expandActionRoot: true,
|
expandActionRoot: true,
|
||||||
|
@ -64,22 +89,14 @@ export default class LogMonitor extends Component {
|
||||||
markStateDiff: false,
|
markStateDiff: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
shouldComponentUpdate = shouldPureComponentUpdate;
|
scrollDown?: boolean;
|
||||||
|
node?: HTMLDivElement | null;
|
||||||
|
|
||||||
updateScrollTop = debounce(() => {
|
updateScrollTop = debounce(() => {
|
||||||
const node = this.node;
|
const node = this.node;
|
||||||
this.props.dispatch(updateScrollTop(node ? node.scrollTop : 0));
|
this.props.dispatch(updateScrollTop(node ? node.scrollTop : 0));
|
||||||
}, 500);
|
}, 500);
|
||||||
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
this.handleToggleAction = this.handleToggleAction.bind(this);
|
|
||||||
this.handleToggleConsecutiveAction = this.handleToggleConsecutiveAction.bind(
|
|
||||||
this
|
|
||||||
);
|
|
||||||
this.getRef = this.getRef.bind(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
scroll() {
|
scroll() {
|
||||||
const node = this.node;
|
const node = this.node;
|
||||||
if (!node) {
|
if (!node) {
|
||||||
|
@ -114,7 +131,7 @@ export default class LogMonitor extends Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
UNSAFE_componentWillReceiveProps(nextProps) {
|
UNSAFE_componentWillReceiveProps(nextProps: LogMonitorProps<S, A>) {
|
||||||
const node = this.node;
|
const node = this.node;
|
||||||
if (!node) {
|
if (!node) {
|
||||||
this.scrollDown = true;
|
this.scrollDown = true;
|
||||||
|
@ -134,11 +151,11 @@ export default class LogMonitor extends Component {
|
||||||
this.scroll();
|
this.scroll();
|
||||||
}
|
}
|
||||||
|
|
||||||
handleToggleAction(id) {
|
handleToggleAction = (id: number) => {
|
||||||
this.props.dispatch(toggleAction(id));
|
this.props.dispatch(toggleAction(id));
|
||||||
}
|
};
|
||||||
|
|
||||||
handleToggleConsecutiveAction(id) {
|
handleToggleConsecutiveAction = (id: number) => {
|
||||||
const { monitorState, actionsById } = this.props;
|
const { monitorState, actionsById } = this.props;
|
||||||
const { consecutiveToggleStartId } = monitorState;
|
const { consecutiveToggleStartId } = monitorState;
|
||||||
if (consecutiveToggleStartId && actionsById[consecutiveToggleStartId]) {
|
if (consecutiveToggleStartId && actionsById[consecutiveToggleStartId]) {
|
||||||
|
@ -151,10 +168,10 @@ export default class LogMonitor extends Component {
|
||||||
} else if (id > 0) {
|
} else if (id > 0) {
|
||||||
this.props.dispatch(startConsecutiveToggle(id));
|
this.props.dispatch(startConsecutiveToggle(id));
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
getTheme() {
|
getTheme() {
|
||||||
let { theme } = this.props;
|
const { theme } = this.props;
|
||||||
if (typeof theme !== 'string') {
|
if (typeof theme !== 'string') {
|
||||||
return theme;
|
return theme;
|
||||||
}
|
}
|
||||||
|
@ -170,9 +187,9 @@ export default class LogMonitor extends Component {
|
||||||
return themes.nicinabox;
|
return themes.nicinabox;
|
||||||
}
|
}
|
||||||
|
|
||||||
getRef(node) {
|
getRef: React.RefCallback<HTMLDivElement> = (node) => {
|
||||||
this.node = node;
|
this.node = node;
|
||||||
}
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const theme = this.getTheme();
|
const theme = this.getTheme();
|
|
@ -1,8 +1,8 @@
|
||||||
import React from 'react';
|
import React, { CSSProperties } from 'react';
|
||||||
|
import { Base16Theme } from 'redux-devtools-themes';
|
||||||
import brighten from './brighten';
|
import brighten from './brighten';
|
||||||
import shouldPureComponentUpdate from 'react-pure-render/function';
|
|
||||||
|
|
||||||
const styles = {
|
const styles: { base: CSSProperties } = {
|
||||||
base: {
|
base: {
|
||||||
cursor: 'pointer',
|
cursor: 'pointer',
|
||||||
fontWeight: 'bold',
|
fontWeight: 'bold',
|
||||||
|
@ -20,48 +20,50 @@ const styles = {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export default class LogMonitorButton extends React.Component {
|
interface State {
|
||||||
shouldComponentUpdate = shouldPureComponentUpdate;
|
hovered: boolean;
|
||||||
|
active: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
constructor(props) {
|
interface Props {
|
||||||
super(props);
|
theme: Base16Theme;
|
||||||
|
onClick: () => void;
|
||||||
|
enabled: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
this.handleMouseEnter = this.handleMouseEnter.bind(this);
|
export default class LogMonitorButton extends React.PureComponent<
|
||||||
this.handleMouseLeave = this.handleMouseLeave.bind(this);
|
Props,
|
||||||
this.handleMouseDown = this.handleMouseDown.bind(this);
|
State
|
||||||
this.handleMouseUp = this.handleMouseUp.bind(this);
|
> {
|
||||||
this.onClick = this.onClick.bind(this);
|
state: State = {
|
||||||
|
|
||||||
this.state = {
|
|
||||||
hovered: false,
|
hovered: false,
|
||||||
active: false,
|
active: false,
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
handleMouseEnter() {
|
handleMouseEnter = () => {
|
||||||
this.setState({ hovered: true });
|
this.setState({ hovered: true });
|
||||||
}
|
};
|
||||||
|
|
||||||
handleMouseLeave() {
|
handleMouseLeave = () => {
|
||||||
this.setState({ hovered: false });
|
this.setState({ hovered: false });
|
||||||
}
|
};
|
||||||
|
|
||||||
handleMouseDown() {
|
handleMouseDown = () => {
|
||||||
this.setState({ active: true });
|
this.setState({ active: true });
|
||||||
}
|
};
|
||||||
|
|
||||||
handleMouseUp() {
|
handleMouseUp = () => {
|
||||||
this.setState({ active: false });
|
this.setState({ active: false });
|
||||||
}
|
};
|
||||||
|
|
||||||
onClick() {
|
onClick = () => {
|
||||||
if (!this.props.enabled) {
|
if (!this.props.enabled) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (this.props.onClick) {
|
if (this.props.onClick) {
|
||||||
this.props.onClick();
|
this.props.onClick();
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
let style = {
|
let style = {
|
|
@ -1,12 +1,16 @@
|
||||||
import React, { Component } from 'react';
|
import React, { CSSProperties, PureComponent } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import shouldPureComponentUpdate from 'react-pure-render/function';
|
import { ActionCreators, LiftedAction } from 'redux-devtools';
|
||||||
import { ActionCreators } from 'redux-devtools';
|
import { Base16Theme } from 'redux-devtools-themes';
|
||||||
|
import { Action, Dispatch } from 'redux';
|
||||||
import LogMonitorButton from './LogMonitorButton';
|
import LogMonitorButton from './LogMonitorButton';
|
||||||
|
import { LogMonitorAction } from './actions';
|
||||||
|
import { LogMonitorState } from './reducers';
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/unbound-method
|
||||||
const { reset, rollback, commit, sweep } = ActionCreators;
|
const { reset, rollback, commit, sweep } = ActionCreators;
|
||||||
|
|
||||||
const style = {
|
const style: CSSProperties = {
|
||||||
textAlign: 'center',
|
textAlign: 'center',
|
||||||
borderBottomWidth: 1,
|
borderBottomWidth: 1,
|
||||||
borderBottomStyle: 'solid',
|
borderBottomStyle: 'solid',
|
||||||
|
@ -16,37 +20,37 @@ const style = {
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
};
|
};
|
||||||
|
|
||||||
export default class LogMonitorButtonBar extends Component {
|
interface Props<S, A extends Action<unknown>> {
|
||||||
|
theme: Base16Theme;
|
||||||
|
dispatch: Dispatch<LogMonitorAction | LiftedAction<S, A, LogMonitorState>>;
|
||||||
|
hasStates: boolean;
|
||||||
|
hasSkippedActions: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class LogMonitorButtonBar<
|
||||||
|
S,
|
||||||
|
A extends Action<unknown>
|
||||||
|
> extends PureComponent<Props<S, A>> {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
dispatch: PropTypes.func,
|
dispatch: PropTypes.func,
|
||||||
theme: PropTypes.object,
|
theme: PropTypes.object,
|
||||||
};
|
};
|
||||||
|
|
||||||
shouldComponentUpdate = shouldPureComponentUpdate;
|
handleRollback = () => {
|
||||||
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
this.handleReset = this.handleReset.bind(this);
|
|
||||||
this.handleRollback = this.handleRollback.bind(this);
|
|
||||||
this.handleSweep = this.handleSweep.bind(this);
|
|
||||||
this.handleCommit = this.handleCommit.bind(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
handleRollback() {
|
|
||||||
this.props.dispatch(rollback());
|
this.props.dispatch(rollback());
|
||||||
}
|
};
|
||||||
|
|
||||||
handleSweep() {
|
handleSweep = () => {
|
||||||
this.props.dispatch(sweep());
|
this.props.dispatch(sweep());
|
||||||
}
|
};
|
||||||
|
|
||||||
handleCommit() {
|
handleCommit = () => {
|
||||||
this.props.dispatch(commit());
|
this.props.dispatch(commit());
|
||||||
}
|
};
|
||||||
|
|
||||||
handleReset() {
|
handleReset = () => {
|
||||||
this.props.dispatch(reset());
|
this.props.dispatch(reset());
|
||||||
}
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { theme, hasStates, hasSkippedActions } = this.props;
|
const { theme, hasStates, hasSkippedActions } = this.props;
|
|
@ -1,10 +1,11 @@
|
||||||
import React, { Component } from 'react';
|
import React, { CSSProperties, MouseEventHandler, PureComponent } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import JSONTree from 'react-json-tree';
|
import JSONTree, { StylingValue } from 'react-json-tree';
|
||||||
|
import { Base16Theme } from 'redux-devtools-themes';
|
||||||
|
import { Action } from 'redux';
|
||||||
import LogMonitorEntryAction from './LogMonitorEntryAction';
|
import LogMonitorEntryAction from './LogMonitorEntryAction';
|
||||||
import shouldPureComponentUpdate from 'react-pure-render/function';
|
|
||||||
|
|
||||||
const styles = {
|
const styles: { entry: CSSProperties; root: CSSProperties } = {
|
||||||
entry: {
|
entry: {
|
||||||
display: 'block',
|
display: 'block',
|
||||||
WebkitUserSelect: 'none',
|
WebkitUserSelect: 'none',
|
||||||
|
@ -15,15 +16,40 @@ const styles = {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const getDeepItem = (data, path) =>
|
const getDeepItem = (data: any, path: (string | number)[]) =>
|
||||||
path.reduce((obj, key) => obj && obj[key], data);
|
path.reduce((obj, key) => obj && obj[key], data);
|
||||||
const dataIsEqual = (data, previousData, keyPath) => {
|
const dataIsEqual = (
|
||||||
|
data: any,
|
||||||
|
previousData: unknown,
|
||||||
|
keyPath: (string | number)[]
|
||||||
|
) => {
|
||||||
const path = [...keyPath].reverse().slice(1);
|
const path = [...keyPath].reverse().slice(1);
|
||||||
|
|
||||||
return getDeepItem(data, path) === getDeepItem(previousData, path);
|
return getDeepItem(data, path) === getDeepItem(previousData, path);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default class LogMonitorEntry extends Component {
|
interface Props<S, A extends Action<unknown>> {
|
||||||
|
theme: Base16Theme;
|
||||||
|
select: (state: any) => unknown;
|
||||||
|
action: A;
|
||||||
|
actionId: number;
|
||||||
|
state: S;
|
||||||
|
previousState: S | undefined;
|
||||||
|
collapsed: boolean;
|
||||||
|
inFuture: boolean;
|
||||||
|
selected: boolean;
|
||||||
|
error: string | undefined;
|
||||||
|
expandActionRoot: boolean;
|
||||||
|
expandStateRoot: boolean;
|
||||||
|
markStateDiff: boolean;
|
||||||
|
onActionClick: (id: number) => void;
|
||||||
|
onActionShiftClick: (id: number) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class LogMonitorEntry<
|
||||||
|
S,
|
||||||
|
A extends Action<unknown>
|
||||||
|
> extends PureComponent<Props<S, A>> {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
state: PropTypes.object.isRequired,
|
state: PropTypes.object.isRequired,
|
||||||
action: PropTypes.object.isRequired,
|
action: PropTypes.object.isRequired,
|
||||||
|
@ -37,17 +63,10 @@ export default class LogMonitorEntry extends Component {
|
||||||
selected: PropTypes.bool,
|
selected: PropTypes.bool,
|
||||||
expandActionRoot: PropTypes.bool,
|
expandActionRoot: PropTypes.bool,
|
||||||
expandStateRoot: PropTypes.bool,
|
expandStateRoot: PropTypes.bool,
|
||||||
|
previousState: PropTypes.object,
|
||||||
};
|
};
|
||||||
|
|
||||||
shouldComponentUpdate = shouldPureComponentUpdate;
|
printState(state: S, error: string | undefined) {
|
||||||
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
this.handleActionClick = this.handleActionClick.bind(this);
|
|
||||||
this.shouldExpandNode = this.shouldExpandNode.bind(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
printState(state, error) {
|
|
||||||
let errorText = error;
|
let errorText = error;
|
||||||
if (!errorText) {
|
if (!errorText) {
|
||||||
try {
|
try {
|
||||||
|
@ -59,7 +78,11 @@ export default class LogMonitorEntry extends Component {
|
||||||
typeof this.props.previousState !== 'undefined'
|
typeof this.props.previousState !== 'undefined'
|
||||||
? this.props.select(this.props.previousState)
|
? this.props.select(this.props.previousState)
|
||||||
: undefined;
|
: undefined;
|
||||||
const getValueStyle = ({ style }, nodeType, keyPath) => ({
|
const getValueStyle: StylingValue = (
|
||||||
|
{ style },
|
||||||
|
nodeType,
|
||||||
|
keyPath
|
||||||
|
) => ({
|
||||||
style: {
|
style: {
|
||||||
...style,
|
...style,
|
||||||
backgroundColor: dataIsEqual(data, previousData, keyPath)
|
backgroundColor: dataIsEqual(data, previousData, keyPath)
|
||||||
|
@ -67,7 +90,7 @@ export default class LogMonitorEntry extends Component {
|
||||||
: this.props.theme.base01,
|
: this.props.theme.base01,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
const getNestedNodeStyle = ({ style }, keyPath) => ({
|
const getNestedNodeStyle: StylingValue = ({ style }, keyPath) => ({
|
||||||
style: {
|
style: {
|
||||||
...style,
|
...style,
|
||||||
...(keyPath.length > 1 ? {} : styles.root),
|
...(keyPath.length > 1 ? {} : styles.root),
|
||||||
|
@ -75,7 +98,6 @@ export default class LogMonitorEntry extends Component {
|
||||||
});
|
});
|
||||||
theme = {
|
theme = {
|
||||||
extend: this.props.theme,
|
extend: this.props.theme,
|
||||||
tree: styles.tree,
|
|
||||||
value: getValueStyle,
|
value: getValueStyle,
|
||||||
nestedNode: getNestedNodeStyle,
|
nestedNode: getNestedNodeStyle,
|
||||||
};
|
};
|
||||||
|
@ -112,7 +134,7 @@ export default class LogMonitorEntry extends Component {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
handleActionClick(e) {
|
handleActionClick: MouseEventHandler<HTMLDivElement> = (e) => {
|
||||||
const { actionId, onActionClick, onActionShiftClick } = this.props;
|
const { actionId, onActionClick, onActionShiftClick } = this.props;
|
||||||
if (actionId > 0) {
|
if (actionId > 0) {
|
||||||
if (e.shiftKey) {
|
if (e.shiftKey) {
|
||||||
|
@ -121,11 +143,15 @@ export default class LogMonitorEntry extends Component {
|
||||||
onActionClick(actionId);
|
onActionClick(actionId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
shouldExpandNode(keyName, data, level) {
|
shouldExpandNode = (
|
||||||
|
keyPath: (string | number)[],
|
||||||
|
data: any,
|
||||||
|
level: number
|
||||||
|
) => {
|
||||||
return this.props.expandStateRoot && level === 0;
|
return this.props.expandStateRoot && level === 0;
|
||||||
}
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
|
@ -1,5 +1,7 @@
|
||||||
import React, { Component } from 'react';
|
import React, { Component, CSSProperties, MouseEventHandler } from 'react';
|
||||||
import JSONTree from 'react-json-tree';
|
import JSONTree from 'react-json-tree';
|
||||||
|
import { Base16Theme } from 'redux-devtools-themes';
|
||||||
|
import { Action } from 'redux';
|
||||||
|
|
||||||
const styles = {
|
const styles = {
|
||||||
actionBar: {
|
actionBar: {
|
||||||
|
@ -14,13 +16,19 @@ const styles = {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export default class LogMonitorAction extends Component {
|
interface Props<A extends Action<unknown>> {
|
||||||
constructor(props) {
|
theme: Base16Theme;
|
||||||
super(props);
|
collapsed: boolean;
|
||||||
this.shouldExpandNode = this.shouldExpandNode.bind(this);
|
action: A;
|
||||||
}
|
expandActionRoot: boolean;
|
||||||
|
onClick: MouseEventHandler<HTMLDivElement>;
|
||||||
|
style: CSSProperties;
|
||||||
|
}
|
||||||
|
|
||||||
renderPayload(payload) {
|
export default class LogMonitorAction<
|
||||||
|
A extends Action<unknown>
|
||||||
|
> extends Component<Props<A>> {
|
||||||
|
renderPayload(payload: Record<string, unknown>) {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
|
@ -43,9 +51,13 @@ export default class LogMonitorAction extends Component {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
shouldExpandNode(keyName, data, level) {
|
shouldExpandNode = (
|
||||||
|
keyPath: (string | number)[],
|
||||||
|
data: any,
|
||||||
|
level: number
|
||||||
|
) => {
|
||||||
return this.props.expandActionRoot && level === 0;
|
return this.props.expandActionRoot && level === 0;
|
||||||
}
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { type, ...payload } = this.props.action;
|
const { type, ...payload } = this.props.action;
|
||||||
|
@ -58,7 +70,7 @@ export default class LogMonitorAction extends Component {
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div style={styles.actionBar} onClick={this.props.onClick}>
|
<div style={styles.actionBar} onClick={this.props.onClick}>
|
||||||
{type !== null && type.toString()}
|
{type !== null && (type as string).toString()}
|
||||||
</div>
|
</div>
|
||||||
{!this.props.collapsed ? this.renderPayload(payload) : ''}
|
{!this.props.collapsed ? this.renderPayload(payload) : ''}
|
||||||
</div>
|
</div>
|
|
@ -1,9 +1,31 @@
|
||||||
import React, { Component } from 'react';
|
import React, { PureComponent } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
|
import { Action } from 'redux';
|
||||||
|
import { PerformAction } from 'redux-devtools';
|
||||||
|
import { Base16Theme } from 'redux-devtools-themes';
|
||||||
import LogMonitorEntry from './LogMonitorEntry';
|
import LogMonitorEntry from './LogMonitorEntry';
|
||||||
import shouldPureComponentUpdate from 'react-pure-render/function';
|
|
||||||
|
|
||||||
export default class LogMonitorEntryList extends Component {
|
interface Props<S, A extends Action<unknown>> {
|
||||||
|
actionsById: { [actionId: number]: PerformAction<A> };
|
||||||
|
computedStates: { state: S; error?: string }[];
|
||||||
|
stagedActionIds: number[];
|
||||||
|
skippedActionIds: number[];
|
||||||
|
currentStateIndex: number;
|
||||||
|
consecutiveToggleStartId: number | null | undefined;
|
||||||
|
|
||||||
|
select: (state: S) => unknown;
|
||||||
|
onActionClick: (id: number) => void;
|
||||||
|
theme: Base16Theme;
|
||||||
|
expandActionRoot: boolean;
|
||||||
|
expandStateRoot: boolean;
|
||||||
|
markStateDiff: boolean;
|
||||||
|
onActionShiftClick: (id: number) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class LogMonitorEntryList<
|
||||||
|
S,
|
||||||
|
A extends Action<unknown>
|
||||||
|
> extends PureComponent<Props<S, A>> {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
actionsById: PropTypes.object,
|
actionsById: PropTypes.object,
|
||||||
computedStates: PropTypes.array,
|
computedStates: PropTypes.array,
|
||||||
|
@ -19,8 +41,6 @@ export default class LogMonitorEntryList extends Component {
|
||||||
expandStateRoot: PropTypes.bool,
|
expandStateRoot: PropTypes.bool,
|
||||||
};
|
};
|
||||||
|
|
||||||
shouldComponentUpdate = shouldPureComponentUpdate;
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const elements = [];
|
const elements = [];
|
||||||
const {
|
const {
|
|
@ -1,11 +0,0 @@
|
||||||
export const UPDATE_SCROLL_TOP =
|
|
||||||
'@@redux-devtools-log-monitor/UPDATE_SCROLL_TOP';
|
|
||||||
export function updateScrollTop(scrollTop) {
|
|
||||||
return { type: UPDATE_SCROLL_TOP, scrollTop };
|
|
||||||
}
|
|
||||||
|
|
||||||
export const START_CONSECUTIVE_TOGGLE =
|
|
||||||
'@@redux-devtools-log-monitor/START_CONSECUTIVE_TOGGLE';
|
|
||||||
export function startConsecutiveToggle(id) {
|
|
||||||
return { type: START_CONSECUTIVE_TOGGLE, id };
|
|
||||||
}
|
|
25
packages/redux-devtools-log-monitor/src/actions.ts
Normal file
25
packages/redux-devtools-log-monitor/src/actions.ts
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
export const UPDATE_SCROLL_TOP =
|
||||||
|
'@@redux-devtools-log-monitor/UPDATE_SCROLL_TOP';
|
||||||
|
interface UpdateScrollTopAction {
|
||||||
|
type: typeof UPDATE_SCROLL_TOP;
|
||||||
|
scrollTop: number;
|
||||||
|
}
|
||||||
|
export function updateScrollTop(scrollTop: number): UpdateScrollTopAction {
|
||||||
|
return { type: UPDATE_SCROLL_TOP, scrollTop };
|
||||||
|
}
|
||||||
|
|
||||||
|
export const START_CONSECUTIVE_TOGGLE =
|
||||||
|
'@@redux-devtools-log-monitor/START_CONSECUTIVE_TOGGLE';
|
||||||
|
interface StartConsecutiveToggleAction {
|
||||||
|
type: typeof START_CONSECUTIVE_TOGGLE;
|
||||||
|
id: number | null;
|
||||||
|
}
|
||||||
|
export function startConsecutiveToggle(
|
||||||
|
id: number | null
|
||||||
|
): StartConsecutiveToggleAction {
|
||||||
|
return { type: START_CONSECUTIVE_TOGGLE, id };
|
||||||
|
}
|
||||||
|
|
||||||
|
export type LogMonitorAction =
|
||||||
|
| UpdateScrollTopAction
|
||||||
|
| StartConsecutiveToggleAction;
|
|
@ -1,9 +1,9 @@
|
||||||
export default function (hexColor, lightness) {
|
export default function (hexColor: string, lightness: number) {
|
||||||
let hex = String(hexColor).replace(/[^0-9a-f]/gi, '');
|
let hex = String(hexColor).replace(/[^0-9a-f]/gi, '');
|
||||||
if (hex.length < 6) {
|
if (hex.length < 6) {
|
||||||
hex = hex.replace(/(.)/g, '$1$1');
|
hex = hex.replace(/(.)/g, '$1$1');
|
||||||
}
|
}
|
||||||
let lum = lightness || 0;
|
const lum = lightness || 0;
|
||||||
|
|
||||||
let rgb = '#';
|
let rgb = '#';
|
||||||
let c;
|
let c;
|
|
@ -1 +0,0 @@
|
||||||
export default from './LogMonitor';
|
|
2
packages/redux-devtools-log-monitor/src/index.ts
Normal file
2
packages/redux-devtools-log-monitor/src/index.ts
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
import LogMonitor from './LogMonitor';
|
||||||
|
export default LogMonitor;
|
|
@ -1,24 +0,0 @@
|
||||||
import { UPDATE_SCROLL_TOP, START_CONSECUTIVE_TOGGLE } from './actions';
|
|
||||||
|
|
||||||
function initialScrollTop(props, state = 0, action) {
|
|
||||||
if (!props.preserveScrollTop) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return action.type === UPDATE_SCROLL_TOP ? action.scrollTop : state;
|
|
||||||
}
|
|
||||||
|
|
||||||
function startConsecutiveToggle(props, state, action) {
|
|
||||||
return action.type === START_CONSECUTIVE_TOGGLE ? action.id : state;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function reducer(props, state = {}, action) {
|
|
||||||
return {
|
|
||||||
initialScrollTop: initialScrollTop(props, state.initialScrollTop, action),
|
|
||||||
consecutiveToggleStartId: startConsecutiveToggle(
|
|
||||||
props,
|
|
||||||
state.consecutiveToggleStartId,
|
|
||||||
action
|
|
||||||
),
|
|
||||||
};
|
|
||||||
}
|
|
47
packages/redux-devtools-log-monitor/src/reducers.ts
Normal file
47
packages/redux-devtools-log-monitor/src/reducers.ts
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
import { Action } from 'redux';
|
||||||
|
import {
|
||||||
|
UPDATE_SCROLL_TOP,
|
||||||
|
START_CONSECUTIVE_TOGGLE,
|
||||||
|
LogMonitorAction,
|
||||||
|
} from './actions';
|
||||||
|
import { LogMonitorProps } from './LogMonitor';
|
||||||
|
|
||||||
|
function initialScrollTop<S, A extends Action<unknown>>(
|
||||||
|
props: LogMonitorProps<S, A>,
|
||||||
|
state = 0,
|
||||||
|
action: LogMonitorAction
|
||||||
|
) {
|
||||||
|
if (!props.preserveScrollTop) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return action.type === UPDATE_SCROLL_TOP ? action.scrollTop : state;
|
||||||
|
}
|
||||||
|
|
||||||
|
function startConsecutiveToggle<S, A extends Action<unknown>>(
|
||||||
|
props: LogMonitorProps<S, A>,
|
||||||
|
state: number | null | undefined,
|
||||||
|
action: LogMonitorAction
|
||||||
|
) {
|
||||||
|
return action.type === START_CONSECUTIVE_TOGGLE ? action.id : state;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface LogMonitorState {
|
||||||
|
initialScrollTop: number;
|
||||||
|
consecutiveToggleStartId: number | null | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function reducer<S, A extends Action<unknown>>(
|
||||||
|
props: LogMonitorProps<S, A>,
|
||||||
|
state: Partial<LogMonitorState> = {},
|
||||||
|
action: LogMonitorAction
|
||||||
|
): LogMonitorState {
|
||||||
|
return {
|
||||||
|
initialScrollTop: initialScrollTop(props, state.initialScrollTop, action),
|
||||||
|
consecutiveToggleStartId: startConsecutiveToggle(
|
||||||
|
props,
|
||||||
|
state.consecutiveToggleStartId,
|
||||||
|
action
|
||||||
|
),
|
||||||
|
};
|
||||||
|
}
|
7
packages/redux-devtools-log-monitor/tsconfig.json
Normal file
7
packages/redux-devtools-log-monitor/tsconfig.json
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
{
|
||||||
|
"extends": "../../tsconfig.react.base.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "lib"
|
||||||
|
},
|
||||||
|
"include": ["src"]
|
||||||
|
}
|
|
@ -3045,7 +3045,7 @@
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/types" "^7.3.0"
|
"@babel/types" "^7.3.0"
|
||||||
|
|
||||||
"@types/base16@^1.0.2":
|
"@types/base16@*", "@types/base16@^1.0.2":
|
||||||
version "1.0.2"
|
version "1.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/@types/base16/-/base16-1.0.2.tgz#eb3a07db52309bfefb9ba010dfdb3c0784971f65"
|
resolved "https://registry.yarnpkg.com/@types/base16/-/base16-1.0.2.tgz#eb3a07db52309bfefb9ba010dfdb3c0784971f65"
|
||||||
integrity sha512-oYO/U4VD1DavwrKuCSQWdLG+5K22SLPem2OQaHmFcQuwHoVeGC+JGVRji2MUqZUAIQZHEonOeVfAX09hYiLsdg==
|
integrity sha512-oYO/U4VD1DavwrKuCSQWdLG+5K22SLPem2OQaHmFcQuwHoVeGC+JGVRji2MUqZUAIQZHEonOeVfAX09hYiLsdg==
|
||||||
|
@ -3340,6 +3340,13 @@
|
||||||
"@types/prop-types" "*"
|
"@types/prop-types" "*"
|
||||||
csstype "^3.0.2"
|
csstype "^3.0.2"
|
||||||
|
|
||||||
|
"@types/redux-devtools-themes@^1.0.0":
|
||||||
|
version "1.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/redux-devtools-themes/-/redux-devtools-themes-1.0.0.tgz#4d22d3e8be499fc7eec220e020b0640d4bfb17bd"
|
||||||
|
integrity sha512-ul3x0MYM5Nzj57Fh9wINyHFne8vZL04RC4nWAUWLYcL105vHoa/oJyopuKOrQmqVmhqmDiL4c9FfLbUmIB7TWQ==
|
||||||
|
dependencies:
|
||||||
|
"@types/base16" "*"
|
||||||
|
|
||||||
"@types/serve-static@*":
|
"@types/serve-static@*":
|
||||||
version "1.13.5"
|
version "1.13.5"
|
||||||
resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.13.5.tgz#3d25d941a18415d3ab092def846e135a08bbcf53"
|
resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.13.5.tgz#3d25d941a18415d3ab092def846e135a08bbcf53"
|
||||||
|
|
Loading…
Reference in New Issue
Block a user