domainViewHeader.tsx 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. import {Fragment} from 'react';
  2. import {Breadcrumbs, type Crumb} from 'sentry/components/breadcrumbs';
  3. import ButtonBar from 'sentry/components/buttonBar';
  4. import FeedbackWidgetButton from 'sentry/components/feedback/widget/feedbackWidgetButton';
  5. import * as Layout from 'sentry/components/layouts/thirds';
  6. import {TabList, Tabs} from 'sentry/components/tabs';
  7. import {useNavigate} from 'sentry/utils/useNavigate';
  8. import useOrganization from 'sentry/utils/useOrganization';
  9. import {useModuleTitles} from 'sentry/views/insights/common/utils/useModuleTitle';
  10. import {
  11. type RoutableModuleNames,
  12. useModuleURLBuilder,
  13. } from 'sentry/views/insights/common/utils/useModuleURL';
  14. import {
  15. DOMAIN_VIEW_BASE_TITLE,
  16. OVERVIEW_PAGE_TITLE,
  17. } from 'sentry/views/insights/pages/settings';
  18. import type {ModuleName} from 'sentry/views/insights/types';
  19. export type Props = {
  20. domainBaseUrl: string;
  21. domainTitle: string;
  22. headerTitle: React.ReactNode;
  23. modules: ModuleName[];
  24. selectedModule: ModuleName | undefined;
  25. additionalBreadCrumbs?: Crumb[];
  26. additonalHeaderActions?: React.ReactNode;
  27. hideDefaultTabs?: boolean;
  28. tabs?: {onTabChange: (key: string) => void; tabList: React.ReactNode; value: string};
  29. };
  30. type Tab = {
  31. key: string;
  32. label: string;
  33. };
  34. export function DomainViewHeader({
  35. modules,
  36. headerTitle,
  37. domainTitle,
  38. selectedModule,
  39. hideDefaultTabs,
  40. additonalHeaderActions,
  41. additionalBreadCrumbs = [],
  42. domainBaseUrl,
  43. tabs,
  44. }: Props) {
  45. const navigate = useNavigate();
  46. const organization = useOrganization();
  47. const moduleURLBuilder = useModuleURLBuilder();
  48. const moduleTitles = useModuleTitles();
  49. const baseCrumbs: Crumb[] = [
  50. {
  51. label: DOMAIN_VIEW_BASE_TITLE,
  52. to: undefined, // There is no base /performance/ page
  53. preservePageFilters: true,
  54. },
  55. {
  56. label: domainTitle,
  57. to: domainBaseUrl,
  58. preservePageFilters: true,
  59. },
  60. {
  61. label: selectedModule ? moduleTitles[selectedModule] : OVERVIEW_PAGE_TITLE,
  62. to: selectedModule
  63. ? `${moduleURLBuilder(selectedModule as RoutableModuleNames)}/`
  64. : domainBaseUrl,
  65. preservePageFilters: true,
  66. },
  67. ...additionalBreadCrumbs,
  68. ];
  69. const showModuleTabs = organization.features.includes('insights-entry-points');
  70. const defaultHandleTabChange = (key: ModuleName | typeof OVERVIEW_PAGE_TITLE) => {
  71. if (key === selectedModule || (key === OVERVIEW_PAGE_TITLE && !module)) {
  72. return;
  73. }
  74. if (!key) {
  75. return;
  76. }
  77. if (key === OVERVIEW_PAGE_TITLE) {
  78. navigate(domainBaseUrl);
  79. return;
  80. }
  81. navigate(`${moduleURLBuilder(key as RoutableModuleNames)}/`);
  82. };
  83. const tabValue =
  84. hideDefaultTabs && tabs?.value ? tabs.value : selectedModule ?? OVERVIEW_PAGE_TITLE;
  85. const handleTabChange =
  86. hideDefaultTabs && tabs ? tabs.onTabChange : defaultHandleTabChange;
  87. const tabList: Tab[] = [
  88. {
  89. key: OVERVIEW_PAGE_TITLE,
  90. label: OVERVIEW_PAGE_TITLE,
  91. },
  92. ];
  93. if (showModuleTabs) {
  94. tabList.push(
  95. ...modules.map(moduleName => ({
  96. key: moduleName,
  97. label: moduleTitles[moduleName],
  98. }))
  99. );
  100. }
  101. return (
  102. <Fragment>
  103. <Layout.Header>
  104. <Layout.HeaderContent>
  105. <Breadcrumbs crumbs={baseCrumbs} />
  106. <Layout.Title>{headerTitle}</Layout.Title>
  107. </Layout.HeaderContent>
  108. <Layout.HeaderActions>
  109. <ButtonBar gap={1}>
  110. {additonalHeaderActions}
  111. <FeedbackWidgetButton />
  112. </ButtonBar>
  113. </Layout.HeaderActions>
  114. <Tabs value={tabValue} onChange={handleTabChange}>
  115. {!hideDefaultTabs && (
  116. <TabList hideBorder>
  117. {tabList.map(tab => (
  118. <TabList.Item key={tab.key}>{tab.label}</TabList.Item>
  119. ))}
  120. </TabList>
  121. )}
  122. {hideDefaultTabs && tabs && tabs.tabList}
  123. </Tabs>
  124. </Layout.Header>
  125. </Fragment>
  126. );
  127. }