utils.tsx 4.6 KB

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