projectEventRedirect.tsx 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  1. import {Component} from 'react';
  2. import {RouteComponentProps} from 'react-router';
  3. import DetailedError from 'app/components/errors/detailedError';
  4. import {t} from 'app/locale';
  5. import {PageContent} from 'app/styles/organization';
  6. type Props = RouteComponentProps<{}, {}>;
  7. type State = {
  8. error: string | null;
  9. };
  10. /**
  11. * This component performs a client-side redirect to Event Details given only
  12. * an event ID (which normally additionally requires the event's Issue/Group ID).
  13. * It does this by using an XHR against the identically-named ProjectEventRedirect
  14. * _Django_ view, which responds with a 302 with the Location of the corresponding
  15. * Event Details page (if it exists).
  16. *
  17. * See:
  18. * https://github.com/getsentry/sentry/blob/824c03089907ad22a9282303a5eaca33989ce481/src/sentry/web/urls.py#L578
  19. */
  20. class ProjectEventRedirect extends Component<Props, State> {
  21. state: State = {
  22. error: null,
  23. };
  24. componentDidMount() {
  25. const {router} = this.props;
  26. // This presumes that _this_ React view/route is only reachable at
  27. // /:org/:project/events/:eventId (the same URL which serves the ProjectEventRedirect
  28. // Django view).
  29. const endpoint = router.location.pathname;
  30. // Use XmlHttpRequest directly instead of our client API helper (fetch),
  31. // because you can't reach the underlying XHR via $.ajax, and we need
  32. // access to `xhr.responseURL`.
  33. //
  34. // TODO(epurkhiser): We can likely replace tihs with fetch
  35. const xhr = new XMLHttpRequest();
  36. // Hitting this endpoint will return a 302 with a new location, which
  37. // the XHR will follow and make a _second_ request. Using HEAD instead
  38. // of GET returns an empty response instead of the entire HTML content.
  39. xhr.open('HEAD', endpoint);
  40. xhr.send();
  41. xhr.onload = () => {
  42. if (xhr.status === 404) {
  43. this.setState({error: t('Could not find an issue for the provided event id')});
  44. return;
  45. }
  46. // responseURL is the URL of the document the browser ultimately loaded,
  47. // after following any redirects. It _should_ be the page we're trying
  48. // to reach; use the router to go there.
  49. // Use `replace` so that hitting the browser back button will skip all
  50. // this redirect business.
  51. router.replace(xhr.responseURL);
  52. };
  53. xhr.onerror = () => {
  54. this.setState({error: t('Could not load the requested event')});
  55. };
  56. }
  57. render() {
  58. return this.state.error ? (
  59. <DetailedError
  60. heading={t('Not found')}
  61. message={this.state.error}
  62. hideSupportLinks
  63. />
  64. ) : (
  65. <PageContent />
  66. );
  67. }
  68. }
  69. export default ProjectEventRedirect;