Lots of UI updates

This commit is contained in:
2018-08-16 00:13:06 +02:00
parent 38b440e2f6
commit d92bd0c586
24 changed files with 637 additions and 225 deletions

View File

@@ -17,6 +17,7 @@ const styles = StyleSheet.create({
},
input: {
flex: 1,
fontFamily: 'Menlo-Regular',
},
});
@@ -39,13 +40,13 @@ const Input = ({
onPress={() => {
const fn = new Function(text);
try {
const response = eval(text);
log.info(response);
const response = fn();
log.info([response]);
setState({
text: '',
});
} catch (err) {
log.error(err);
log.error([err]);
}
}}
/>

View File

@@ -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 {
StyleSheet,
ScrollView,
View,
Text,
ScrollView
} from 'react-native';
import JSONTree from 'react-native-json-tree'
import prune from './tools';
import {
Body,
Emphasis,
Fixed,
} from '../../base/text';
const styles = StyleSheet.create({
container: {
flex: 1,
},
});
const getCircularReplacer = () => {
const seen = [];
return (key, val) => {
if (val != null && typeof val == "object") {
if (seen.indexOf(val) >= 0) {
return;
}
seen.push(val);
}
return val;
}
const theme = {
scheme: 'bright',
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 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') {
return <Text>undefined</Text>;
return <Fixed>undefined</Fixed>;
}
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') {
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 = ({
logs,
includeStackTrace,
}) => (
<ScrollView style={styles.container}>
<View>
<ScrollView
ref={ref => this.scrollView = ref}
onContentSizeChange={(contentWidth, contentHeight)=>{
this.scrollView.scrollToEnd({animated: true});
}}
>
<Wrapper>
{logs.map((log, i) => (
<View key={i}>
<Text>
<Row key={i}>
<Emphasis color={getColor(log.type)}>
{log.type}
</Text>
{formatData(log.data)}
</View>
</Emphasis>
<OutputList
items={log.data}
includeStackTrace={includeStackTrace}
color={getColor(log.type)}
/>
</Row>
))}
</View>
</Wrapper>
</ScrollView>
);

View File

@@ -14,11 +14,13 @@ const styles = StyleSheet.create({
},
});
const Console = () => (
const Console = ({
includeStackTrace,
}) => (
<Log>
{({ logs }) => (
<View style={styles.container}>
<Output logs={logs} />
<Output logs={logs} includeStackTrace={includeStackTrace} />
<Input />
</View>
)}

View File

@@ -1,7 +1,9 @@
import React, { Component, Fragment } from 'react';
import React, { Component } from 'react';
import {
Button,
Modal,
SafeAreaView,
KeyboardAvoidingView,
} from 'react-native';
import events from '../../events';
import DevTool from './index';
@@ -39,6 +41,10 @@ class Events extends Component {
}
render() {
const {
includeStackTrace
} = this.props;
return (
<Modal
animationType="slide"
@@ -47,15 +53,24 @@ class Events extends Component {
onRequestClose={() => {
}}
>
<Fragment>
<DevTool />
<Button
title="close"
onPress={() => {
events.publish('HIDE_DEVTOOLS');
}}
/>
</Fragment>
<SafeAreaView
forceInset={{ top: 'always', vertical: 'always' }}
style={{flex: 1}}
>
<KeyboardAvoidingView
style={{flex: 1}}
behavior="padding"
enabled
>
<DevTool includeStackTrace={includeStackTrace} />
<Button
title="close"
onPress={() => {
events.publish('HIDE_DEVTOOLS');
}}
/>
</KeyboardAvoidingView>
</SafeAreaView>
</Modal>
)
}

View File

@@ -1,43 +1,98 @@
import React from 'react';
import React, { Fragment } from 'react';
import {
StyleSheet,
ScrollView,
View,
Text,
} 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';
const styles = StyleSheet.create({
container: {
flex: 1,
},
});
const theme = {
scheme: 'bright',
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 = ({
url,
method,
status,
headers,
request,
args = [],
}) => (
<ScrollView style={styles.container}>
<View>
<Text>Status: {status}</Text>
<Text>Method: {method}</Text>
<Text>Url: {url}</Text>
<Text>Request Body:</Text>
{args[0] && (
<Text>{args[0].toString()}</Text>
)}
</View>
</ScrollView>
);
}) => {
const headerInfo = Object.keys(headers).map(key => `${key}: ${headers[key]}`).join('\n');
return (
<ScrollView>
<View>
<Cell left="Status" right={status} />
<Cell left="Method" right={method} />
<Cell left="Url" right={url} />
<CellHeader>Response Headers</CellHeader>
<Indented><Fixed>{request.getAllResponseHeaders()}</Fixed></Indented>
{headerInfo && (
<Fragment>
<CellHeader>Request Headers</CellHeader>
<Indented><Fixed>{headerInfo}</Fixed></Indented>
</Fragment>
)}
{args[0] && (
<Fragment>
<CellHeader>Request Body</CellHeader>
<Fixed>{args[0].toString()}</Fixed>
</Fragment>
)}
</View>
</ScrollView>
);
};
const Response = ({
request,
}) => (
<ScrollView style={styles.container}>
<ScrollView>
<View>
<Text>Response: {request.responseText}</Text>
{getResponse(request)}
</View>
</ScrollView>
);
@@ -46,10 +101,10 @@ const Response = ({
const RequestDetails = (props) => (
<Tab
tabs={[{
name: 'overview',
name: 'Details',
view: <Data {...props} />
}, {
name: 'response',
name: 'Response',
view: <Response {...props} />
}]}
/>

View File

@@ -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 {
StyleSheet,
View,
Text,
ScrollView,
TouchableOpacity,
} from 'react-native';
Body,
} from '../../base/text';
const styles = StyleSheet.create({
container: {
flex: 1,
borderColor: '#ccc',
borderBottomWidth: 1,
},
row: {
flexDirection: 'row',
padding: 10,
},
method: {
padding: 5,
},
url: {
flex: 1,
padding: 5,
},
status: {
padding: 5,
},
});
const ScrollView = styled.ScrollView`
flex: 1;
`;
const Wrapper = styled.View`
flex: 1;
`;
const TouchableOpacity = styled.TouchableOpacity`
`;
const RequestDetails = ({
requests,
onSelect,
selected,
}) => (
<ScrollView style={styles.container}>
<View>
<ScrollView>
<Wrapper>
{requests.map(({
id,
status,
method,
url,
@@ -44,14 +34,18 @@ const RequestDetails = ({
key={i}
onPress={() => onSelect(i)}
>
<View style={styles.row}>
<Text style={styles.method}>{method}</Text>
<Text style={styles.url}>{url}</Text>
<Text style={styles.status}>{status}</Text>
</View>
<Row
selected={selected === id}
left={<Body>{method}</Body>}
right={(
<Status code={status} />
)}
>
<Body>{url}</Body>
</Row>
</TouchableOpacity>
))}
</View>
</Wrapper>
</ScrollView>
);

View File

@@ -35,6 +35,7 @@ const Console = () => (
return (
<View style={styles.container}>
<List
selected={selected ? selected.id : undefined}
requests={requests}
onSelect={(i) => setState({ active: i })}
/>

View File

@@ -1,4 +1,4 @@
import React from 'react';
import React, { Fragment } from 'react';
import PropTypes from 'prop-types';
import {
Text,
@@ -30,20 +30,21 @@ const styles = StyleSheet.create({
justifyContent: 'center',
padding: 10,
borderBottomWidth: 4,
borderColor: 'red',
borderColor: '#2980b9',
},
});
const Console = ({
tabs,
}) => (
<State
initState={{
active: 0,
}}
>
<View style={styles.container}>
<State
initState={{
active: 0,
}}
>
{({ active }, setState) => (
<View style={styles.container}>
<Fragment>
<View style={styles.tabs}>
{tabs.map(({ name }, i) => (
<TouchableOpacity
@@ -58,9 +59,10 @@ const Console = ({
))}
</View>
{tabs[active] && tabs[active].view}
</View>
</Fragment>
)}
</State>
</State>
</View>
);
Console.propTypes = {

View File

@@ -15,14 +15,15 @@ const styles = StyleSheet.create({
const DevTool = ({
style,
includeStackTrace
}) => (
<View style={style || styles.container}>
<Tab
tabs={[{
name: 'console',
view: <Console />,
name: 'Console',
view: <Console includeStackTrace={includeStackTrace} />,
}, {
name: 'network',
name: 'Network',
view: <Requests />,
}]}
/>