feedbackOnboarding.tsx 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307
  1. import Alert from 'sentry/components/alert';
  2. import ExternalLink from 'sentry/components/links/externalLink';
  3. import {StepType} from 'sentry/components/onboarding/gettingStartedDoc/step';
  4. import type {
  5. DocsParams,
  6. OnboardingConfig,
  7. } from 'sentry/components/onboarding/gettingStartedDoc/types';
  8. import {t, tct} from 'sentry/locale';
  9. export const getFeedbackConfigureDescription = ({
  10. linkConfig,
  11. linkButton,
  12. }: {
  13. linkButton: string;
  14. linkConfig: string;
  15. }) =>
  16. tct(
  17. 'To set up the integration, add the following to your Sentry initialization. There are many options you can pass to the [code:integrations] constructor to customize your form. [break] [break] You can even [linkButton:link the widget to a custom button] if you don’t want to use our auto-injected floating button. Learn more about configuring User Feedback by reading the [linkConfig:configuration docs].',
  18. {
  19. code: <code />,
  20. break: <br />,
  21. linkConfig: <ExternalLink href={linkConfig} />,
  22. linkButton: <ExternalLink href={linkButton} />,
  23. }
  24. );
  25. export const getFeedbackSDKSetupSnippet = ({
  26. importStatement,
  27. dsn,
  28. feedbackOptions,
  29. }: {
  30. dsn: string;
  31. importStatement: string;
  32. feedbackOptions?: {email?: boolean; name?: boolean};
  33. }) =>
  34. `${importStatement}
  35. Sentry.init({
  36. dsn: "${dsn}",
  37. integrations: [
  38. Sentry.feedbackIntegration({
  39. // Additional SDK configuration goes in here, for example:
  40. colorScheme: "system",
  41. ${getFeedbackConfigOptions(feedbackOptions)}}),
  42. ],
  43. });`;
  44. export const getCrashReportApiIntroduction = () =>
  45. t(
  46. 'When a user experiences an error, Sentry provides the ability to collect additional feedback from the user via a form. The user feedback API allows you to collect user feedback while utilizing your own UI for the form. You can use the same programming language you have in your app to send user feedback.'
  47. );
  48. export const getCrashReportInstallDescription = () =>
  49. tct(
  50. 'Sentry needs the error [codeEvent:eventId] to be able to associate the user feedback to the corresponding event. To get the [codeEvent:eventId], you can use [codeBefore:beforeSend] or the return value of the method capturing an event.',
  51. {codeEvent: <code />, codeBefore: <code />}
  52. );
  53. export function FeedbackOnboardingWebApiBanner() {
  54. return (
  55. <Alert type="info" showIcon>
  56. {tct(
  57. `When a user experiences an error, Sentry provides the ability to collect additional feedback. You can use an endpoint in Sentry to submit it. [link:Read our docs] to learn more.`,
  58. {
  59. link: (
  60. <ExternalLink href="https://docs.sentry.io/api/projects/submit-user-feedback/" />
  61. ),
  62. }
  63. )}
  64. </Alert>
  65. );
  66. }
  67. export const CrashReportWebApiOnboarding: OnboardingConfig = {
  68. introduction: () => FeedbackOnboardingWebApiBanner(),
  69. install: () => [],
  70. configure: () => [],
  71. verify: () => [],
  72. nextSteps: () => [],
  73. };
  74. export const getFeedbackConfigOptions = ({
  75. name,
  76. email,
  77. }: {
  78. email?: boolean;
  79. name?: boolean;
  80. } = {}) => {
  81. const options: string[] = [];
  82. if (name) {
  83. options.push('isNameRequired: true,');
  84. }
  85. if (email) {
  86. options.push('isEmailRequired: true,');
  87. }
  88. return options.join('\n');
  89. };
  90. export const getCrashReportModalIntroduction = () =>
  91. t(
  92. 'Collect feedback on your errors by installing our crash-report modal. This allows users to submit feedback after they experience an error via an automatic modal that pops up after an error occurs. The default modal will prompt the user for their name, email address, and description of what occurred.'
  93. );
  94. export const getCrashReportModalInstallDescriptionJavaScript = () =>
  95. tct(
  96. 'You can collect feedback at the time the event is sent, using [code:beforeSend].',
  97. {code: <code />}
  98. );
  99. export const getCrashReportModalConfigDescription = ({link}: {link: string}) =>
  100. tct(
  101. 'There are many options you can pass to the [code:Sentry.showReportDialog] call to customize your form. Learn more about configuring the modal by reading the [link:configuration docs].',
  102. {code: <code />, link: <ExternalLink href={link} />}
  103. );
  104. const getCrashReportModalSnippetJavaScript = params => [
  105. {
  106. code: [
  107. {
  108. label: 'HTML',
  109. value: 'html',
  110. language: 'html',
  111. code: `<script>
  112. Sentry.init({
  113. dsn: "${params.dsn}",
  114. beforeSend(event, hint) {
  115. // Check if it is an exception, and if so, show the report dialog
  116. if (event.exception && event.event_id) {
  117. Sentry.showReportDialog({ eventId: event.event_id });
  118. }
  119. return event;
  120. },
  121. });
  122. </script>`,
  123. },
  124. ],
  125. },
  126. ];
  127. export const getCrashReportJavaScriptInstallStep = params => [
  128. {
  129. type: StepType.INSTALL,
  130. description: getCrashReportModalInstallDescriptionJavaScript(),
  131. configurations: getCrashReportModalSnippetJavaScript(params),
  132. },
  133. ];
  134. export function getCrashReportSDKInstallFirstStep(params: DocsParams) {
  135. const dataLoaded =
  136. params.sourcePackageRegistries && !params.sourcePackageRegistries.isLoading;
  137. const version =
  138. (dataLoaded &&
  139. params.sourcePackageRegistries.data?.['sentry.javascript.browser'].version) ??
  140. '';
  141. const hash =
  142. (dataLoaded &&
  143. params.sourcePackageRegistries.data?.['sentry.javascript.browser'].files[
  144. 'bundle.min.js'
  145. ].checksums['sha384-base64']) ??
  146. '';
  147. return {
  148. description: t('Make sure you have the JavaScript SDK available:'),
  149. code: [
  150. {
  151. label: 'HTML',
  152. value: 'html',
  153. language: 'html',
  154. code: `<script
  155. src="https://browser.sentry-cdn.com/${version}/bundle.min.js"
  156. integrity="sha384-${hash}"
  157. crossorigin="anonymous"
  158. ></script>`,
  159. },
  160. ],
  161. };
  162. }
  163. const getGenericScript = params => [
  164. {
  165. label: 'HTML',
  166. value: 'html',
  167. language: 'html',
  168. code: `<script>
  169. Sentry.init({ dsn: "${params.dsn}" });
  170. Sentry.showReportDialog({
  171. eventId: "{{ event_id }}",
  172. });
  173. </script>`,
  174. },
  175. ];
  176. export const getCrashReportGenericInstallStep = params => [
  177. {
  178. type: StepType.INSTALL,
  179. configurations: [
  180. getCrashReportSDKInstallFirstStep(params),
  181. {
  182. description: tct(
  183. 'You will then need to call [codeShow:showReportDialog] and pass in the generated event ID. This event ID is returned from all calls to [codeEvent:CaptureEvent] and [codeException:CaptureException]. There is also a function called [codeLast:LastEventId] that returns the ID of the most recently sent event.',
  184. {
  185. codeShow: <code />,
  186. codeEvent: <code />,
  187. codeException: <code />,
  188. codeLast: <code />,
  189. }
  190. ),
  191. code: getGenericScript(params),
  192. },
  193. ],
  194. },
  195. ];
  196. export const getCrashReportBackendInstallStep = params => [
  197. {
  198. type: StepType.INSTALL,
  199. configurations: [
  200. getCrashReportSDKInstallFirstStep(params),
  201. {
  202. description: tct(
  203. 'You will then need to call [codeShow:showReportDialog] and pass in the generated event ID. This event ID is returned from all calls to [codeEvent:capture_event] and [codeException:capture_exception]. There is also a function called [codeLast:last_event_id] that returns the ID of the most recently sent event.',
  204. {
  205. codeShow: <code />,
  206. codeEvent: <code />,
  207. codeException: <code />,
  208. codeLast: <code />,
  209. }
  210. ),
  211. code: getGenericScript(params),
  212. },
  213. ],
  214. },
  215. ];
  216. export function getCrashReportSDKInstallFirstStepRails(params: DocsParams) {
  217. const dataLoaded =
  218. params.sourcePackageRegistries && !params.sourcePackageRegistries.isLoading;
  219. const version =
  220. (dataLoaded &&
  221. params.sourcePackageRegistries.data?.['sentry.javascript.browser'].version) ??
  222. '';
  223. const hash =
  224. (dataLoaded &&
  225. params.sourcePackageRegistries.data?.['sentry.javascript.browser'].files[
  226. 'bundle.min.js'
  227. ].checksums['sha384-base64']) ??
  228. '';
  229. return {
  230. description: t('Make sure you have the JavaScript SDK available:'),
  231. code: [
  232. {
  233. label: 'ERB',
  234. value: 'erb',
  235. language: 'erb',
  236. code: `<script
  237. src="https://browser.sentry-cdn.com/${version}/bundle.min.js"
  238. integrity="sha384-${hash}"
  239. crossorigin="anonymous"
  240. ></script>`,
  241. },
  242. ],
  243. };
  244. }
  245. export const getCrashReportPHPInstallStep = params => [
  246. {
  247. type: StepType.INSTALL,
  248. configurations: [
  249. {
  250. description: tct('This function php returns the last [code:eventId]:', {
  251. code: <code />,
  252. }),
  253. code: [
  254. {
  255. label: 'PHP',
  256. value: 'php',
  257. language: 'php',
  258. code: `\Sentry\SentrySdk::getCurrentHub()->getLastEventId();`,
  259. },
  260. ],
  261. },
  262. getCrashReportSDKInstallFirstStep(params),
  263. {
  264. description: t(
  265. 'Depending on how you render your templates, the example would be in a simple php file:'
  266. ),
  267. code: [
  268. {
  269. label: 'HTML',
  270. value: 'html',
  271. language: 'html',
  272. code: `<?php if (\Sentry\SentrySdk::getCurrentHub()->getLastEventId()) { ?>
  273. <script>
  274. Sentry.init({ dsn: "${params.dsn}" });
  275. Sentry.showReportDialog({
  276. eventId:
  277. "<?php echo \Sentry\SentrySdk::getCurrentHub()->getLastEventId(); ?>",
  278. });
  279. </script>
  280. <?php } ?>`,
  281. },
  282. ],
  283. },
  284. ],
  285. },
  286. ];