utils.tsx 4.2 KB

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