focusTabs.tsx 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  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.BREADCRUMBS]: t('Breadcrumbs'),
  19. [TabKey.CONSOLE]: t('Console'),
  20. [TabKey.NETWORK]: t('Network'),
  21. [TabKey.ERRORS]: (
  22. <Fragment>
  23. {t('Errors')} <FeatureBadge type="new" />
  24. </Fragment>
  25. ),
  26. [TabKey.TRACE]: t('Trace'),
  27. [TabKey.PERF]: hasPerfTab ? (
  28. <Fragment>
  29. {t('Perf')} <FeatureBadge type="alpha" />
  30. </Fragment>
  31. ) : null,
  32. [TabKey.DOM]: t('DOM Events'),
  33. [TabKey.A11Y]: hasA11yTab ? (
  34. <Fragment>
  35. <Tooltip
  36. isHoverable
  37. title={
  38. <ExternalLink href="https://developer.mozilla.org/en-US/docs/Learn/Accessibility/What_is_accessibility">
  39. {t('What is accessibility?')}
  40. </ExternalLink>
  41. }
  42. >
  43. {t('a11y')}
  44. </Tooltip>
  45. <FeatureBadge type="alpha" />
  46. </Fragment>
  47. ) : null,
  48. [TabKey.MEMORY]: t('Memory'),
  49. [TabKey.TAGS]: t('Tags'),
  50. };
  51. }
  52. type Props = {
  53. className?: string;
  54. };
  55. function FocusTabs({className}: Props) {
  56. const organization = useOrganization();
  57. const {pathname, query} = useLocation();
  58. const {getActiveTab, setActiveTab} = useActiveReplayTab();
  59. const activeTab = getActiveTab();
  60. return (
  61. <ScrollableTabs className={className} underlined>
  62. {Object.entries(getReplayTabs(organization)).map(([tab, label]) =>
  63. label ? (
  64. <ListLink
  65. data-test-id={`replay-details-${tab}-btn`}
  66. key={tab}
  67. isActive={() => tab === activeTab}
  68. to={`${pathname}?${queryString.stringify({...query, t_main: tab})}`}
  69. onClick={e => {
  70. e.preventDefault();
  71. setActiveTab(tab);
  72. trackAnalytics('replay.details-tab-changed', {
  73. tab,
  74. organization,
  75. });
  76. }}
  77. >
  78. {label}
  79. </ListLink>
  80. ) : null
  81. )}
  82. </ScrollableTabs>
  83. );
  84. }
  85. export default FocusTabs;