focusTabs.tsx 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. import type {ReactNode} from 'react';
  2. import {Fragment} from 'react';
  3. import styled from '@emotion/styled';
  4. import FeatureBadge from 'sentry/components/badge/featureBadge';
  5. import ExternalLink from 'sentry/components/links/externalLink';
  6. import ListLink from 'sentry/components/links/listLink';
  7. import ScrollableTabs from 'sentry/components/replays/scrollableTabs';
  8. import {Tooltip} from 'sentry/components/tooltip';
  9. import {t} from 'sentry/locale';
  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({
  15. isVideoReplay,
  16. }: {
  17. isVideoReplay: boolean;
  18. }): Record<TabKey, ReactNode> {
  19. // For video replays, we hide the a11y and memory tabs (not applicable for mobile)
  20. return {
  21. [TabKey.BREADCRUMBS]: t('Breadcrumbs'),
  22. [TabKey.CONSOLE]: t('Console'),
  23. [TabKey.NETWORK]: t('Network'),
  24. [TabKey.ERRORS]: t('Errors'),
  25. [TabKey.TRACE]: t('Trace'),
  26. [TabKey.A11Y]: isVideoReplay ? null : (
  27. <Fragment>
  28. <Tooltip
  29. isHoverable
  30. title={
  31. <ExternalLink
  32. href="https://developer.mozilla.org/en-US/docs/Learn/Accessibility/What_is_accessibility"
  33. onClick={e => {
  34. e.stopPropagation();
  35. }}
  36. >
  37. {t('What is accessibility?')}
  38. </ExternalLink>
  39. }
  40. >
  41. {t('Accessibility')}
  42. </Tooltip>
  43. <FlexFeatureBadge
  44. type="alpha"
  45. title={t('This feature is available for early adopters and may change')}
  46. />
  47. </Fragment>
  48. ),
  49. [TabKey.MEMORY]: isVideoReplay ? null : t('Memory'),
  50. [TabKey.TAGS]: t('Tags'),
  51. };
  52. }
  53. type Props = {
  54. isVideoReplay: boolean;
  55. className?: string;
  56. };
  57. function FocusTabs({className, isVideoReplay}: Props) {
  58. const organization = useOrganization();
  59. const {pathname, query} = useLocation();
  60. const {getActiveTab, setActiveTab} = useActiveReplayTab({isVideoReplay});
  61. const activeTab = getActiveTab();
  62. return (
  63. <ScrollableTabs className={className} underlined>
  64. {Object.entries(getReplayTabs({isVideoReplay})).map(([tab, label]) =>
  65. label ? (
  66. <ListLink
  67. data-test-id={`replay-details-${tab}-btn`}
  68. key={tab}
  69. isActive={() => tab === activeTab}
  70. to={{pathname, query: {...query, t_main: tab}}}
  71. onClick={e => {
  72. e.preventDefault();
  73. setActiveTab(tab);
  74. trackAnalytics('replay.details-tab-changed', {
  75. tab,
  76. organization,
  77. mobile: isVideoReplay,
  78. });
  79. }}
  80. >
  81. {label}
  82. </ListLink>
  83. ) : null
  84. )}
  85. </ScrollableTabs>
  86. );
  87. }
  88. const FlexFeatureBadge = styled(FeatureBadge)`
  89. & > span {
  90. display: flex;
  91. }
  92. `;
  93. export default FocusTabs;