focusTabs.tsx 3.9 KB

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