chunk.tsx 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. import {Component, Fragment} from 'react';
  2. import EventDataSection from 'sentry/components/events/eventDataSection';
  3. import {t} from 'sentry/locale';
  4. import plugins from 'sentry/plugins';
  5. import {Group} from 'sentry/types';
  6. import {Event} from 'sentry/types/event';
  7. import {defined, toTitleCase} from 'sentry/utils';
  8. import {getContextComponent, getSourcePlugin} from './utils';
  9. type Props = {
  10. alias: string;
  11. event: Event;
  12. type: string;
  13. group?: Group;
  14. value?: Record<string, any>;
  15. };
  16. type State = {
  17. isLoading: boolean;
  18. pluginLoading?: boolean;
  19. };
  20. class Chunk extends Component<Props, State> {
  21. state: State = {
  22. isLoading: false,
  23. };
  24. UNSAFE_componentWillMount() {
  25. this.syncPlugin();
  26. }
  27. componentDidUpdate(prevProps: Props) {
  28. if (
  29. prevProps.type !== this.props.type ||
  30. prevProps.group?.id !== this.props.group?.id
  31. ) {
  32. this.syncPlugin();
  33. }
  34. }
  35. syncPlugin() {
  36. const {group, type, alias} = this.props;
  37. // If we don't have a grouped event we can't sync with plugins.
  38. if (!group) {
  39. return;
  40. }
  41. // Search using `alias` first because old plugins rely on it and type is set to "default"
  42. // e.g. sessionstack
  43. const sourcePlugin =
  44. type === 'default'
  45. ? getSourcePlugin(group.pluginContexts, alias) ||
  46. getSourcePlugin(group.pluginContexts, type)
  47. : getSourcePlugin(group.pluginContexts, type);
  48. if (!sourcePlugin) {
  49. this.setState({pluginLoading: false});
  50. return;
  51. }
  52. this.setState(
  53. {
  54. pluginLoading: true,
  55. },
  56. () => {
  57. plugins.load(sourcePlugin, () => {
  58. this.setState({pluginLoading: false});
  59. });
  60. }
  61. );
  62. }
  63. getTitle() {
  64. const {value = {}, alias, type} = this.props;
  65. if (defined(value.title) && typeof value.title !== 'object') {
  66. return value.title;
  67. }
  68. if (!defined(type)) {
  69. return toTitleCase(alias);
  70. }
  71. switch (type) {
  72. case 'app':
  73. return t('App');
  74. case 'device':
  75. return t('Device');
  76. case 'os':
  77. return t('Operating System');
  78. case 'user':
  79. return t('User');
  80. case 'gpu':
  81. return t('Graphics Processing Unit');
  82. case 'runtime':
  83. return t('Runtime');
  84. case 'trace':
  85. return t('Trace Details');
  86. case 'default':
  87. if (alias === 'state') {
  88. return t('Application State');
  89. }
  90. return toTitleCase(alias);
  91. default:
  92. return toTitleCase(type);
  93. }
  94. }
  95. render() {
  96. const {pluginLoading} = this.state;
  97. // if we are currently loading the plugin, just render nothing for now.
  98. if (pluginLoading) {
  99. return null;
  100. }
  101. const {type, alias, value = {}, event} = this.props;
  102. // we intentionally hide reprocessing context to not imply it was sent by the SDK.
  103. if (alias === 'reprocessing') {
  104. return null;
  105. }
  106. const ContextComponent =
  107. type === 'default'
  108. ? getContextComponent(alias) || getContextComponent(type)
  109. : getContextComponent(type);
  110. const isObjectValueEmpty = Object.values(value).filter(v => defined(v)).length === 0;
  111. // this can happen if the component does not exist
  112. if (!ContextComponent || isObjectValueEmpty) {
  113. return null;
  114. }
  115. return (
  116. <EventDataSection
  117. key={`context-${alias}`}
  118. type={`context-${alias}`}
  119. title={
  120. <Fragment>
  121. {this.getTitle()}
  122. {defined(type) && type !== 'default' && alias !== type && (
  123. <small>({alias})</small>
  124. )}
  125. </Fragment>
  126. }
  127. >
  128. <ContextComponent alias={alias} event={event} data={value} />
  129. </EventDataSection>
  130. );
  131. }
  132. }
  133. export default Chunk;