UNPKG

4.55 kBJavaScriptView Raw
1import React, { Component } from 'react';
2import PropTypes from 'prop-types';
3import JSONTree from 'react-json-tree';
4import LogMonitorEntryAction from './LogMonitorEntryAction';
5import shouldPureComponentUpdate from 'react-pure-render/function';
6
7const styles = {
8 entry: {
9 display: 'block',
10 WebkitUserSelect: 'none'
11 },
12
13 root: {
14 marginLeft: 0
15 }
16};
17
18const getDeepItem = (data, path) =>
19 path.reduce((obj, key) => obj && obj[key], data);
20const dataIsEqual = (data, previousData, keyPath) => {
21 const path = [...keyPath].reverse().slice(1);
22
23 return getDeepItem(data, path) === getDeepItem(previousData, path);
24};
25
26export default class LogMonitorEntry extends Component {
27 static propTypes = {
28 state: PropTypes.object.isRequired,
29 action: PropTypes.object.isRequired,
30 actionId: PropTypes.number.isRequired,
31 select: PropTypes.func.isRequired,
32 inFuture: PropTypes.bool,
33 error: PropTypes.string,
34 onActionClick: PropTypes.func.isRequired,
35 onActionShiftClick: PropTypes.func.isRequired,
36 collapsed: PropTypes.bool,
37 selected: PropTypes.bool,
38 expandActionRoot: PropTypes.bool,
39 expandStateRoot: PropTypes.bool
40 };
41
42 shouldComponentUpdate = shouldPureComponentUpdate;
43
44 constructor(props) {
45 super(props);
46 this.handleActionClick = this.handleActionClick.bind(this);
47 this.shouldExpandNode = this.shouldExpandNode.bind(this);
48 }
49
50 printState(state, error) {
51 let errorText = error;
52 if (!errorText) {
53 try {
54 const data = this.props.select(state);
55 let theme;
56
57 if (this.props.markStateDiff) {
58 const previousData =
59 typeof this.props.previousState !== 'undefined'
60 ? this.props.select(this.props.previousState)
61 : undefined;
62 const getValueStyle = ({ style }, nodeType, keyPath) => ({
63 style: {
64 ...style,
65 backgroundColor: dataIsEqual(data, previousData, keyPath)
66 ? 'transparent'
67 : this.props.theme.base01
68 }
69 });
70 const getNestedNodeStyle = ({ style }, keyPath) => ({
71 style: {
72 ...style,
73 ...(keyPath.length > 1 ? {} : styles.root)
74 }
75 });
76 theme = {
77 extend: this.props.theme,
78 tree: styles.tree,
79 value: getValueStyle,
80 nestedNode: getNestedNodeStyle
81 };
82 } else {
83 theme = this.props.theme;
84 }
85
86 return (
87 <JSONTree
88 theme={theme}
89 data={data}
90 invertTheme={false}
91 keyPath={['state']}
92 shouldExpandNode={this.shouldExpandNode}
93 />
94 );
95 } catch (err) {
96 errorText = 'Error selecting state.';
97 }
98 }
99
100 return (
101 <div
102 style={{
103 color: this.props.theme.base08,
104 paddingTop: 20,
105 paddingLeft: 30,
106 paddingRight: 30,
107 paddingBottom: 35
108 }}
109 >
110 {errorText}
111 </div>
112 );
113 }
114
115 handleActionClick(e) {
116 const { actionId, onActionClick, onActionShiftClick } = this.props;
117 if (actionId > 0) {
118 if (e.shiftKey) {
119 onActionShiftClick(actionId);
120 } else {
121 onActionClick(actionId);
122 }
123 }
124 }
125
126 shouldExpandNode(keyName, data, level) {
127 return this.props.expandStateRoot && level === 0;
128 }
129
130 render() {
131 const {
132 actionId,
133 error,
134 action,
135 state,
136 collapsed,
137 selected,
138 inFuture
139 } = this.props;
140 const styleEntry = {
141 opacity: collapsed ? 0.5 : 1,
142 cursor: actionId > 0 ? 'pointer' : 'default'
143 };
144
145 return (
146 <div
147 style={{
148 opacity: selected ? 0.4 : inFuture ? 0.6 : 1, // eslint-disable-line no-nested-ternary
149 textDecoration: collapsed ? 'line-through' : 'none',
150 color: this.props.theme.base06
151 }}
152 >
153 <LogMonitorEntryAction
154 theme={this.props.theme}
155 collapsed={collapsed}
156 action={action}
157 expandActionRoot={this.props.expandActionRoot}
158 onClick={this.handleActionClick}
159 style={{ ...styles.entry, ...styleEntry }}
160 />
161 {!collapsed && (
162 <div style={{ paddingLeft: 16 }}>{this.printState(state, error)}</div>
163 )}
164 </div>
165 );
166 }
167}