mirror of
https://github.com/morten-olsen/react-native-debug-console.git
synced 2026-02-08 00:36:26 +01:00
Lots of UI updates
This commit is contained in:
57
README.md
Normal file
57
README.md
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
# React Native Debug Console
|
||||||
|
|
||||||
|
A network and console debug component and modal for `react native` purely in JavaScript
|
||||||
|
|
||||||
|
[[demo]](https://expo.io/@mortenolsen/demo)
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
```
|
||||||
|
npm install react-native-debug-console
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
It comes as a ready to use modal, as well as a standalone component
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
import {
|
||||||
|
DevToolModal,
|
||||||
|
log,
|
||||||
|
network,
|
||||||
|
show,
|
||||||
|
} from 'react-native-debug-console';
|
||||||
|
|
||||||
|
network.attach();
|
||||||
|
log.attach();
|
||||||
|
|
||||||
|
const App = () => (
|
||||||
|
<View>
|
||||||
|
<MyOtherContent />
|
||||||
|
<DevToolModal />
|
||||||
|
<Button
|
||||||
|
onPress={show}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
import {
|
||||||
|
DevTool,
|
||||||
|
log,
|
||||||
|
network,
|
||||||
|
} from 'react-native-debug-console';
|
||||||
|
|
||||||
|
network.attach();
|
||||||
|
log.attach();
|
||||||
|
|
||||||
|
const App = () => (
|
||||||
|
<View>
|
||||||
|
<MyOtherContent />
|
||||||
|
<DevTool />
|
||||||
|
</View>
|
||||||
|
)
|
||||||
|
```
|
||||||
37
demo/App.js
37
demo/App.js
@@ -19,22 +19,35 @@ network.attach();
|
|||||||
log.attach();
|
log.attach();
|
||||||
|
|
||||||
console.log('fooo');
|
console.log('fooo');
|
||||||
|
let xhr = new XMLHttpRequest();
|
||||||
|
xhr.open('GET', 'https://google.com');
|
||||||
|
xhr.send();
|
||||||
|
xhr = new XMLHttpRequest();
|
||||||
|
xhr.open('GET', 'https://google.com/sdfsfsdfsfdf');
|
||||||
|
xhr.send();
|
||||||
|
|
||||||
|
const t = new Promise((resolve, reject) => {
|
||||||
|
setTimeout(() => {
|
||||||
|
throw new Error('everything is broken');
|
||||||
|
}, 1000);
|
||||||
|
});
|
||||||
|
|
||||||
export default class App extends React.Component {
|
export default class App extends React.Component {
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<SafeAreaView style={styles.container}>
|
<SafeAreaView style={styles.container}>
|
||||||
<KeyboardAvoidingView style={styles.wrapper} behavior="padding">
|
<KeyboardAvoidingView style={styles.wrapper} behavior="padding">
|
||||||
|
<View>
|
||||||
<Button
|
<Button
|
||||||
style={styles.button}
|
style={styles.button}
|
||||||
title="Console log"
|
title="console.log('hello')"
|
||||||
onPress={() => {
|
onPress={() => {
|
||||||
console.log('hello');
|
console.log('hello');
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<View style={{ height: 10 }} />
|
<View style={{ height: 10 }} />
|
||||||
<Button
|
<Button
|
||||||
title="GET XHR"
|
title="GET XHR (html)"
|
||||||
style={styles.button}
|
style={styles.button}
|
||||||
onPress={() => {
|
onPress={() => {
|
||||||
const xhr = new XMLHttpRequest();
|
const xhr = new XMLHttpRequest();
|
||||||
@@ -43,6 +56,17 @@ export default class App extends React.Component {
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<View style={{ height: 10 }} />
|
<View style={{ height: 10 }} />
|
||||||
|
<View style={{ height: 10 }} />
|
||||||
|
<Button
|
||||||
|
title="GET XHR (json)"
|
||||||
|
style={styles.button}
|
||||||
|
onPress={() => {
|
||||||
|
const xhr = new XMLHttpRequest();
|
||||||
|
xhr.open('GET', 'https://api.github.com');
|
||||||
|
xhr.send();
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<View style={{ height: 10 }} />
|
||||||
<Button
|
<Button
|
||||||
title="POST XHR"
|
title="POST XHR"
|
||||||
style={styles.button}
|
style={styles.button}
|
||||||
@@ -57,7 +81,7 @@ export default class App extends React.Component {
|
|||||||
/>
|
/>
|
||||||
<View style={{ height: 10 }} />
|
<View style={{ height: 10 }} />
|
||||||
<Button
|
<Button
|
||||||
title="Break"
|
title="Unhandled error"
|
||||||
style={styles.button}
|
style={styles.button}
|
||||||
onPress={() => {
|
onPress={() => {
|
||||||
const err = new Error('some error');
|
const err = new Error('some error');
|
||||||
@@ -66,16 +90,17 @@ export default class App extends React.Component {
|
|||||||
/>
|
/>
|
||||||
<View style={{ height: 30 }} />
|
<View style={{ height: 30 }} />
|
||||||
<Button
|
<Button
|
||||||
title="Show"
|
title="Show modal"
|
||||||
style={styles.button}
|
style={styles.button}
|
||||||
onPress={() => {
|
onPress={() => {
|
||||||
show();
|
show();
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<View style={{ flex: 1 }} />
|
<View style={{ height: 10 }} />
|
||||||
|
</View>
|
||||||
<DevTool
|
<DevTool
|
||||||
style={{
|
style={{
|
||||||
height: 300,
|
flex: 1,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<DevToolModal />
|
<DevToolModal />
|
||||||
|
|||||||
@@ -24,6 +24,7 @@
|
|||||||
"prop-types": "^15.6.2",
|
"prop-types": "^15.6.2",
|
||||||
"react": "16.3.1",
|
"react": "16.3.1",
|
||||||
"react-native": "~0.55.2",
|
"react-native": "~0.55.2",
|
||||||
"react-native-json-tree": "^1.2.0"
|
"react-native-json-tree": "^1.2.0",
|
||||||
|
"styled-components": "^3.4.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ module.exports = {
|
|||||||
'react-native',
|
'react-native',
|
||||||
'react',
|
'react',
|
||||||
'prop-types',
|
'prop-types',
|
||||||
|
'styled-components',
|
||||||
'react-native-json-tree',
|
'react-native-json-tree',
|
||||||
];
|
];
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1667,7 +1667,7 @@ base64-js@1.2.0:
|
|||||||
version "1.2.0"
|
version "1.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.2.0.tgz#a39992d723584811982be5e290bb6a53d86700f1"
|
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.2.0.tgz#a39992d723584811982be5e290bb6a53d86700f1"
|
||||||
|
|
||||||
base64-js@^1.1.2, base64-js@^1.2.0:
|
base64-js@^1.0.2, base64-js@^1.1.2, base64-js@^1.2.0:
|
||||||
version "1.3.0"
|
version "1.3.0"
|
||||||
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.3.0.tgz#cab1e6118f051095e58b5281aea8c1cd22bfc0e3"
|
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.3.0.tgz#cab1e6118f051095e58b5281aea8c1cd22bfc0e3"
|
||||||
|
|
||||||
@@ -1814,6 +1814,13 @@ buffer-from@^1.0.0:
|
|||||||
version "1.1.1"
|
version "1.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef"
|
resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef"
|
||||||
|
|
||||||
|
buffer@^5.0.3:
|
||||||
|
version "5.2.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.2.0.tgz#53cf98241100099e9eeae20ee6d51d21b16e541e"
|
||||||
|
dependencies:
|
||||||
|
base64-js "^1.0.2"
|
||||||
|
ieee754 "^1.1.4"
|
||||||
|
|
||||||
builtin-modules@^1.0.0:
|
builtin-modules@^1.0.0:
|
||||||
version "1.1.1"
|
version "1.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f"
|
resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f"
|
||||||
@@ -2210,6 +2217,18 @@ crypto-token@^1.0.1:
|
|||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/crypto-token/-/crypto-token-1.0.1.tgz#27c6482faf3b63c2f5da11577f8304346fe797a5"
|
resolved "https://registry.yarnpkg.com/crypto-token/-/crypto-token-1.0.1.tgz#27c6482faf3b63c2f5da11577f8304346fe797a5"
|
||||||
|
|
||||||
|
css-color-keywords@^1.0.0:
|
||||||
|
version "1.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/css-color-keywords/-/css-color-keywords-1.0.0.tgz#fea2616dc676b2962686b3af8dbdbe180b244e05"
|
||||||
|
|
||||||
|
css-to-react-native@^2.0.3:
|
||||||
|
version "2.2.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/css-to-react-native/-/css-to-react-native-2.2.1.tgz#7f3f4c95de65501b8720c87bf0caf1f39073b88e"
|
||||||
|
dependencies:
|
||||||
|
css-color-keywords "^1.0.0"
|
||||||
|
fbjs "^0.8.5"
|
||||||
|
postcss-value-parser "^3.3.0"
|
||||||
|
|
||||||
cssom@0.3.x, "cssom@>= 0.3.2 < 0.4.0":
|
cssom@0.3.x, "cssom@>= 0.3.2 < 0.4.0":
|
||||||
version "0.3.4"
|
version "0.3.4"
|
||||||
resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.3.4.tgz#8cd52e8a3acfd68d3aed38ee0a640177d2f9d797"
|
resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.3.4.tgz#8cd52e8a3acfd68d3aed38ee0a640177d2f9d797"
|
||||||
@@ -2771,7 +2790,7 @@ fbjs-scripts@^0.8.1:
|
|||||||
semver "^5.1.0"
|
semver "^5.1.0"
|
||||||
through2 "^2.0.0"
|
through2 "^2.0.0"
|
||||||
|
|
||||||
fbjs@^0.8.14, fbjs@^0.8.16, fbjs@^0.8.4, fbjs@^0.8.9:
|
fbjs@^0.8.14, fbjs@^0.8.16, fbjs@^0.8.4, fbjs@^0.8.5, fbjs@^0.8.9:
|
||||||
version "0.8.17"
|
version "0.8.17"
|
||||||
resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.17.tgz#c4d598ead6949112653d6588b01a5cdcd9f90fdd"
|
resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.17.tgz#c4d598ead6949112653d6588b01a5cdcd9f90fdd"
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -3325,6 +3344,10 @@ idx@^2.1.0:
|
|||||||
version "2.4.0"
|
version "2.4.0"
|
||||||
resolved "https://registry.yarnpkg.com/idx/-/idx-2.4.0.tgz#e89e6650c889a44bf889f79d47f40fe09b4eeaa3"
|
resolved "https://registry.yarnpkg.com/idx/-/idx-2.4.0.tgz#e89e6650c889a44bf889f79d47f40fe09b4eeaa3"
|
||||||
|
|
||||||
|
ieee754@^1.1.4:
|
||||||
|
version "1.1.12"
|
||||||
|
resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.12.tgz#50bf24e5b9c8bb98af4964c941cdb0918da7b60b"
|
||||||
|
|
||||||
ignore-walk@^3.0.1:
|
ignore-walk@^3.0.1:
|
||||||
version "3.0.1"
|
version "3.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-3.0.1.tgz#a83e62e7d272ac0e3b551aaa82831a19b69f82f8"
|
resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-3.0.1.tgz#a83e62e7d272ac0e3b551aaa82831a19b69f82f8"
|
||||||
@@ -5327,6 +5350,10 @@ posix-character-classes@^0.1.0:
|
|||||||
version "0.1.1"
|
version "0.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab"
|
resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab"
|
||||||
|
|
||||||
|
postcss-value-parser@^3.3.0:
|
||||||
|
version "3.3.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-3.3.0.tgz#87f38f9f18f774a4ab4c8a232f5c5ce8872a9d15"
|
||||||
|
|
||||||
pouchdb-collections@^1.0.1:
|
pouchdb-collections@^1.0.1:
|
||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/pouchdb-collections/-/pouchdb-collections-1.0.1.tgz#fe63a17da977611abef7cb8026cb1a9553fd8359"
|
resolved "https://registry.yarnpkg.com/pouchdb-collections/-/pouchdb-collections-1.0.1.tgz#fe63a17da977611abef7cb8026cb1a9553fd8359"
|
||||||
@@ -5400,7 +5427,7 @@ prop-types@15.5.8:
|
|||||||
dependencies:
|
dependencies:
|
||||||
fbjs "^0.8.9"
|
fbjs "^0.8.9"
|
||||||
|
|
||||||
prop-types@^15.5.10, prop-types@^15.5.8, prop-types@^15.6.0, prop-types@^15.6.2:
|
prop-types@^15.5.10, prop-types@^15.5.4, prop-types@^15.5.8, prop-types@^15.6.0, prop-types@^15.6.2:
|
||||||
version "15.6.2"
|
version "15.6.2"
|
||||||
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.6.2.tgz#05d5ca77b4453e985d60fc7ff8c859094a497102"
|
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.6.2.tgz#05d5ca77b4453e985d60fc7ff8c859094a497102"
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -6552,6 +6579,28 @@ strip-json-comments@~2.0.1:
|
|||||||
version "2.0.1"
|
version "2.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a"
|
resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a"
|
||||||
|
|
||||||
|
styled-components@^3.4.2:
|
||||||
|
version "3.4.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/styled-components/-/styled-components-3.4.2.tgz#8f518419932327e47fe9144824e3184b3e2da95d"
|
||||||
|
dependencies:
|
||||||
|
buffer "^5.0.3"
|
||||||
|
css-to-react-native "^2.0.3"
|
||||||
|
fbjs "^0.8.16"
|
||||||
|
hoist-non-react-statics "^2.5.0"
|
||||||
|
prop-types "^15.5.4"
|
||||||
|
react-is "^16.3.1"
|
||||||
|
stylis "^3.5.0"
|
||||||
|
stylis-rule-sheet "^0.0.10"
|
||||||
|
supports-color "^3.2.3"
|
||||||
|
|
||||||
|
stylis-rule-sheet@^0.0.10:
|
||||||
|
version "0.0.10"
|
||||||
|
resolved "https://registry.yarnpkg.com/stylis-rule-sheet/-/stylis-rule-sheet-0.0.10.tgz#44e64a2b076643f4b52e5ff71efc04d8c3c4a430"
|
||||||
|
|
||||||
|
stylis@^3.5.0:
|
||||||
|
version "3.5.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/stylis/-/stylis-3.5.3.tgz#99fdc46afba6af4deff570825994181a5e6ce546"
|
||||||
|
|
||||||
superagent-proxy@^1.0.2:
|
superagent-proxy@^1.0.2:
|
||||||
version "1.0.3"
|
version "1.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/superagent-proxy/-/superagent-proxy-1.0.3.tgz#acfa776672f11c24a90ad575e855def8be44f741"
|
resolved "https://registry.yarnpkg.com/superagent-proxy/-/superagent-proxy-1.0.3.tgz#acfa776672f11c24a90ad575e855def8be44f741"
|
||||||
@@ -6582,7 +6631,7 @@ supports-color@^2.0.0:
|
|||||||
version "2.0.0"
|
version "2.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7"
|
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7"
|
||||||
|
|
||||||
supports-color@^3.1.2:
|
supports-color@^3.1.2, supports-color@^3.2.3:
|
||||||
version "3.2.3"
|
version "3.2.3"
|
||||||
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-3.2.3.tgz#65ac0504b3954171d8a64946b2ae3cbb8a5f54f6"
|
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-3.2.3.tgz#65ac0504b3954171d8a64946b2ae3cbb8a5f54f6"
|
||||||
dependencies:
|
dependencies:
|
||||||
|
|||||||
BIN
docs/assets/screen1.PNG
Normal file
BIN
docs/assets/screen1.PNG
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 604 KiB |
@@ -17,6 +17,7 @@ const styles = StyleSheet.create({
|
|||||||
},
|
},
|
||||||
input: {
|
input: {
|
||||||
flex: 1,
|
flex: 1,
|
||||||
|
fontFamily: 'Menlo-Regular',
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -39,13 +40,13 @@ const Input = ({
|
|||||||
onPress={() => {
|
onPress={() => {
|
||||||
const fn = new Function(text);
|
const fn = new Function(text);
|
||||||
try {
|
try {
|
||||||
const response = eval(text);
|
const response = fn();
|
||||||
log.info(response);
|
log.info([response]);
|
||||||
setState({
|
setState({
|
||||||
text: '',
|
text: '',
|
||||||
});
|
});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
log.error(err);
|
log.error([err]);
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -1,59 +1,127 @@
|
|||||||
import React from 'react';
|
import React, { Fragment } from 'react';
|
||||||
|
import styled from 'styled-components/native';
|
||||||
|
import JSONTree from 'react-native-json-tree';
|
||||||
import {
|
import {
|
||||||
StyleSheet,
|
ScrollView
|
||||||
ScrollView,
|
|
||||||
View,
|
|
||||||
Text,
|
|
||||||
} from 'react-native';
|
} from 'react-native';
|
||||||
import JSONTree from 'react-native-json-tree'
|
import {
|
||||||
import prune from './tools';
|
Body,
|
||||||
|
Emphasis,
|
||||||
|
Fixed,
|
||||||
|
} from '../../base/text';
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const theme = {
|
||||||
container: {
|
scheme: 'bright',
|
||||||
flex: 1,
|
author: 'chris kempson (http://chriskempson.com)',
|
||||||
},
|
base00: '#000000',
|
||||||
});
|
base01: '#303030',
|
||||||
|
base02: '#505050',
|
||||||
const getCircularReplacer = () => {
|
base03: '#b0b0b0',
|
||||||
const seen = [];
|
base04: '#d0d0d0',
|
||||||
return (key, val) => {
|
base05: '#e0e0e0',
|
||||||
if (val != null && typeof val == "object") {
|
base06: '#f5f5f5',
|
||||||
if (seen.indexOf(val) >= 0) {
|
base07: '#ffffff',
|
||||||
return;
|
base08: '#fb0120',
|
||||||
}
|
base09: '#fc6d24',
|
||||||
seen.push(val);
|
base0A: '#fda331',
|
||||||
}
|
base0B: '#a1c659',
|
||||||
return val;
|
base0C: '#76c7b7',
|
||||||
}
|
base0D: '#6fb3d2',
|
||||||
|
base0E: '#d381c3',
|
||||||
|
base0F: '#be643c'
|
||||||
};
|
};
|
||||||
|
|
||||||
const formatData = (data) => {
|
const Wrapper = styled.View``;
|
||||||
|
const List = styled.View`
|
||||||
|
padding-left: 10px;
|
||||||
|
border-left-width: 10px;
|
||||||
|
border-color: ${props => props.color || 'black' }
|
||||||
|
`;
|
||||||
|
const Row = styled.View`
|
||||||
|
margin: 10px;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const getColor = (type) => {
|
||||||
|
if (type === 'error') {
|
||||||
|
return 'red';
|
||||||
|
}
|
||||||
|
if (type === 'warn') {
|
||||||
|
return 'yellow';
|
||||||
|
}
|
||||||
|
if (type === 'verbose') {
|
||||||
|
return 'gray';
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const formatData = (data, options) => {
|
||||||
|
const {
|
||||||
|
includeStackTrace
|
||||||
|
} = options;
|
||||||
if (typeof data === 'undefined') {
|
if (typeof data === 'undefined') {
|
||||||
return <Text>undefined</Text>;
|
return <Fixed>undefined</Fixed>;
|
||||||
}
|
}
|
||||||
if (data instanceof Error) {
|
if (data instanceof Error) {
|
||||||
return <Text>Error {data.toString()} {data.stack.toString()}</Text>;
|
if (includeStackTrace) {
|
||||||
|
return (
|
||||||
|
<JSONTree
|
||||||
|
theme={theme}
|
||||||
|
data={{
|
||||||
|
message: data.toString(),
|
||||||
|
stackTrace: data.stack.toString(),
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return <Fixed>{data.toString()}</Fixed>;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (typeof data === 'object') {
|
if (typeof data === 'object') {
|
||||||
return <JSONTree data={prune(data, null, ' ')} />
|
return <JSONTree data={data} />
|
||||||
}
|
}
|
||||||
return <Text>{data.toString()}</Text>;
|
return <Fixed>{data.toString()}</Fixed>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const OutputList = ({
|
||||||
|
items,
|
||||||
|
color,
|
||||||
|
includeStackTrace,
|
||||||
|
}) => (
|
||||||
|
<List color={color}>
|
||||||
|
{items.map((data, i) => (
|
||||||
|
<Fragment key={i}>
|
||||||
|
{formatData(data, {
|
||||||
|
includeStackTrace,
|
||||||
|
})}
|
||||||
|
</Fragment>
|
||||||
|
))}
|
||||||
|
</List>
|
||||||
|
)
|
||||||
|
|
||||||
const Console = ({
|
const Console = ({
|
||||||
logs,
|
logs,
|
||||||
|
includeStackTrace,
|
||||||
}) => (
|
}) => (
|
||||||
<ScrollView style={styles.container}>
|
<ScrollView
|
||||||
<View>
|
ref={ref => this.scrollView = ref}
|
||||||
|
onContentSizeChange={(contentWidth, contentHeight)=>{
|
||||||
|
this.scrollView.scrollToEnd({animated: true});
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Wrapper>
|
||||||
{logs.map((log, i) => (
|
{logs.map((log, i) => (
|
||||||
<View key={i}>
|
<Row key={i}>
|
||||||
<Text>
|
<Emphasis color={getColor(log.type)}>
|
||||||
{log.type}
|
{log.type}
|
||||||
</Text>
|
</Emphasis>
|
||||||
{formatData(log.data)}
|
<OutputList
|
||||||
</View>
|
items={log.data}
|
||||||
|
includeStackTrace={includeStackTrace}
|
||||||
|
color={getColor(log.type)}
|
||||||
|
/>
|
||||||
|
</Row>
|
||||||
))}
|
))}
|
||||||
</View>
|
</Wrapper>
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -14,11 +14,13 @@ const styles = StyleSheet.create({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const Console = () => (
|
const Console = ({
|
||||||
|
includeStackTrace,
|
||||||
|
}) => (
|
||||||
<Log>
|
<Log>
|
||||||
{({ logs }) => (
|
{({ logs }) => (
|
||||||
<View style={styles.container}>
|
<View style={styles.container}>
|
||||||
<Output logs={logs} />
|
<Output logs={logs} includeStackTrace={includeStackTrace} />
|
||||||
<Input />
|
<Input />
|
||||||
</View>
|
</View>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
import React, { Component, Fragment } from 'react';
|
import React, { Component } from 'react';
|
||||||
import {
|
import {
|
||||||
Button,
|
Button,
|
||||||
Modal,
|
Modal,
|
||||||
|
SafeAreaView,
|
||||||
|
KeyboardAvoidingView,
|
||||||
} from 'react-native';
|
} from 'react-native';
|
||||||
import events from '../../events';
|
import events from '../../events';
|
||||||
import DevTool from './index';
|
import DevTool from './index';
|
||||||
@@ -39,6 +41,10 @@ class Events extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
const {
|
||||||
|
includeStackTrace
|
||||||
|
} = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
animationType="slide"
|
animationType="slide"
|
||||||
@@ -47,15 +53,24 @@ class Events extends Component {
|
|||||||
onRequestClose={() => {
|
onRequestClose={() => {
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Fragment>
|
<SafeAreaView
|
||||||
<DevTool />
|
forceInset={{ top: 'always', vertical: 'always' }}
|
||||||
|
style={{flex: 1}}
|
||||||
|
>
|
||||||
|
<KeyboardAvoidingView
|
||||||
|
style={{flex: 1}}
|
||||||
|
behavior="padding"
|
||||||
|
enabled
|
||||||
|
>
|
||||||
|
<DevTool includeStackTrace={includeStackTrace} />
|
||||||
<Button
|
<Button
|
||||||
title="close"
|
title="close"
|
||||||
onPress={() => {
|
onPress={() => {
|
||||||
events.publish('HIDE_DEVTOOLS');
|
events.publish('HIDE_DEVTOOLS');
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</Fragment>
|
</KeyboardAvoidingView>
|
||||||
|
</SafeAreaView>
|
||||||
</Modal>
|
</Modal>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,43 +1,98 @@
|
|||||||
import React from 'react';
|
import React, { Fragment } from 'react';
|
||||||
import {
|
import {
|
||||||
StyleSheet,
|
|
||||||
ScrollView,
|
ScrollView,
|
||||||
View,
|
View,
|
||||||
Text,
|
|
||||||
} from 'react-native';
|
} from 'react-native';
|
||||||
|
import styled from 'styled-components/native';
|
||||||
|
import {
|
||||||
|
Emphasis,
|
||||||
|
Fixed,
|
||||||
|
} from '../../base/text';
|
||||||
|
import JSONTree from 'react-native-json-tree';
|
||||||
|
import Cell from '../../base/Cell';
|
||||||
|
import CellHeader from '../../base/CellHeader';
|
||||||
import Tab from '../Tab';
|
import Tab from '../Tab';
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const theme = {
|
||||||
container: {
|
scheme: 'bright',
|
||||||
flex: 1,
|
author: 'chris kempson (http://chriskempson.com)',
|
||||||
},
|
base00: '#000000',
|
||||||
});
|
base01: '#303030',
|
||||||
|
base02: '#505050',
|
||||||
|
base03: '#b0b0b0',
|
||||||
|
base04: '#d0d0d0',
|
||||||
|
base05: '#e0e0e0',
|
||||||
|
base06: '#f5f5f5',
|
||||||
|
base07: '#ffffff',
|
||||||
|
base08: '#fb0120',
|
||||||
|
base09: '#fc6d24',
|
||||||
|
base0A: '#fda331',
|
||||||
|
base0B: '#a1c659',
|
||||||
|
base0C: '#76c7b7',
|
||||||
|
base0D: '#6fb3d2',
|
||||||
|
base0E: '#d381c3',
|
||||||
|
base0F: '#be643c'
|
||||||
|
};
|
||||||
|
|
||||||
|
const Indented = styled.View`
|
||||||
|
margin: 0 25px;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const getResponse = (request) => {
|
||||||
|
if (request.responseType == 'blob' || request.responseType == 'ArrayBuffer') {
|
||||||
|
return <Emphasis>🤖 Binary</Emphasis>
|
||||||
|
}
|
||||||
|
const contentType = request.getResponseHeader('content-type');
|
||||||
|
const contentTypes = contentType.split(';').map(c => c.trim());
|
||||||
|
|
||||||
|
if (contentTypes.includes('application/json')) {
|
||||||
|
const data = JSON.parse(request.responseText);
|
||||||
|
return <JSONTree theme={theme} data={data} />
|
||||||
|
}
|
||||||
|
|
||||||
|
return <Fixed>{request.responseText}</Fixed>;
|
||||||
|
}
|
||||||
|
|
||||||
const Data = ({
|
const Data = ({
|
||||||
url,
|
url,
|
||||||
method,
|
method,
|
||||||
status,
|
status,
|
||||||
|
headers,
|
||||||
|
request,
|
||||||
args = [],
|
args = [],
|
||||||
}) => (
|
}) => {
|
||||||
<ScrollView style={styles.container}>
|
const headerInfo = Object.keys(headers).map(key => `${key}: ${headers[key]}`).join('\n');
|
||||||
|
return (
|
||||||
|
<ScrollView>
|
||||||
<View>
|
<View>
|
||||||
<Text>Status: {status}</Text>
|
<Cell left="Status" right={status} />
|
||||||
<Text>Method: {method}</Text>
|
<Cell left="Method" right={method} />
|
||||||
<Text>Url: {url}</Text>
|
<Cell left="Url" right={url} />
|
||||||
<Text>Request Body:</Text>
|
<CellHeader>Response Headers</CellHeader>
|
||||||
|
<Indented><Fixed>{request.getAllResponseHeaders()}</Fixed></Indented>
|
||||||
|
{headerInfo && (
|
||||||
|
<Fragment>
|
||||||
|
<CellHeader>Request Headers</CellHeader>
|
||||||
|
<Indented><Fixed>{headerInfo}</Fixed></Indented>
|
||||||
|
</Fragment>
|
||||||
|
)}
|
||||||
{args[0] && (
|
{args[0] && (
|
||||||
<Text>{args[0].toString()}</Text>
|
<Fragment>
|
||||||
|
<CellHeader>Request Body</CellHeader>
|
||||||
|
<Fixed>{args[0].toString()}</Fixed>
|
||||||
|
</Fragment>
|
||||||
)}
|
)}
|
||||||
</View>
|
</View>
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
);
|
);
|
||||||
|
};
|
||||||
|
|
||||||
const Response = ({
|
const Response = ({
|
||||||
request,
|
request,
|
||||||
}) => (
|
}) => (
|
||||||
<ScrollView style={styles.container}>
|
<ScrollView>
|
||||||
<View>
|
<View>
|
||||||
<Text>Response: {request.responseText}</Text>
|
{getResponse(request)}
|
||||||
</View>
|
</View>
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
);
|
);
|
||||||
@@ -46,10 +101,10 @@ const Response = ({
|
|||||||
const RequestDetails = (props) => (
|
const RequestDetails = (props) => (
|
||||||
<Tab
|
<Tab
|
||||||
tabs={[{
|
tabs={[{
|
||||||
name: 'overview',
|
name: 'Details',
|
||||||
view: <Data {...props} />
|
view: <Data {...props} />
|
||||||
}, {
|
}, {
|
||||||
name: 'response',
|
name: 'Response',
|
||||||
view: <Response {...props} />
|
view: <Response {...props} />
|
||||||
}]}
|
}]}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -1,41 +1,31 @@
|
|||||||
import React from 'react';
|
import React, { Fragment } from 'react';
|
||||||
|
import styled from 'styled-components/native';
|
||||||
|
import Status from '../../base/Status';
|
||||||
|
import Row from '../../base/Row';
|
||||||
import {
|
import {
|
||||||
StyleSheet,
|
Body,
|
||||||
View,
|
} from '../../base/text';
|
||||||
Text,
|
|
||||||
ScrollView,
|
|
||||||
TouchableOpacity,
|
|
||||||
} from 'react-native';
|
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const ScrollView = styled.ScrollView`
|
||||||
container: {
|
flex: 1;
|
||||||
flex: 1,
|
`;
|
||||||
borderColor: '#ccc',
|
|
||||||
borderBottomWidth: 1,
|
const Wrapper = styled.View`
|
||||||
},
|
flex: 1;
|
||||||
row: {
|
`;
|
||||||
flexDirection: 'row',
|
|
||||||
padding: 10,
|
const TouchableOpacity = styled.TouchableOpacity`
|
||||||
},
|
`;
|
||||||
method: {
|
|
||||||
padding: 5,
|
|
||||||
},
|
|
||||||
url: {
|
|
||||||
flex: 1,
|
|
||||||
padding: 5,
|
|
||||||
},
|
|
||||||
status: {
|
|
||||||
padding: 5,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const RequestDetails = ({
|
const RequestDetails = ({
|
||||||
requests,
|
requests,
|
||||||
onSelect,
|
onSelect,
|
||||||
|
selected,
|
||||||
}) => (
|
}) => (
|
||||||
<ScrollView style={styles.container}>
|
<ScrollView>
|
||||||
<View>
|
<Wrapper>
|
||||||
{requests.map(({
|
{requests.map(({
|
||||||
|
id,
|
||||||
status,
|
status,
|
||||||
method,
|
method,
|
||||||
url,
|
url,
|
||||||
@@ -44,14 +34,18 @@ const RequestDetails = ({
|
|||||||
key={i}
|
key={i}
|
||||||
onPress={() => onSelect(i)}
|
onPress={() => onSelect(i)}
|
||||||
>
|
>
|
||||||
<View style={styles.row}>
|
<Row
|
||||||
<Text style={styles.method}>{method}</Text>
|
selected={selected === id}
|
||||||
<Text style={styles.url}>{url}</Text>
|
left={<Body>{method}</Body>}
|
||||||
<Text style={styles.status}>{status}</Text>
|
right={(
|
||||||
</View>
|
<Status code={status} />
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<Body>{url}</Body>
|
||||||
|
</Row>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
))}
|
))}
|
||||||
</View>
|
</Wrapper>
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ const Console = () => (
|
|||||||
return (
|
return (
|
||||||
<View style={styles.container}>
|
<View style={styles.container}>
|
||||||
<List
|
<List
|
||||||
|
selected={selected ? selected.id : undefined}
|
||||||
requests={requests}
|
requests={requests}
|
||||||
onSelect={(i) => setState({ active: i })}
|
onSelect={(i) => setState({ active: i })}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React from 'react';
|
import React, { Fragment } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import {
|
import {
|
||||||
Text,
|
Text,
|
||||||
@@ -30,20 +30,21 @@ const styles = StyleSheet.create({
|
|||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
padding: 10,
|
padding: 10,
|
||||||
borderBottomWidth: 4,
|
borderBottomWidth: 4,
|
||||||
borderColor: 'red',
|
borderColor: '#2980b9',
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const Console = ({
|
const Console = ({
|
||||||
tabs,
|
tabs,
|
||||||
}) => (
|
}) => (
|
||||||
|
<View style={styles.container}>
|
||||||
<State
|
<State
|
||||||
initState={{
|
initState={{
|
||||||
active: 0,
|
active: 0,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{({ active }, setState) => (
|
{({ active }, setState) => (
|
||||||
<View style={styles.container}>
|
<Fragment>
|
||||||
<View style={styles.tabs}>
|
<View style={styles.tabs}>
|
||||||
{tabs.map(({ name }, i) => (
|
{tabs.map(({ name }, i) => (
|
||||||
<TouchableOpacity
|
<TouchableOpacity
|
||||||
@@ -58,9 +59,10 @@ const Console = ({
|
|||||||
))}
|
))}
|
||||||
</View>
|
</View>
|
||||||
{tabs[active] && tabs[active].view}
|
{tabs[active] && tabs[active].view}
|
||||||
</View>
|
</Fragment>
|
||||||
)}
|
)}
|
||||||
</State>
|
</State>
|
||||||
|
</View>
|
||||||
);
|
);
|
||||||
|
|
||||||
Console.propTypes = {
|
Console.propTypes = {
|
||||||
|
|||||||
@@ -15,14 +15,15 @@ const styles = StyleSheet.create({
|
|||||||
|
|
||||||
const DevTool = ({
|
const DevTool = ({
|
||||||
style,
|
style,
|
||||||
|
includeStackTrace
|
||||||
}) => (
|
}) => (
|
||||||
<View style={style || styles.container}>
|
<View style={style || styles.container}>
|
||||||
<Tab
|
<Tab
|
||||||
tabs={[{
|
tabs={[{
|
||||||
name: 'console',
|
name: 'Console',
|
||||||
view: <Console />,
|
view: <Console includeStackTrace={includeStackTrace} />,
|
||||||
}, {
|
}, {
|
||||||
name: 'network',
|
name: 'Network',
|
||||||
view: <Requests />,
|
view: <Requests />,
|
||||||
}]}
|
}]}
|
||||||
/>
|
/>
|
||||||
|
|||||||
29
lib/src/components/base/Cell.js
Normal file
29
lib/src/components/base/Cell.js
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import styled from 'styled-components/native';
|
||||||
|
import {
|
||||||
|
Body,
|
||||||
|
Emphasis,
|
||||||
|
} from './text';
|
||||||
|
|
||||||
|
const Wrapper = styled.View`
|
||||||
|
flex-direction: row;
|
||||||
|
padding: 10px;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const Left = styled.View`
|
||||||
|
width: 100px;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const Row = ({
|
||||||
|
left,
|
||||||
|
right,
|
||||||
|
}) => (
|
||||||
|
<Wrapper>
|
||||||
|
<Left>
|
||||||
|
<Emphasis>{left}:</Emphasis>
|
||||||
|
</Left>
|
||||||
|
<Body>{right}</Body>
|
||||||
|
</Wrapper>
|
||||||
|
)
|
||||||
|
|
||||||
|
export default Row;
|
||||||
20
lib/src/components/base/CellHeader.js
Normal file
20
lib/src/components/base/CellHeader.js
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import styled from 'styled-components/native';
|
||||||
|
import {
|
||||||
|
Emphasis,
|
||||||
|
} from './text';
|
||||||
|
|
||||||
|
const Wrapper = styled.View`
|
||||||
|
flex-direction: row;
|
||||||
|
padding: 10px;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const Row = ({
|
||||||
|
children,
|
||||||
|
}) => (
|
||||||
|
<Wrapper>
|
||||||
|
<Emphasis>{children}:</Emphasis>
|
||||||
|
</Wrapper>
|
||||||
|
)
|
||||||
|
|
||||||
|
export default Row;
|
||||||
35
lib/src/components/base/Row.js
Normal file
35
lib/src/components/base/Row.js
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import styled from 'styled-components/native';
|
||||||
|
|
||||||
|
const Wrapper = styled.View`
|
||||||
|
flex-direction: row;
|
||||||
|
padding: 10px;
|
||||||
|
border-left-width: ${props => props.selected ? '10px' : '0'};
|
||||||
|
border-color: #2980b9;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const Left = styled.View`
|
||||||
|
`;
|
||||||
|
|
||||||
|
const Right = styled.View`
|
||||||
|
`;
|
||||||
|
|
||||||
|
const Center = styled.View`
|
||||||
|
flex: 1;
|
||||||
|
margin: 0 10px;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const Row = ({
|
||||||
|
left,
|
||||||
|
right,
|
||||||
|
children,
|
||||||
|
selected,
|
||||||
|
}) => (
|
||||||
|
<Wrapper selected={selected}>
|
||||||
|
{left && <Left>{left}</Left>}
|
||||||
|
<Center>{children}</Center>
|
||||||
|
{right && <Right>{right}</Right>}
|
||||||
|
</Wrapper>
|
||||||
|
)
|
||||||
|
|
||||||
|
export default Row;
|
||||||
41
lib/src/components/base/Status.js
Normal file
41
lib/src/components/base/Status.js
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import styled from 'styled-components/native';
|
||||||
|
import {
|
||||||
|
Body,
|
||||||
|
} from '../base/text';
|
||||||
|
|
||||||
|
const getColor = (code) => {
|
||||||
|
if (code >= 500) {
|
||||||
|
return '#c0392b';
|
||||||
|
}
|
||||||
|
if (code >= 400) {
|
||||||
|
return '#f1c40f';
|
||||||
|
}
|
||||||
|
if (code >= 300) {
|
||||||
|
return '#2980b9';
|
||||||
|
}
|
||||||
|
return '#2ecc71';
|
||||||
|
}
|
||||||
|
|
||||||
|
const Wrapper = styled.View`
|
||||||
|
flex-direction: row;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const Icon = styled.View`
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
border-radius: 8px;
|
||||||
|
background: ${props => getColor(props.code)};
|
||||||
|
margin-left: 5px;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const Status = ({
|
||||||
|
code,
|
||||||
|
}) => (
|
||||||
|
<Wrapper>
|
||||||
|
<Body>{code}</Body>
|
||||||
|
<Icon code={code} />
|
||||||
|
</Wrapper>
|
||||||
|
)
|
||||||
|
|
||||||
|
export default Status;
|
||||||
14
lib/src/components/base/text.js
Normal file
14
lib/src/components/base/text.js
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import styled from 'styled-components/native';
|
||||||
|
|
||||||
|
export const Body = styled.Text`
|
||||||
|
color: ${props => props.color || 'black'};
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const Emphasis = styled.Text`
|
||||||
|
font-weight: bold;
|
||||||
|
color: ${props => props.color || 'black'};
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const Fixed = styled.Text`
|
||||||
|
font-family: Menlo-Regular;
|
||||||
|
`;
|
||||||
@@ -7,23 +7,18 @@ class Log extends Component {
|
|||||||
this.state = {
|
this.state = {
|
||||||
logs: [],
|
logs: [],
|
||||||
};
|
};
|
||||||
this.addLog = this.addLog.bind(this);
|
this.setLogs = this.setLogs.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
log.listen(this.addLog);
|
log.listen(this.setLogs);
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
log.unlisten(this.addLog);
|
log.unlisten(this.setLogs);
|
||||||
}
|
}
|
||||||
|
|
||||||
addLog(entry) {
|
setLogs(logs) {
|
||||||
entry = Array.isArray(entry) ? entry : [entry];
|
|
||||||
const logs = [
|
|
||||||
...this.state.logs,
|
|
||||||
...entry,
|
|
||||||
];
|
|
||||||
this.setState({
|
this.setState({
|
||||||
logs,
|
logs,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -7,23 +7,18 @@ class Network extends Component {
|
|||||||
this.state = {
|
this.state = {
|
||||||
requests: [],
|
requests: [],
|
||||||
};
|
};
|
||||||
this.addRequest = this.addRequest.bind(this);
|
this.setRequests = this.setRequests.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
network.listen(this.addRequest);
|
network.listen(this.setRequests);
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
network.unlisten(this.addRequest);
|
network.unlisten(this.setRequests);
|
||||||
}
|
}
|
||||||
|
|
||||||
addRequest(request) {
|
setRequests(requests) {
|
||||||
request = Array.isArray(request) ? request : [request];
|
|
||||||
const requests = [
|
|
||||||
...this.state.requests,
|
|
||||||
...request,
|
|
||||||
];
|
|
||||||
this.setState({
|
this.setState({
|
||||||
requests,
|
requests,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,12 +1,3 @@
|
|||||||
/* const overrides = [
|
|
||||||
'log',
|
|
||||||
];
|
|
||||||
|
|
||||||
const proxies = overrides.reduce((output, key) => ({
|
|
||||||
...output,
|
|
||||||
[key]: window.console[key],
|
|
||||||
}), {}); */
|
|
||||||
|
|
||||||
const proxyConsole = window.console;
|
const proxyConsole = window.console;
|
||||||
|
|
||||||
class Log {
|
class Log {
|
||||||
@@ -24,41 +15,49 @@ class Log {
|
|||||||
this.listeners = this.listeners.filter(l => l !== fn);
|
this.listeners = this.listeners.filter(l => l !== fn);
|
||||||
}
|
}
|
||||||
|
|
||||||
log(type, data) {
|
log(type, data, keep) {
|
||||||
const entry = {
|
const entry = {
|
||||||
type,
|
type,
|
||||||
data,
|
data,
|
||||||
};
|
};
|
||||||
this.logs.push(entry);
|
this.logs.push(entry);
|
||||||
this.listeners.forEach(l => l(entry));
|
this.listeners.forEach(l => l(this.logs));
|
||||||
|
if (keep) {
|
||||||
|
proxyConsole[type](...data);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
info(data) {
|
info(data, keep) {
|
||||||
this.log('info', data);
|
this.log('info', data, keep);
|
||||||
}
|
}
|
||||||
|
|
||||||
error(error) {
|
error(data, keep) {
|
||||||
this.log('error', error);
|
this.log('error', data, keep);
|
||||||
}
|
}
|
||||||
|
|
||||||
warn(data) {
|
warn(data, keep) {
|
||||||
this.log('warn', data);
|
this.log('warn', data, keep);
|
||||||
}
|
}
|
||||||
|
|
||||||
debug(data) {
|
debug(data, keep) {
|
||||||
this.log('debug', data);
|
this.log('debug', data, keep);
|
||||||
}
|
}
|
||||||
|
|
||||||
attach(keep) {
|
attach(keep) {
|
||||||
|
const redirected = Object.keys(proxyConsole).reduce((output, key) => ({
|
||||||
|
...output,
|
||||||
|
[key]: keep ? (...args) => proxyConsole[key](...args) : () => {},
|
||||||
|
}), {});
|
||||||
window.console = {
|
window.console = {
|
||||||
error: (...data) => this.error(...data),
|
...redirected,
|
||||||
warn: (data) => this.warn(data),
|
error: (...data) => this.error(data, keep),
|
||||||
info: (data) => this.info(data),
|
warn: (...data) => this.warn(data, keep),
|
||||||
log: (data) => this.info(data),
|
info: (...data) => this.info(data, keep),
|
||||||
debug: (data) => this.debug(data),
|
log: (...data) => this.info(data, keep),
|
||||||
|
debug: (...data) => this.debug(data, keep),
|
||||||
};
|
};
|
||||||
ErrorUtils.setGlobalHandler((err, fatal) => {
|
ErrorUtils.setGlobalHandler((err, fatal) => {
|
||||||
this.error(err);
|
this.error([err], keep);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ class Network {
|
|||||||
constructor() {
|
constructor() {
|
||||||
this.requests = [];
|
this.requests = [];
|
||||||
this.listeners = [];
|
this.listeners = [];
|
||||||
|
this.currentId = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
listen(fn) {
|
listen(fn) {
|
||||||
@@ -16,12 +17,16 @@ class Network {
|
|||||||
}
|
}
|
||||||
|
|
||||||
addRequest(request) {
|
addRequest(request) {
|
||||||
this.requests.push(request);
|
this.requests.push({
|
||||||
this.listeners.forEach(l => l(request));
|
id: this.currentId++,
|
||||||
|
...request,
|
||||||
|
});
|
||||||
|
this.listeners.forEach(l => l(this.requests));
|
||||||
}
|
}
|
||||||
|
|
||||||
attach() {
|
attach() {
|
||||||
const me = this;
|
const me = this;
|
||||||
|
const headers = {};
|
||||||
window.XMLHttpRequest.prototype.open = function proxyOpen (...args) {
|
window.XMLHttpRequest.prototype.open = function proxyOpen (...args) {
|
||||||
let sendArgs;
|
let sendArgs;
|
||||||
const [
|
const [
|
||||||
@@ -33,6 +38,7 @@ class Network {
|
|||||||
url,
|
url,
|
||||||
method,
|
method,
|
||||||
args: sendArgs,
|
args: sendArgs,
|
||||||
|
headers,
|
||||||
request: this,
|
request: this,
|
||||||
status: this.status,
|
status: this.status,
|
||||||
});
|
});
|
||||||
@@ -43,15 +49,21 @@ class Network {
|
|||||||
method,
|
method,
|
||||||
error,
|
error,
|
||||||
args: sendArgs,
|
args: sendArgs,
|
||||||
|
headers,
|
||||||
request: this,
|
request: this,
|
||||||
status: this.status || 'CONN ERR',
|
status: this.status || 'CONN ERR',
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
const proxiedSend = this.send;
|
const proxiedSend = this.send;
|
||||||
|
const proxiedSetRequestHeader = this.setRequestHeader;
|
||||||
this.send = function proxySend (...sendargs) {
|
this.send = function proxySend (...sendargs) {
|
||||||
sendArgs = sendargs;
|
sendArgs = sendargs;
|
||||||
return proxiedSend.apply(this, [].slice.call(arguments));
|
return proxiedSend.apply(this, [].slice.call(arguments));
|
||||||
}
|
}
|
||||||
|
this.setRequestHeader = function (name, value) {
|
||||||
|
headers[name] = value;
|
||||||
|
return proxiedSetRequestHeader.apply(this, [].slice.call(arguments));
|
||||||
|
}
|
||||||
return proxied.apply(this, [].slice.call(arguments));
|
return proxied.apply(this, [].slice.call(arguments));
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user