focusTabs.tsx 2.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. import {Fragment, ReactNode} from 'react';
  2. import queryString from 'query-string';
  3. import FeatureBadge from 'sentry/components/featureBadge';
  4. import ExternalLink from 'sentry/components/links/externalLink';
  5. import ListLink from 'sentry/components/links/listLink';
  6. import ScrollableTabs from 'sentry/components/replays/scrollableTabs';
  7. import {Tooltip} from 'sentry/components/tooltip';
  8. import {t} from 'sentry/locale';
  9. import type {Organization} from 'sentry/types';
  10. import {trackAnalytics} from 'sentry/utils/analytics';
  11. import useActiveReplayTab, {TabKey} from 'sentry/utils/replays/hooks/useActiveReplayTab';
  12. import {useLocation} from 'sentry/utils/useLocation';
  13. import useOrganization from 'sentry/utils/useOrganization';
  14. function getReplayTabs(organization: Organization): Record<TabKey, ReactNode> {
  15. const hasA11yTab = organization.features.includes('session-replay-a11y-tab');
  16. const hasPerfTab = organization.features.includes('session-replay-trace-table');
  17. return {
  18. [TabKey.CONSOLE]: t('Console'),
  19. [TabKey.NETWORK]: t('Network'),
  20. [TabKey.ERRORS]: (
  21. <Fragment>
  22. {t('Errors')} <FeatureBadge type="new" />
  23. </Fragment>
  24. ),
  25. [TabKey.TRACE]: t('Trace'),
  26. [TabKey.PERF]: hasPerfTab ? (
  27. <Fragment>
  28. {t('Perf')} <FeatureBadge type="alpha" />
  29. </Fragment>
  30. ) : null,
  31. [TabKey.DOM]: t('DOM Events'),
  32. [TabKey.A11Y]: hasA11yTab ? (
  33. <Fragment>
  34. <Tooltip
  35. isHoverable
  36. title={
  37. <ExternalLink href="https://developer.mozilla.org/en-US/docs/Learn/Accessibility/What_is_accessibility">
  38. {t('What is accessibility?')}
  39. </ExternalLink>
  40. }
  41. >
  42. {t('a11y')}
  43. </Tooltip>
  44. <FeatureBadge type="alpha" />
  45. </Fragment>
  46. ) : null,
  47. [TabKey.MEMORY]: t('Memory'),
  48. };
  49. }
  50. type Props = {
  51. className?: string;
  52. };
  53. function FocusTabs({className}: Props) {
  54. const organization = useOrganization();
  55. const {pathname, query} = useLocation();
  56. const {getActiveTab, setActiveTab} = useActiveReplayTab();
  57. const activeTab = getActiveTab();
  58. return (
  59. <ScrollableTabs className={className} underlined>
  60. {Object.entries(getReplayTabs(organization)).map(([tab, label]) =>
  61. label ? (
  62. <ListLink
  63. data-test-id={`replay-details-${tab}-btn`}
  64. key={tab}
  65. isActive={() => tab === activeTab}
  66. to={`${pathname}?${queryString.stringify({...query, t_main: tab})}`}
  67. onClick={e => {
  68. e.preventDefault();
  69. setActiveTab(tab);
  70. trackAnalytics('replay.details-tab-changed', {
  71. tab,
  72. organization,
  73. });
  74. }}
  75. >
  76. {label}
  77. </ListLink>
  78. ) : null
  79. )}
  80. </ScrollableTabs>
  81. );
  82. }
  83. export default FocusTabs;