focusTabs.tsx 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. import {Fragment, ReactNode} from 'react';
  2. import styled from '@emotion/styled';
  3. import queryString from 'query-string';
  4. import FeatureBadge from 'sentry/components/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';
  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(organization: Organization): Record<TabKey, ReactNode> {
  16. // The new Accessibility tab:
  17. const hasA11yTab = organization.features.includes('session-replay-a11y-tab');
  18. // The new trace table inside Breadcrumb items:
  19. const hasTraceTable = organization.features.includes('session-replay-trace-table');
  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]: hasTraceTable ? null : t('Trace'),
  26. [TabKey.PERF]: null,
  27. [TabKey.A11Y]: hasA11yTab ? (
  28. <Fragment>
  29. <Tooltip
  30. isHoverable
  31. title={
  32. <ExternalLink
  33. href="https://developer.mozilla.org/en-US/docs/Learn/Accessibility/What_is_accessibility"
  34. onClick={e => {
  35. e.stopPropagation();
  36. }}
  37. >
  38. {t('What is accessibility?')}
  39. </ExternalLink>
  40. }
  41. >
  42. {t('Accessibility')}
  43. </Tooltip>
  44. <FlexFeatureBadge
  45. type="alpha"
  46. title={t('This feature is available for early adopters and may change')}
  47. />
  48. </Fragment>
  49. ) : null,
  50. [TabKey.MEMORY]: t('Memory'),
  51. [TabKey.TAGS]: t('Tags'),
  52. };
  53. }
  54. type Props = {
  55. className?: string;
  56. };
  57. function FocusTabs({className}: Props) {
  58. const organization = useOrganization();
  59. const {pathname, query} = useLocation();
  60. const {getActiveTab, setActiveTab} = useActiveReplayTab();
  61. const activeTab = getActiveTab();
  62. return (
  63. <ScrollableTabs className={className} underlined>
  64. {Object.entries(getReplayTabs(organization)).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}?${queryString.stringify({...query, t_main: tab})}`}
  71. onClick={e => {
  72. e.preventDefault();
  73. setActiveTab(tab);
  74. trackAnalytics('replay.details-tab-changed', {
  75. tab,
  76. organization,
  77. });
  78. }}
  79. >
  80. {label}
  81. </ListLink>
  82. ) : null
  83. )}
  84. </ScrollableTabs>
  85. );
  86. }
  87. const FlexFeatureBadge = styled(FeatureBadge)`
  88. & > span {
  89. display: flex;
  90. }
  91. `;
  92. export default FocusTabs;