focusTabs.tsx 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  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 type {Organization} from 'sentry/types/organization';
  11. import {trackAnalytics} from 'sentry/utils/analytics';
  12. import useActiveReplayTab, {TabKey} from 'sentry/utils/replays/hooks/useActiveReplayTab';
  13. import {useLocation} from 'sentry/utils/useLocation';
  14. import useOrganization from 'sentry/utils/useOrganization';
  15. function getReplayTabs({
  16. isVideoReplay,
  17. organization,
  18. }: {
  19. isVideoReplay: boolean;
  20. organization: Organization;
  21. }): Record<TabKey, ReactNode> {
  22. // For video replays, we hide the console, a11y, trace, and memory tabs
  23. // The console tab isn't useful for video replays (for now); most of the
  24. // useful logging context will come from breadcrumbs
  25. // A11y, trace, and memory aren't applicable for mobile
  26. // Show the console tab if 1) it's a video replay and we have the FF enabled
  27. // or 2) it's not a video replay
  28. const showConsoleTab = isVideoReplay
  29. ? organization.features.includes('session-replay-mobile-network-tab')
  30. : true;
  31. return {
  32. [TabKey.BREADCRUMBS]: t('Breadcrumbs'),
  33. [TabKey.CONSOLE]: showConsoleTab ? t('Console') : null,
  34. [TabKey.NETWORK]: t('Network'),
  35. [TabKey.ERRORS]: t('Errors'),
  36. [TabKey.TRACE]: isVideoReplay ? null : t('Trace'),
  37. [TabKey.A11Y]: isVideoReplay ? null : (
  38. <Fragment>
  39. <Tooltip
  40. isHoverable
  41. title={
  42. <ExternalLink
  43. href="https://developer.mozilla.org/en-US/docs/Learn/Accessibility/What_is_accessibility"
  44. onClick={e => {
  45. e.stopPropagation();
  46. }}
  47. >
  48. {t('What is accessibility?')}
  49. </ExternalLink>
  50. }
  51. >
  52. {t('Accessibility')}
  53. </Tooltip>
  54. <FlexFeatureBadge
  55. type="alpha"
  56. title={t('This feature is available for early adopters and may change')}
  57. />
  58. </Fragment>
  59. ),
  60. [TabKey.MEMORY]: isVideoReplay ? null : t('Memory'),
  61. [TabKey.TAGS]: t('Tags'),
  62. };
  63. }
  64. type Props = {
  65. isVideoReplay: boolean;
  66. className?: string;
  67. };
  68. function FocusTabs({className, isVideoReplay}: Props) {
  69. const organization = useOrganization();
  70. const {pathname, query} = useLocation();
  71. const {getActiveTab, setActiveTab} = useActiveReplayTab({isVideoReplay});
  72. const activeTab = getActiveTab();
  73. const isTabDisabled = (tab: string) => {
  74. return (
  75. tab === TabKey.NETWORK &&
  76. isVideoReplay &&
  77. !organization.features.includes('session-replay-mobile-network-tab')
  78. );
  79. };
  80. return (
  81. <ScrollableTabs className={className} underlined>
  82. {Object.entries(getReplayTabs({organization, isVideoReplay})).map(([tab, label]) =>
  83. label ? (
  84. <ListLink
  85. disabled={isTabDisabled(tab)}
  86. data-test-id={`replay-details-${tab}-btn`}
  87. key={tab}
  88. isActive={() => tab === activeTab}
  89. to={{pathname, query: {...query, t_main: tab}}}
  90. onClick={e => {
  91. e.preventDefault();
  92. setActiveTab(tab);
  93. trackAnalytics('replay.details-tab-changed', {
  94. tab,
  95. organization,
  96. });
  97. }}
  98. >
  99. <Tooltip title={isTabDisabled(tab) ? t('This feature is coming soon') : null}>
  100. {label}
  101. </Tooltip>
  102. </ListLink>
  103. ) : null
  104. )}
  105. </ScrollableTabs>
  106. );
  107. }
  108. const FlexFeatureBadge = styled(FeatureBadge)`
  109. & > span {
  110. display: flex;
  111. }
  112. `;
  113. export default FocusTabs;