LogBoxInspector.js 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. /**
  2. * Copyright (c) Facebook, Inc. and its affiliates.
  3. *
  4. * This source code is licensed under the MIT license found in the
  5. * LICENSE file in the root directory of this source tree.
  6. *
  7. * @flow strict-local
  8. * @format
  9. */
  10. 'use strict';
  11. import LogBoxInspectorCodeFrame from './LogBoxInspectorCodeFrame';
  12. import * as React from 'react';
  13. import ScrollView from '../../Components/ScrollView/ScrollView';
  14. import StyleSheet from '../../StyleSheet/StyleSheet';
  15. import View from '../../Components/View/View';
  16. import * as LogBoxData from '../Data/LogBoxData';
  17. import Keyboard from '../../Components/Keyboard/Keyboard';
  18. import LogBoxInspectorFooter from './LogBoxInspectorFooter';
  19. import LogBoxInspectorMessageHeader from './LogBoxInspectorMessageHeader';
  20. import LogBoxInspectorReactFrames from './LogBoxInspectorReactFrames';
  21. import LogBoxInspectorStackFrames from './LogBoxInspectorStackFrames';
  22. import LogBoxInspectorHeader from './LogBoxInspectorHeader';
  23. import * as LogBoxStyle from './LogBoxStyle';
  24. import LogBoxLog, {type LogLevel} from '../Data/LogBoxLog';
  25. type Props = $ReadOnly<{|
  26. onDismiss: () => void,
  27. onChangeSelectedIndex: (index: number) => void,
  28. onMinimize: () => void,
  29. logs: $ReadOnlyArray<LogBoxLog>,
  30. selectedIndex: number,
  31. fatalType?: ?LogLevel,
  32. |}>;
  33. function LogBoxInspector(props: Props): React.Node {
  34. const {logs, selectedIndex} = props;
  35. let log = logs[selectedIndex];
  36. React.useEffect(() => {
  37. if (log) {
  38. LogBoxData.symbolicateLogNow(log);
  39. }
  40. }, [log]);
  41. React.useEffect(() => {
  42. // Optimistically symbolicate the last and next logs.
  43. if (logs.length > 1) {
  44. const selected = selectedIndex;
  45. const lastIndex = logs.length - 1;
  46. const prevIndex = selected - 1 < 0 ? lastIndex : selected - 1;
  47. const nextIndex = selected + 1 > lastIndex ? 0 : selected + 1;
  48. LogBoxData.symbolicateLogLazy(logs[prevIndex]);
  49. LogBoxData.symbolicateLogLazy(logs[nextIndex]);
  50. }
  51. }, [logs, selectedIndex]);
  52. React.useEffect(() => {
  53. Keyboard.dismiss();
  54. }, []);
  55. function _handleRetry() {
  56. LogBoxData.retrySymbolicateLogNow(log);
  57. }
  58. if (log == null) {
  59. return null;
  60. }
  61. return (
  62. <View style={styles.root}>
  63. <LogBoxInspectorHeader
  64. onSelectIndex={props.onChangeSelectedIndex}
  65. selectedIndex={selectedIndex}
  66. total={logs.length}
  67. level={log.level}
  68. />
  69. <LogBoxInspectorBody log={log} onRetry={_handleRetry} />
  70. <LogBoxInspectorFooter
  71. onDismiss={props.onDismiss}
  72. onMinimize={props.onMinimize}
  73. level={log.level}
  74. />
  75. </View>
  76. );
  77. }
  78. const headerTitleMap = {
  79. warn: 'Warning',
  80. error: 'Error',
  81. fatal: 'Exception',
  82. syntax: 'Syntax Error',
  83. component: 'Component Exception',
  84. };
  85. function LogBoxInspectorBody(props) {
  86. const [collapsed, setCollapsed] = React.useState(true);
  87. React.useEffect(() => {
  88. setCollapsed(true);
  89. }, [props.log]);
  90. const headerTitle =
  91. props.log.type ??
  92. headerTitleMap[props.log.isComponentError ? 'component' : props.log.level];
  93. if (collapsed) {
  94. return (
  95. <>
  96. <LogBoxInspectorMessageHeader
  97. collapsed={collapsed}
  98. onPress={() => setCollapsed(!collapsed)}
  99. message={props.log.message}
  100. level={props.log.level}
  101. title={headerTitle}
  102. />
  103. <ScrollView style={styles.scrollBody}>
  104. <LogBoxInspectorCodeFrame codeFrame={props.log.codeFrame} />
  105. <LogBoxInspectorReactFrames log={props.log} />
  106. <LogBoxInspectorStackFrames log={props.log} onRetry={props.onRetry} />
  107. </ScrollView>
  108. </>
  109. );
  110. }
  111. return (
  112. <ScrollView style={styles.scrollBody}>
  113. <LogBoxInspectorMessageHeader
  114. collapsed={collapsed}
  115. onPress={() => setCollapsed(!collapsed)}
  116. message={props.log.message}
  117. level={props.log.level}
  118. title={headerTitle}
  119. />
  120. <LogBoxInspectorCodeFrame codeFrame={props.log.codeFrame} />
  121. <LogBoxInspectorReactFrames log={props.log} />
  122. <LogBoxInspectorStackFrames log={props.log} onRetry={props.onRetry} />
  123. </ScrollView>
  124. );
  125. }
  126. const styles = StyleSheet.create({
  127. root: {
  128. flex: 1,
  129. backgroundColor: LogBoxStyle.getTextColor(),
  130. },
  131. scrollBody: {
  132. backgroundColor: LogBoxStyle.getBackgroundColor(0.9),
  133. flex: 1,
  134. },
  135. });
  136. export default LogBoxInspector;