chunk.tsx 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. import {Fragment, useCallback, useEffect, useState} 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. function getTitle({value = {}, alias, type}: Pick<Props, 'alias' | 'type' | 'value'>) {
  17. if (defined(value.title) && typeof value.title !== 'object') {
  18. return value.title;
  19. }
  20. if (!defined(type)) {
  21. return toTitleCase(alias);
  22. }
  23. switch (type) {
  24. case 'app':
  25. return t('App');
  26. case 'device':
  27. return t('Device');
  28. case 'os':
  29. return t('Operating System');
  30. case 'user':
  31. return t('User');
  32. case 'gpu':
  33. return t('Graphics Processing Unit');
  34. case 'runtime':
  35. return t('Runtime');
  36. case 'trace':
  37. return t('Trace Details');
  38. case 'otel':
  39. return t('OpenTelemetry');
  40. case 'unity':
  41. return t('Unity');
  42. case 'memory_info': // Future new value for memory info
  43. case 'Memory Info': // Current value for memory info
  44. return t('Memory Info');
  45. case 'threadpool_info': // Future new value for thread pool info
  46. case 'ThreadPool Info': // Current value for thread pool info
  47. return t('Thread Pool Info');
  48. case 'default':
  49. if (alias === 'state') {
  50. return t('Application State');
  51. }
  52. return toTitleCase(alias);
  53. default:
  54. return toTitleCase(type);
  55. }
  56. }
  57. export function Chunk({group, type, alias, value = {}, event}: Props) {
  58. const [pluginLoading, setPluginLoading] = useState(false);
  59. const syncPlugin = useCallback(() => {
  60. // If we don't have a grouped event we can't sync with plugins.
  61. if (!group) {
  62. return;
  63. }
  64. // Search using `alias` first because old plugins rely on it and type is set to "default"
  65. // e.g. sessionstack
  66. const sourcePlugin =
  67. type === 'default'
  68. ? getSourcePlugin(group.pluginContexts, alias) ||
  69. getSourcePlugin(group.pluginContexts, type)
  70. : getSourcePlugin(group.pluginContexts, type);
  71. if (!sourcePlugin) {
  72. setPluginLoading(false);
  73. return;
  74. }
  75. setPluginLoading(true);
  76. plugins.load(sourcePlugin, () => {
  77. setPluginLoading(false);
  78. });
  79. }, [alias, type, group]);
  80. useEffect(() => {
  81. syncPlugin();
  82. }, [type, group?.id, syncPlugin]);
  83. // if we are currently loading the plugin, just render nothing for now.
  84. if (pluginLoading) {
  85. return null;
  86. }
  87. // we intentionally hide reprocessing context to not imply it was sent by the SDK.
  88. if (alias === 'reprocessing') {
  89. return null;
  90. }
  91. const ContextComponent =
  92. type === 'default'
  93. ? getContextComponent(alias) || getContextComponent(type)
  94. : getContextComponent(type);
  95. const isObjectValueEmpty = Object.values(value).filter(v => defined(v)).length === 0;
  96. // this can happen if the component does not exist
  97. if (!ContextComponent || isObjectValueEmpty) {
  98. return null;
  99. }
  100. return (
  101. <EventDataSection
  102. key={`context-${alias}`}
  103. type={`context-${alias}`}
  104. title={
  105. <Fragment>
  106. {getTitle({value, alias, type})}
  107. {defined(type) && type !== 'default' && alias !== type && (
  108. <small>({alias})</small>
  109. )}
  110. </Fragment>
  111. }
  112. >
  113. <ContextComponent alias={alias} event={event} data={value} />
  114. </EventDataSection>
  115. );
  116. }