focusTabs.tsx 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  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/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';
  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(organization: Organization): Record<TabKey, ReactNode> {
  17. // The new trace table inside Breadcrumb items:
  18. const hasTraceTable = organization.features.includes('session-replay-trace-table');
  19. return {
  20. [TabKey.BREADCRUMBS]: t('Breadcrumbs'),
  21. [TabKey.CONSOLE]: t('Console'),
  22. [TabKey.NETWORK]: t('Network'),
  23. [TabKey.ERRORS]: t('Errors'),
  24. [TabKey.TRACE]: hasTraceTable ? null : t('Trace'),
  25. [TabKey.PERF]: null,
  26. [TabKey.A11Y]: (
  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]: t('Memory'),
  50. [TabKey.TAGS]: t('Tags'),
  51. };
  52. }
  53. type Props = {
  54. className?: string;
  55. };
  56. function FocusTabs({className}: Props) {
  57. const organization = useOrganization();
  58. const {pathname, query} = useLocation();
  59. const {getActiveTab, setActiveTab} = useActiveReplayTab();
  60. const activeTab = getActiveTab();
  61. return (
  62. <ScrollableTabs className={className} underlined>
  63. {Object.entries(getReplayTabs(organization)).map(([tab, label]) =>
  64. label ? (
  65. <ListLink
  66. data-test-id={`replay-details-${tab}-btn`}
  67. key={tab}
  68. isActive={() => tab === activeTab}
  69. to={`${pathname}?${queryString.stringify({...query, t_main: tab})}`}
  70. onClick={e => {
  71. e.preventDefault();
  72. setActiveTab(tab);
  73. trackAnalytics('replay.details-tab-changed', {
  74. tab,
  75. organization,
  76. });
  77. }}
  78. >
  79. {label}
  80. </ListLink>
  81. ) : null
  82. )}
  83. </ScrollableTabs>
  84. );
  85. }
  86. const FlexFeatureBadge = styled(FeatureBadge)`
  87. & > span {
  88. display: flex;
  89. }
  90. `;
  91. export default FocusTabs;