utils.tsx 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. import {Fragment} from 'react';
  2. import styled from '@emotion/styled';
  3. import startCase from 'lodash/startCase';
  4. import moment from 'moment-timezone';
  5. import ContextData from 'sentry/components/contextData';
  6. import {t} from 'sentry/locale';
  7. import plugins from 'sentry/plugins';
  8. import {space} from 'sentry/styles/space';
  9. import {Event, KeyValueListData} from 'sentry/types';
  10. import {defined} from 'sentry/utils';
  11. import {AppEventContext} from './app';
  12. import {BrowserEventContext} from './browser';
  13. import {DefaultContext} from './default';
  14. import {DeviceEventContext} from './device';
  15. import {GPUEventContext} from './gpu';
  16. import {MemoryInfoEventContext} from './memoryInfo';
  17. import {OperatingSystemEventContext} from './operatingSystem';
  18. import {ProfileEventContext} from './profile';
  19. import {ReduxContext} from './redux';
  20. import {RuntimeEventContext} from './runtime';
  21. import {StateEventContext} from './state';
  22. import {ThreadPoolInfoEventContext} from './threadPoolInfo';
  23. import {TraceEventContext} from './trace';
  24. import {UnityEventContext} from './unity';
  25. import {UserEventContext} from './user';
  26. const CONTEXT_TYPES = {
  27. default: DefaultContext,
  28. app: AppEventContext,
  29. device: DeviceEventContext,
  30. memory_info: MemoryInfoEventContext,
  31. browser: BrowserEventContext,
  32. os: OperatingSystemEventContext,
  33. unity: UnityEventContext,
  34. runtime: RuntimeEventContext,
  35. user: UserEventContext,
  36. gpu: GPUEventContext,
  37. trace: TraceEventContext,
  38. threadpool_info: ThreadPoolInfoEventContext,
  39. state: StateEventContext,
  40. profile: ProfileEventContext,
  41. // 'redux.state' will be replaced with more generic context called 'state'
  42. 'redux.state': ReduxContext,
  43. // 'ThreadPool Info' will be replaced with 'threadpool_info' but
  44. // we want to keep it here for now so it works for existing versions
  45. 'ThreadPool Info': ThreadPoolInfoEventContext,
  46. // 'Memory Info' will be replaced with 'memory_info' but
  47. // we want to keep it here for now so it works for existing versions
  48. 'Memory Info': MemoryInfoEventContext,
  49. };
  50. export function getContextComponent(type: string) {
  51. return CONTEXT_TYPES[type] || plugins.contexts[type] || CONTEXT_TYPES.default;
  52. }
  53. export function getSourcePlugin(pluginContexts: Array<any>, contextType: string) {
  54. if (CONTEXT_TYPES[contextType]) {
  55. return null;
  56. }
  57. for (const plugin of pluginContexts) {
  58. if (plugin.contexts.indexOf(contextType) >= 0) {
  59. return plugin;
  60. }
  61. }
  62. return null;
  63. }
  64. export function getRelativeTimeFromEventDateCreated(
  65. eventDateCreated: string,
  66. timestamp?: string,
  67. showTimestamp = true
  68. ) {
  69. if (!defined(timestamp)) {
  70. return timestamp;
  71. }
  72. const dateTime = moment(timestamp);
  73. if (!dateTime.isValid()) {
  74. return timestamp;
  75. }
  76. const relativeTime = `(${dateTime.from(eventDateCreated, true)} ${t(
  77. 'before this event'
  78. )})`;
  79. if (!showTimestamp) {
  80. return <RelativeTime>{relativeTime}</RelativeTime>;
  81. }
  82. return (
  83. <Fragment>
  84. {timestamp}
  85. <RelativeTime>{relativeTime}</RelativeTime>
  86. </Fragment>
  87. );
  88. }
  89. export function getKnownData<Data, DataType>({
  90. data,
  91. knownDataTypes,
  92. meta,
  93. raw,
  94. onGetKnownDataDetails,
  95. }: {
  96. data: Data;
  97. knownDataTypes: string[];
  98. onGetKnownDataDetails: (props: {data: Data; type: DataType}) =>
  99. | {
  100. subject: string;
  101. value?: React.ReactNode;
  102. }
  103. | undefined;
  104. meta?: Record<any, any>;
  105. raw?: boolean;
  106. }): KeyValueListData {
  107. const filteredTypes = knownDataTypes.filter(knownDataType => {
  108. if (
  109. typeof data[knownDataType] !== 'number' &&
  110. typeof data[knownDataType] !== 'boolean' &&
  111. !data[knownDataType]
  112. ) {
  113. return !!meta?.[knownDataType];
  114. }
  115. return true;
  116. });
  117. return filteredTypes
  118. .map(type => {
  119. const knownDataDetails = onGetKnownDataDetails({
  120. data,
  121. type: type as unknown as DataType,
  122. });
  123. if (!knownDataDetails) {
  124. return null;
  125. }
  126. return {
  127. key: type,
  128. ...knownDataDetails,
  129. value: raw ? (
  130. knownDataDetails.value
  131. ) : (
  132. <ContextData
  133. data={knownDataDetails.value}
  134. meta={meta?.[type]}
  135. withAnnotatedText
  136. />
  137. ),
  138. };
  139. })
  140. .filter(defined);
  141. }
  142. export function getUnknownData({
  143. allData,
  144. knownKeys,
  145. meta,
  146. }: {
  147. allData: Record<string, any>;
  148. knownKeys: string[];
  149. meta?: NonNullable<Event['_meta']>[keyof Event['_meta']];
  150. }): KeyValueListData {
  151. return Object.entries(allData)
  152. .filter(
  153. ([key]) =>
  154. key !== 'type' &&
  155. key !== 'title' &&
  156. !knownKeys.includes(key) &&
  157. (typeof allData[key] !== 'number' && !allData[key] ? !!meta?.[key]?.[''] : true)
  158. )
  159. .map(([key, value]) => ({
  160. key,
  161. value,
  162. subject: startCase(key),
  163. meta: meta?.[key]?.[''],
  164. }));
  165. }
  166. const RelativeTime = styled('span')`
  167. color: ${p => p.theme.subText};
  168. margin-left: ${space(0.5)};
  169. `;