index.tsx 2.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. import {useCallback, useEffect, useMemo, useRef, useState} from 'react';
  2. import styled from '@emotion/styled';
  3. import {Button} from 'sentry/components/button';
  4. import ButtonBar from 'sentry/components/buttonBar';
  5. import LoadingIndicator from 'sentry/components/loadingIndicator';
  6. import ThemeAndStyleProvider from 'sentry/components/themeAndStyleProvider';
  7. import {t} from 'sentry/locale';
  8. import useApi from 'sentry/utils/useApi';
  9. type Props = {
  10. hash?: boolean | string;
  11. };
  12. const platformDocsMapping = {
  13. 'javascript-nextjs':
  14. 'https://docs.sentry.io/platforms/javascript/guides/nextjs/#verify',
  15. 'react-native': 'https://docs.sentry.io/platforms/react-native/#verify',
  16. cordova: 'https://docs.sentry.io/platforms/javascript/guides/cordova/#verify',
  17. 'javascript-electron':
  18. 'https://docs.sentry.io/platforms/javascript/guides/electron/#verify',
  19. };
  20. function SetupWizard({hash = false}: Props) {
  21. const api = useApi();
  22. const closeTimeoutRef = useRef<number | undefined>(undefined);
  23. const [finished, setFinished] = useState(false);
  24. useEffect(() => {
  25. return () => {
  26. if (closeTimeoutRef.current) {
  27. window.clearTimeout(closeTimeoutRef.current);
  28. }
  29. };
  30. });
  31. useEffect(() => {
  32. return () => {
  33. window.clearTimeout(closeTimeoutRef.current);
  34. };
  35. });
  36. const checkFinished = useCallback(async () => {
  37. try {
  38. await api.requestPromise(`/wizard/${hash}/`);
  39. } catch {
  40. setFinished(true);
  41. window.clearTimeout(closeTimeoutRef.current);
  42. closeTimeoutRef.current = window.setTimeout(() => window.close(), 10000);
  43. }
  44. }, [api, hash]);
  45. useEffect(() => {
  46. const pollingInterval = window.setInterval(checkFinished, 1000);
  47. return () => window.clearInterval(pollingInterval);
  48. }, [checkFinished]);
  49. // outside of route context
  50. const docsLink = useMemo(() => {
  51. const urlParams = new URLSearchParams(location.search);
  52. const projectPlatform = urlParams.get('project_platform');
  53. return platformDocsMapping[projectPlatform || ''] || 'https://docs.sentry.io/';
  54. }, []);
  55. return (
  56. <ThemeAndStyleProvider>
  57. <div className="container">
  58. {!finished ? (
  59. <LoadingIndicator style={{margin: '2em auto'}}>
  60. <div className="row">
  61. <h5>{t('Waiting for wizard to connect')}</h5>
  62. </div>
  63. </LoadingIndicator>
  64. ) : (
  65. <div className="row">
  66. <h5>{t('Return to your terminal to complete your setup')}</h5>
  67. <MinWidthButtonBar gap={1}>
  68. <Button priority="primary" to="/">
  69. {t('View Issues')}
  70. </Button>
  71. <Button href={docsLink} external>
  72. {t('See Docs')}
  73. </Button>
  74. </MinWidthButtonBar>
  75. </div>
  76. )}
  77. </div>
  78. </ThemeAndStyleProvider>
  79. );
  80. }
  81. const MinWidthButtonBar = styled(ButtonBar)`
  82. width: min-content;
  83. margin-top: 20px;
  84. `;
  85. export default SetupWizard;