Add redux-devtools-chart-monitor package (#555)

* Add redux-devtools-chart-monitor

* Changes

* ref
This commit is contained in:
Nathan Bierema 2020-08-04 13:13:22 -07:00 committed by GitHub
parent fead81ca9e
commit 681b11b500
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 416 additions and 13 deletions

View File

@ -1 +0,0 @@
workspaces-experimental true

View File

@ -0,0 +1,4 @@
{
"presets": ["@babel/preset-env", "@babel/preset-react"],
"plugins": ["@babel/plugin-proposal-class-properties", "@babel/plugin-proposal-export-default-from"]
}

View File

@ -0,0 +1,74 @@
Redux DevTools Chart Monitor
=========================
A chart monitor for [Redux DevTools](https://github.com/gaearon/redux-devtools). Created by [@romseguy](https://github.com/romseguy) and merged from [`reduxjs/redux-devtools-chart-monitor`](https://github.com/reduxjs/redux-devtools-chart-monitor).
It shows a real-time view of the store aka the current state of the app.
:rocket: Now with immutable-js support.
[Demo](http://romseguy.github.io/redux-store-visualizer/) [(Source)](https://github.com/romseguy/redux-store-visualizer)
![Chart Monitor](https://camo.githubusercontent.com/19aebaeba929e97f97225115c49dc994299cb76e/687474703a2f2f692e696d6775722e636f6d2f4d53677655366c2e676966)
### Installation
```
yarn add --dev redux-devtools-chart-monitor
```
### Usage
You can use `ChartMonitor` as the only monitor in your app:
##### `containers/DevTools.js`
```js
import React from 'react';
import { createDevTools } from 'redux-devtools';
import ChartMonitor from 'redux-devtools-chart-monitor';
export default createDevTools(
<ChartMonitor />
);
```
Then you can render `<DevTools>` to any place inside app or even into a separate popup window.
Alternatively, you can use it together with [`DockMonitor`](https://github.com/gaearon/redux-devtools-dock-monitor) to make it dockable.
Consult the [`DockMonitor` README](https://github.com/gaearon/redux-devtools-dock-monitor) for details of this approach.
[Read how to start using Redux DevTools.](https://github.com/reduxjs/redux-devtools)
### Features
### Props
#### ChartMonitor props
You can read the React component [propTypes](https://github.com/reduxjs/redux-devtools/blob/master/packages/redux-devtools-chart-monitor/src/Chart.js#L11) in addition to the details below:
Name | Description
------------- | -------------
`defaultIsVisible` | By default, set to `true`.
`transitionDuration` | By default, set to `750`, in milliseconds.
`heightBetweenNodesCoeff` | By default, set to `1`.
`widthBetweenNodesCoeff` | By default, set to `1.3`.
`isSorted` | By default, set to `false`.
`style` | {<br>&nbsp;&nbsp;width: '100%', height: '100%', // i.e fullscreen for [`DockMonitor`](https://github.com/gaearon/redux-devtools-dock-monitor)<br>&nbsp;&nbsp;text: {<br>&nbsp;&nbsp;&nbsp;&nbsp;colors: {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;'default': `theme.base0D`,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;hover: `theme.base06`<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;},<br>&nbsp;&nbsp;node: {<br>&nbsp;&nbsp;&nbsp;&nbsp;colors: {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;'default': `theme.base0B`,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;collapsed: `theme.base0B`,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;parent: `theme.base0E`<br>&nbsp;&nbsp;&nbsp;&nbsp;},<br>&nbsp;&nbsp;&nbsp;&nbsp;radius: 7<br>&nbsp;&nbsp;}<br>}
`onClickText` | Function called with a reference to the clicked node as first argument when clicking on the text next to a node.
`tooltipOptions` | {<br>&nbsp;&nbsp;disabled: false,<br>&nbsp;&nbsp;indentationSize: 2,<br>&nbsp;&nbsp;style: {<br>&nbsp;&nbsp;&nbsp;&nbsp;'background-color': `theme.base06`,<br>&nbsp;&nbsp;&nbsp;&nbsp;'opacity': '0.7',<br>&nbsp;&nbsp;&nbsp;&nbsp;'border-radius': '5px',<br>&nbsp;&nbsp;&nbsp;&nbsp;'padding': '5px'<br>&nbsp;&nbsp;}<br>}<br>[More info](https://github.com/reduxjs/redux-devtools/tree/master/packages/d3tooltip#api).
#### Redux DevTools props
Name | Description
------------- | -------------
`theme` | Either a string referring to one of the themes provided by [redux-devtools-themes](https://github.com/gaearon/redux-devtools-themes) (feel free to contribute!) or a custom object of the same format. Optional. By default, set to [`'nicinabox'`](https://github.com/gaearon/redux-devtools-themes/blob/master/src/nicinabox.js).
`invertTheme` | Boolean value that will invert the colors of the selected theme. Optional. By default, set to `false`
`select` | A function that selects the slice of the state for DevTools to show. For example, `state => state.thePart.iCare.about`. Optional. By default, set to `state => state`.
### License
MIT

View File

@ -0,0 +1,55 @@
{
"name": "redux-devtools-chart-monitor",
"version": "1.7.0",
"description": "Chart monitor for Redux DevTools",
"main": "lib/index.js",
"scripts": {
"clean": "rimraf lib",
"build": "babel src --out-dir lib",
"prepare": "npm run build",
"prepublishOnly": "npm run lint && npm run clean && npm run build"
},
"files": [
"lib",
"src"
],
"repository": {
"type": "git",
"url": "https://github.com/reduxjs/redux-devtools.git"
},
"keywords": [
"redux",
"devtools",
"flux",
"react",
"chart"
],
"author": "romseguy",
"license": "MIT",
"bugs": {
"url": "https://github.com/reduxjs/redux-devtools/issues"
},
"homepage": "https://github.com/reduxjs/redux-devtools",
"devDependencies": {
"@babel/cli": "^7.10.5",
"@babel/core": "^7.11.0",
"@babel/plugin-proposal-class-properties": "^7.10.4",
"@babel/plugin-proposal-export-default-from": "^7.10.4",
"@babel/preset-env": "^7.11.0",
"@babel/preset-react": "^7.10.4",
"babel-loader": "^8.1.0",
"rimraf": "^2.7.1"
},
"peerDependencies": {
"react": "^16.3.0",
"react-dom": "^16.3.0",
"redux-devtools": "^3.0.0"
},
"dependencies": {
"d3-state-visualizer": "^1.3.2",
"deepmerge": "^0.2.10",
"prop-types": "^15.7.2",
"react-pure-render": "^1.0.2",
"redux-devtools-themes": "^1.0.0"
}
}

View File

@ -0,0 +1,86 @@
import React, { Component, createRef } from 'react';
import PropTypes from 'prop-types';
import { tree } from 'd3-state-visualizer';
const wrapperStyle = {
width: '100%',
height: '100%'
};
class Chart extends Component {
static propTypes = {
state: PropTypes.object,
rootKeyName: PropTypes.string,
pushMethod: PropTypes.oneOf(['push', 'unshift']),
tree: PropTypes.shape({
name: PropTypes.string,
children: PropTypes.array
}),
id: PropTypes.string,
style: PropTypes.shape({
node: PropTypes.shape({
colors: PropTypes.shape({
'default': PropTypes.string,
parent: PropTypes.string,
collapsed: PropTypes.string
}),
radius: PropTypes.number
}),
text: PropTypes.shape({
colors: PropTypes.shape({
'default': PropTypes.string,
hover: PropTypes.string
})
}),
link: PropTypes.object
}),
size: PropTypes.number,
aspectRatio: PropTypes.number,
margin: PropTypes.shape({
top: PropTypes.number,
right: PropTypes.number,
bottom: PropTypes.number,
left: PropTypes.number
}),
isSorted: PropTypes.bool,
heightBetweenNodesCoeff: PropTypes.number,
widthBetweenNodesCoeff: PropTypes.number,
transitionDuration: PropTypes.number,
onClickText: PropTypes.func,
tooltipOptions: PropTypes.shape({
disabled: PropTypes.bool,
left: PropTypes.number,
top: PropTypes.number,
offset: PropTypes.shape({
left: PropTypes.number,
top: PropTypes.number
}),
indentationSize: PropTypes.number,
style: PropTypes.object
})
};
divRef = createRef();
componentDidMount() {
const { select, state, defaultIsVisible } = this.props;
this.renderChart = tree(this.divRef.current, this.props);
if (defaultIsVisible) {
this.renderChart(select(state));
}
}
UNSAFE_componentWillReceiveProps(nextProps) {
const { state, select, monitorState } = nextProps;
if (monitorState.isVisible !== false) {
this.renderChart(select(state));
}
}
render() {
return <div style={wrapperStyle} ref={this.divRef}/>;
}
}
export default Chart;

View File

@ -0,0 +1,175 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import shouldPureComponentUpdate from 'react-pure-render/function';
import * as themes from 'redux-devtools-themes';
import { ActionCreators } from 'redux-devtools';
import deepmerge from 'deepmerge';
import reducer from './reducers';
import Chart from './Chart';
const { reset, rollback, commit, sweep, toggleAction } = ActionCreators;
const styles = {
container: {
fontFamily: 'monaco, Consolas, Lucida Console, monospace',
position: 'relative',
overflowY: 'hidden',
width: '100%',
height: '100%',
minWidth: 300
}
};
function invertColors(theme) {
return {
...theme,
base00: theme.base07,
base01: theme.base06,
base02: theme.base05,
base03: theme.base04,
base04: theme.base03,
base05: theme.base02,
base06: theme.base01,
base07: theme.base00
};
}
class ChartMonitor extends Component {
static update = reducer;
static propTypes = {
dispatch: PropTypes.func,
computedStates: PropTypes.array,
currentStateIndex: PropTypes.number,
actionsById: PropTypes.object,
stagedActionIds: PropTypes.array,
skippedActionIds: PropTypes.array,
monitorState: PropTypes.shape({
initialScrollTop: PropTypes.number
}),
preserveScrollTop: PropTypes.bool,
select: PropTypes.func.isRequired,
theme: PropTypes.oneOfType([
PropTypes.object,
PropTypes.string
]),
invertTheme: PropTypes.bool
};
static defaultProps = {
select: (state) => state,
theme: 'nicinabox',
preserveScrollTop: true,
invertTheme: false
};
shouldComponentUpdate = shouldPureComponentUpdate;
constructor(props) {
super(props);
this.handleToggleAction = this.handleToggleAction.bind(this);
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());
}
handleSweep() {
this.props.dispatch(sweep());
}
handleCommit() {
this.props.dispatch(commit());
}
handleToggleAction(id) {
this.props.dispatch(toggleAction(id));
}
handleReset() {
this.props.dispatch(reset());
}
getTheme() {
let { theme, invertTheme } = this.props;
if (typeof theme !== 'string') {
return invertTheme ? invertColors(theme) : theme;
}
if (typeof themes[theme] !== 'undefined') {
return invertTheme ? invertColors(themes[theme]) : themes[theme];
}
// eslint-disable-next-line no-console
console.warn('DevTools theme ' + theme + ' not found, defaulting to nicinabox');
return invertTheme ? invertColors(themes.nicinabox) : themes.nicinabox;
}
getChartStyle() {
const theme = this.getTheme();
return {
width: '100%',
height: '100%',
node: {
colors: {
'default': theme.base0B,
collapsed: theme.base0B,
parent: theme.base0E
},
radius: 7
},
text: {
colors: {
'default': theme.base0D,
hover: theme.base06
}
}
};
}
getChartOptions(props = this.props) {
const { computedStates } = props;
const theme = this.getTheme();
const tooltipOptions = {
disabled: false,
offset: {left: 30, top: 10},
indentationSize: 2,
style: {
'background-color': theme.base06,
'opacity': '0.7',
'border-radius': '5px',
'padding': '5px'
}
};
const defaultOptions = {
state: computedStates.length ? computedStates[props.currentStateIndex].state : null,
isSorted: false,
heightBetweenNodesCoeff: 1,
widthBetweenNodesCoeff: 1.3,
tooltipOptions,
style: this.getChartStyle()
};
return deepmerge(defaultOptions, props);
}
render() {
const theme = this.getTheme();
return (
<div style={{...styles.container, backgroundColor: theme.base07}}>
<Chart {...this.getChartOptions()} />
</div>
);
}
}
export default ChartMonitor;

View File

@ -0,0 +1 @@
export const TOGGLE_VISIBILITY = '@@redux-devtools-log-monitor/TOGGLE_VISIBILITY';

View File

@ -0,0 +1 @@
export default from './ChartMonitor';

View File

@ -0,0 +1,19 @@
import { TOGGLE_VISIBILITY } from './actions';
function toggleVisibility(props, state = props.defaultIsVisible, action) {
if (action.type === TOGGLE_VISIBILITY) {
return !state;
}
if (props.defaultIsVisible !== undefined) {
return props.defaultIsVisible;
}
return true;
}
export default function reducer(props, state = {}, action) {
return {
isVisible: toggleVisibility(props, state.isVisible, action)
};
}

View File

@ -5860,7 +5860,7 @@ cyclist@^1.0.1:
resolved "https://registry.yarnpkg.com/cyclist/-/cyclist-1.0.1.tgz#596e9698fd0c80e12038c2b82d6eb1b35b6224d9"
integrity sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk=
d3-state-visualizer@^1.3.1, d3-state-visualizer@^1.3.2:
d3-state-visualizer@^1.3.2:
version "1.3.2"
resolved "https://registry.yarnpkg.com/d3-state-visualizer/-/d3-state-visualizer-1.3.2.tgz#8e3ac418aa7ee7e3f46025309f9d1c215ee385eb"
integrity sha512-XgTRC6FXeoTt8l79cc2f3Zaah+K7DUQb3GL0zfbvoIi7zWWHV4l7OfuX9/JxxvwilKApMZwHMBJ7cJ2yWAc5IQ==
@ -13734,17 +13734,6 @@ redent@^3.0.0:
indent-string "^4.0.0"
strip-indent "^3.0.0"
redux-devtools-chart-monitor@^1.7.0:
version "1.7.0"
resolved "https://registry.yarnpkg.com/redux-devtools-chart-monitor/-/redux-devtools-chart-monitor-1.7.0.tgz#bf6356f480142e3576f5bbbeead433a1598c5e7f"
integrity sha512-1knxXASbo7ukukyf1rGNnME7gOgKY1XVZ4hoSzUjY6QFIC8iEneivXznCupxjfX5TDXLjZgQrFBrbGano1WK7g==
dependencies:
d3-state-visualizer "^1.3.1"
deepmerge "^0.2.10"
prop-types "^15.6.0"
react-pure-render "^1.0.2"
redux-devtools-themes "^1.0.0"
redux-devtools-dock-monitor@^1.1.3:
version "1.1.3"
resolved "https://registry.yarnpkg.com/redux-devtools-dock-monitor/-/redux-devtools-dock-monitor-1.1.3.tgz#1205e823c82536570aac8551a1c4b70972cba6aa"