LogBoxInspectorStackFrames.js 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  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 * as React from 'react';
  12. import StyleSheet from '../../StyleSheet/StyleSheet';
  13. import Text from '../../Text/Text';
  14. import View from '../../Components/View/View';
  15. import LogBoxButton from './LogBoxButton';
  16. import LogBoxInspectorSourceMapStatus from './LogBoxInspectorSourceMapStatus';
  17. import LogBoxInspectorStackFrame from './LogBoxInspectorStackFrame';
  18. import LogBoxInspectorSection from './LogBoxInspectorSection';
  19. import * as LogBoxStyle from './LogBoxStyle';
  20. import openFileInEditor from '../../Core/Devtools/openFileInEditor';
  21. import type {Stack} from '../Data/LogBoxSymbolication';
  22. import type LogBoxLog from '../Data/LogBoxLog';
  23. type Props = $ReadOnly<{|
  24. log: LogBoxLog,
  25. onRetry: () => void,
  26. |}>;
  27. export function getCollapseMessage(
  28. stackFrames: Stack,
  29. collapsed: boolean,
  30. ): string {
  31. if (stackFrames.length === 0) {
  32. return 'No frames to show';
  33. }
  34. const collapsedCount = stackFrames.reduce((count, {collapse}) => {
  35. if (collapse === true) {
  36. return count + 1;
  37. }
  38. return count;
  39. }, 0);
  40. if (collapsedCount === 0) {
  41. return 'Showing all frames';
  42. }
  43. const framePlural = `frame${collapsedCount > 1 ? 's' : ''}`;
  44. if (collapsedCount === stackFrames.length) {
  45. return collapsed
  46. ? `See${
  47. collapsedCount > 1 ? ' all ' : ' '
  48. }${collapsedCount} collapsed ${framePlural}`
  49. : `Collapse${
  50. collapsedCount > 1 ? ' all ' : ' '
  51. }${collapsedCount} ${framePlural}`;
  52. } else {
  53. return collapsed
  54. ? `See ${collapsedCount} more ${framePlural}`
  55. : `Collapse ${collapsedCount} ${framePlural}`;
  56. }
  57. }
  58. function LogBoxInspectorStackFrames(props: Props): React.Node {
  59. const [collapsed, setCollapsed] = React.useState(true);
  60. function getStackList() {
  61. if (collapsed === true) {
  62. return props.log.getAvailableStack().filter(({collapse}) => !collapse);
  63. } else {
  64. return props.log.getAvailableStack();
  65. }
  66. }
  67. if (props.log.getAvailableStack().length === 0) {
  68. return null;
  69. }
  70. return (
  71. <LogBoxInspectorSection
  72. heading="Call Stack"
  73. action={
  74. <LogBoxInspectorSourceMapStatus
  75. onPress={
  76. props.log.symbolicated.status === 'FAILED' ? props.onRetry : null
  77. }
  78. status={props.log.symbolicated.status}
  79. />
  80. }>
  81. {props.log.symbolicated.status !== 'COMPLETE' && (
  82. <View style={stackStyles.hintBox}>
  83. <Text style={stackStyles.hintText}>
  84. This call stack is not symbolicated. Some features are unavailable
  85. such as viewing the function name or tapping to open files.
  86. </Text>
  87. </View>
  88. )}
  89. <StackFrameList
  90. list={getStackList()}
  91. status={props.log.symbolicated.status}
  92. />
  93. <StackFrameFooter
  94. onPress={() => setCollapsed(!collapsed)}
  95. message={getCollapseMessage(props.log.getAvailableStack(), collapsed)}
  96. />
  97. </LogBoxInspectorSection>
  98. );
  99. }
  100. function StackFrameList(props) {
  101. return (
  102. <>
  103. {props.list.map((frame, index) => {
  104. const {file, lineNumber} = frame;
  105. return (
  106. <LogBoxInspectorStackFrame
  107. key={index}
  108. frame={frame}
  109. onPress={
  110. props.status === 'COMPLETE' && file != null && lineNumber != null
  111. ? () => openFileInEditor(file, lineNumber)
  112. : null
  113. }
  114. />
  115. );
  116. })}
  117. </>
  118. );
  119. }
  120. function StackFrameFooter(props) {
  121. return (
  122. <View style={stackStyles.collapseContainer}>
  123. <LogBoxButton
  124. backgroundColor={{
  125. default: 'transparent',
  126. pressed: LogBoxStyle.getBackgroundColor(1),
  127. }}
  128. onPress={props.onPress}
  129. style={stackStyles.collapseButton}>
  130. <Text style={stackStyles.collapse}>{props.message}</Text>
  131. </LogBoxButton>
  132. </View>
  133. );
  134. }
  135. const stackStyles = StyleSheet.create({
  136. section: {
  137. marginTop: 15,
  138. },
  139. heading: {
  140. alignItems: 'center',
  141. flexDirection: 'row',
  142. paddingHorizontal: 12,
  143. marginBottom: 10,
  144. },
  145. headingText: {
  146. color: LogBoxStyle.getTextColor(1),
  147. flex: 1,
  148. fontSize: 20,
  149. fontWeight: '600',
  150. includeFontPadding: false,
  151. lineHeight: 20,
  152. },
  153. body: {
  154. paddingBottom: 10,
  155. },
  156. bodyText: {
  157. color: LogBoxStyle.getTextColor(1),
  158. fontSize: 14,
  159. includeFontPadding: false,
  160. lineHeight: 18,
  161. fontWeight: '500',
  162. paddingHorizontal: 27,
  163. },
  164. hintText: {
  165. color: LogBoxStyle.getTextColor(0.7),
  166. fontSize: 13,
  167. includeFontPadding: false,
  168. lineHeight: 18,
  169. fontWeight: '400',
  170. marginHorizontal: 10,
  171. },
  172. hintBox: {
  173. backgroundColor: LogBoxStyle.getBackgroundColor(),
  174. marginHorizontal: 10,
  175. paddingHorizontal: 5,
  176. paddingVertical: 10,
  177. borderRadius: 5,
  178. marginBottom: 5,
  179. },
  180. collapseContainer: {
  181. marginLeft: 15,
  182. flexDirection: 'row',
  183. },
  184. collapseButton: {
  185. borderRadius: 5,
  186. },
  187. collapse: {
  188. color: LogBoxStyle.getTextColor(0.7),
  189. fontSize: 12,
  190. fontWeight: '300',
  191. lineHeight: 20,
  192. marginTop: 0,
  193. paddingHorizontal: 10,
  194. paddingVertical: 5,
  195. },
  196. });
  197. export default LogBoxInspectorStackFrames;