Skip to content

Commit 3c525d5

Browse files
rickhanloniifacebook-github-bot
authored andcommitted
LogBox - Display errors for notifications and inspector
Summary: This diff adds and displays errors in LogBox. We will now toast both warnings and errors, open errors for inspection, and allow paginating through errors and warnings. Changelog: [Internal] Reviewed By: cpojer Differential Revision: D18091519 fbshipit-source-id: c155969dc505de5cfb0e95bb5a8221b9f8cfe4f7
1 parent c5aa26d commit 3c525d5

13 files changed

+527
-70
lines changed

Libraries/LogBox/UI/LogBoxContainer.js

Lines changed: 42 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,6 @@ function LogBoxContainer(props: Props): React.Node {
3030

3131
const logs = Array.from(props.logs);
3232

33-
function getVisibleLog() {
34-
// TODO: currently returns the newest log but later will need to return
35-
// the newest log of the highest level. For example, we want to show
36-
// the latest error message even if there are newer warnings.
37-
return logs[logs.length - 1];
38-
}
39-
4033
function handleInspectorDismissAll() {
4134
props.onDismissAll();
4235
}
@@ -59,8 +52,12 @@ function LogBoxContainer(props: Props): React.Node {
5952
setSelectedLog(null);
6053
}
6154

62-
function handleRowPress(index: number) {
63-
setSelectedLog(logs.length - 1);
55+
function openLog(log: LogBoxLog) {
56+
let index = logs.length - 1;
57+
while (index > 0 && logs[index] !== log) {
58+
index -= 1;
59+
}
60+
setSelectedLog(index);
6461
}
6562

6663
if (selectedLogIndex != null) {
@@ -77,20 +74,42 @@ function LogBoxContainer(props: Props): React.Node {
7774
);
7875
}
7976

80-
return logs.length === 0 ? null : (
77+
if (logs.length === 0) {
78+
return null;
79+
}
80+
81+
const warnings = logs.filter(log => log.level === 'warn');
82+
const errors = logs.filter(log => log.level === 'error');
83+
return (
8184
<View style={styles.list}>
82-
<View style={styles.toast}>
83-
<LogBoxLogNotification
84-
log={getVisibleLog()}
85-
level="warn"
86-
totalLogCount={logs.length}
87-
onPressOpen={handleRowPress}
88-
onPressList={() => {
89-
/* TODO: open log list */
90-
}}
91-
onPressDismiss={handleInspectorDismissAll}
92-
/>
93-
</View>
85+
{warnings.length > 0 && (
86+
<View style={styles.toast}>
87+
<LogBoxLogNotification
88+
log={warnings[warnings.length - 1]}
89+
level="warn"
90+
totalLogCount={warnings.length}
91+
onPressOpen={() => openLog(warnings[warnings.length - 1])}
92+
onPressList={() => {
93+
/* TODO: open log list */
94+
}}
95+
onPressDismiss={handleInspectorDismissAll}
96+
/>
97+
</View>
98+
)}
99+
{errors.length > 0 && (
100+
<View style={styles.toast}>
101+
<LogBoxLogNotification
102+
log={errors[errors.length - 1]}
103+
level="error"
104+
totalLogCount={errors.length}
105+
onPressOpen={() => openLog(errors[errors.length - 1])}
106+
onPressList={() => {
107+
/* TODO: open log list */
108+
}}
109+
onPressDismiss={handleInspectorDismissAll}
110+
/>
111+
</View>
112+
)}
94113
<SafeAreaView style={styles.safeArea} />
95114
</View>
96115
);
@@ -105,6 +124,7 @@ const styles = StyleSheet.create({
105124
},
106125
toast: {
107126
borderRadius: 8,
127+
marginBottom: 5,
108128
overflow: 'hidden',
109129
},
110130
safeArea: {

Libraries/LogBox/UI/LogBoxInspector.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ class LogBoxInspector extends React.Component<Props> {
5555
onSelectIndex={this._handleSelectIndex}
5656
selectedIndex={selectedIndex}
5757
total={logs.length}
58+
level={log.level}
5859
/>
5960
<LogBoxInspectorBody
6061
log={log}
@@ -113,6 +114,7 @@ function LogBoxInspectorBody(props) {
113114
collapsed={collapsed}
114115
onPress={() => setCollapsed(!collapsed)}
115116
message={props.log.message}
117+
level={props.log.level}
116118
/>
117119
<ScrollView style={styles.scrollBody}>
118120
<LogBoxInspectorReactFrames log={props.log} />
@@ -128,6 +130,7 @@ function LogBoxInspectorBody(props) {
128130
collapsed={collapsed}
129131
onPress={() => setCollapsed(!collapsed)}
130132
message={props.log.message}
133+
level={props.log.level}
131134
/>
132135
<LogBoxInspectorReactFrames log={props.log} />
133136
<LogBoxInspectorStackFrames log={props.log} onRetry={props.onRetry} />

Libraries/LogBox/UI/LogBoxInspectorHeader.js

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,12 @@ import View from '../../Components/View/View';
2020
import LogBoxImageSource from './LogBoxImageSource';
2121
import LogBoxButton from './LogBoxButton';
2222
import * as LogBoxStyle from './LogBoxStyle';
23-
23+
import type {LogLevel} from '../Data/LogBoxLog';
2424
type Props = $ReadOnly<{|
2525
onSelectIndex: (selectedIndex: number) => void,
2626
selectedIndex: number,
2727
total: number,
28+
level: LogLevel,
2829
|}>;
2930

3031
function LogBoxInspectorHeader(props: Props): React.Node {
@@ -37,10 +38,11 @@ function LogBoxInspectorHeader(props: Props): React.Node {
3738
: `Log ${props.selectedIndex + 1} of ${props.total}`;
3839

3940
return (
40-
<SafeAreaView style={styles.root}>
41+
<SafeAreaView style={styles[props.level]}>
4142
<View style={styles.header}>
4243
<LogBoxInspectorHeaderButton
4344
disabled={prevIndex < 0}
45+
level={props.level}
4446
image={LogBoxImageSource.chevronLeft}
4547
onPress={() => props.onSelectIndex(prevIndex)}
4648
/>
@@ -49,6 +51,7 @@ function LogBoxInspectorHeader(props: Props): React.Node {
4951
</View>
5052
<LogBoxInspectorHeaderButton
5153
disabled={nextIndex >= props.total}
54+
level={props.level}
5255
image={LogBoxImageSource.chevronRight}
5356
onPress={() => props.onSelectIndex(nextIndex)}
5457
/>
@@ -61,14 +64,21 @@ function LogBoxInspectorHeaderButton(
6164
props: $ReadOnly<{|
6265
disabled: boolean,
6366
image: string,
67+
level: LogLevel,
6468
onPress?: ?() => void,
6569
|}>,
6670
): React.Node {
6771
return (
6872
<LogBoxButton
6973
backgroundColor={{
70-
default: LogBoxStyle.getWarningColor(),
71-
pressed: LogBoxStyle.getWarningDarkColor(),
74+
default:
75+
props.level === 'warn'
76+
? LogBoxStyle.getWarningColor()
77+
: LogBoxStyle.getErrorColor(),
78+
pressed:
79+
props.level === 'warn'
80+
? LogBoxStyle.getWarningDarkColor()
81+
: LogBoxStyle.getErrorDarkColor(),
7282
}}
7383
onPress={props.disabled ? null : props.onPress}
7484
style={headerStyles.button}>
@@ -99,8 +109,11 @@ const headerStyles = StyleSheet.create({
99109
});
100110

101111
const styles = StyleSheet.create({
102-
root: {
103-
backgroundColor: LogBoxStyle.getWarningColor(1),
112+
warn: {
113+
backgroundColor: LogBoxStyle.getWarningColor(),
114+
},
115+
error: {
116+
backgroundColor: LogBoxStyle.getErrorColor(),
104117
},
105118
header: {
106119
flexDirection: 'row',

Libraries/LogBox/UI/LogBoxInspectorMessageHeader.js

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,13 @@ import View from '../../Components/View/View';
1717
import LogBoxButton from './LogBoxButton';
1818
import * as LogBoxStyle from './LogBoxStyle';
1919
import LogBoxMessage from './LogBoxMessage';
20-
20+
import type {LogLevel} from '../Data/LogBoxLog';
2121
import type {Message} from '../Data/parseLogBoxLog';
2222

2323
type Props = $ReadOnly<{|
2424
collapsed: boolean,
2525
message: Message,
26+
level: LogLevel,
2627
onPress: () => void,
2728
|}>;
2829

@@ -49,7 +50,9 @@ function LogBoxInspectorMessageHeader(props: Props): React.Node {
4950
return (
5051
<View style={messageStyles.body}>
5152
<View style={messageStyles.heading}>
52-
<Text style={messageStyles.headingText}>Warning</Text>
53+
<Text style={[messageStyles.headingText, messageStyles[props.level]]}>
54+
{props.level === 'warn' ? 'Warning' : 'Error'}
55+
</Text>
5356
{renderShowMore()}
5457
</View>
5558
<Text
@@ -91,13 +94,18 @@ const messageStyles = StyleSheet.create({
9194
marginBottom: 5,
9295
},
9396
headingText: {
94-
color: LogBoxStyle.getWarningColor(1),
9597
flex: 1,
9698
fontSize: 20,
9799
fontWeight: '600',
98100
includeFontPadding: false,
99101
lineHeight: 28,
100102
},
103+
warn: {
104+
color: LogBoxStyle.getWarningColor(1),
105+
},
106+
error: {
107+
color: LogBoxStyle.getErrorColor(1),
108+
},
101109
messageText: {
102110
color: LogBoxStyle.getTextColor(0.6),
103111
},

Libraries/LogBox/UI/LogBoxStyle.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,10 @@ export function getErrorColor(opacity?: number): string {
3434
return `rgba(243, 83, 105, ${opacity == null ? 1 : opacity})`;
3535
}
3636

37+
export function getErrorDarkColor(opacity?: number): string {
38+
return `rgba(208, 75, 95, ${opacity == null ? 1 : opacity})`;
39+
}
40+
3741
export function getLogColor(opacity?: number): string {
3842
return `rgba(119, 119, 119, ${opacity == null ? 1 : opacity})`;
3943
}

Libraries/LogBox/UI/__tests__/LogBoxContainer-test.js

Lines changed: 71 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ describe('LogBoxContainer', () => {
2929
expect(output).toMatchSnapshot();
3030
});
3131

32-
it('should render the latest log', () => {
32+
it('should render the latest warning', () => {
3333
const output = render.shallowRender(
3434
<LogBoxContainer
3535
onDismiss={() => {}}
@@ -63,4 +63,74 @@ describe('LogBoxContainer', () => {
6363

6464
expect(output).toMatchSnapshot();
6565
});
66+
67+
it('should render the latest error', () => {
68+
const output = render.shallowRender(
69+
<LogBoxContainer
70+
onDismiss={() => {}}
71+
onDismissAll={() => {}}
72+
logs={
73+
new Set([
74+
new LogBoxLog(
75+
'error',
76+
{
77+
content: 'Some kind of message',
78+
substitutions: [],
79+
},
80+
[],
81+
'Some kind of message',
82+
[],
83+
),
84+
new LogBoxLog(
85+
'error',
86+
{
87+
content: 'Some kind of message (latest)',
88+
substitutions: [],
89+
},
90+
[],
91+
'Some kind of message (latest)',
92+
[],
93+
),
94+
])
95+
}
96+
/>,
97+
);
98+
99+
expect(output).toMatchSnapshot();
100+
});
101+
102+
it('should render both an error and warning', () => {
103+
const output = render.shallowRender(
104+
<LogBoxContainer
105+
onDismiss={() => {}}
106+
onDismissAll={() => {}}
107+
logs={
108+
new Set([
109+
new LogBoxLog(
110+
'warn',
111+
{
112+
content: 'Some kind of message',
113+
substitutions: [],
114+
},
115+
[],
116+
'Some kind of message',
117+
[],
118+
),
119+
new LogBoxLog(
120+
'error',
121+
{
122+
content: 'Some kind of message (latest)',
123+
substitutions: [],
124+
},
125+
[],
126+
'Some kind of message (latest)',
127+
[],
128+
),
129+
])
130+
}
131+
/>,
132+
);
133+
134+
expect(output).toMatchSnapshot();
135+
});
66136
});

Libraries/LogBox/UI/__tests__/LogBoxInspector-test.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ const logs = [
2828
[],
2929
),
3030
new LogBoxLog(
31-
'warn',
31+
'error',
3232
{
3333
content: 'Some kind of message (second)',
3434
substitutions: [],
@@ -54,7 +54,7 @@ describe('LogBoxContainer', () => {
5454
expect(output).toMatchSnapshot();
5555
});
5656

57-
it('should render first log with selectedIndex 0', () => {
57+
it('should render warning with selectedIndex 0', () => {
5858
const output = render.shallowRender(
5959
<LogBoxInspector
6060
onDismiss={() => {}}
@@ -68,7 +68,7 @@ describe('LogBoxContainer', () => {
6868
expect(output).toMatchSnapshot();
6969
});
7070

71-
it('should render second log with selectedIndex 1', () => {
71+
it('should render error with selectedIndex 1', () => {
7272
const output = render.shallowRender(
7373
<LogBoxInspector
7474
onDismiss={() => {}}

0 commit comments

Comments
 (0)