domainViewHeader.tsx 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  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 {t} from 'sentry/locale';
  8. import type {Organization} from 'sentry/types/organization';
  9. import {useNavigate} from 'sentry/utils/useNavigate';
  10. import useOrganization from 'sentry/utils/useOrganization';
  11. import {
  12. type RoutableModuleNames,
  13. useModuleURLBuilder,
  14. } from 'sentry/views/insights/common/utils/useModuleURL';
  15. import {OVERVIEW_PAGE_TITLE} from 'sentry/views/insights/pages/settings';
  16. import {isModuleEnabled} from 'sentry/views/insights/pages/utils';
  17. import {MODULE_TITLES} from 'sentry/views/insights/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 baseCrumbs: Crumb[] = [
  49. {
  50. label: t('Performance'),
  51. to: undefined, // There is no base /performance/ page
  52. preservePageFilters: true,
  53. },
  54. {
  55. label: domainTitle,
  56. to: domainBaseUrl,
  57. preservePageFilters: true,
  58. },
  59. {
  60. label: selectedModule ? MODULE_TITLES[selectedModule] : OVERVIEW_PAGE_TITLE,
  61. to: `${moduleURLBuilder(selectedModule as RoutableModuleNames)}/`,
  62. preservePageFilters: true,
  63. },
  64. ...additionalBreadCrumbs,
  65. ];
  66. const filteredModules = filterEnabledModules(modules, organization);
  67. const defaultHandleTabChange = (key: ModuleName | typeof OVERVIEW_PAGE_TITLE) => {
  68. if (key === selectedModule || (key === OVERVIEW_PAGE_TITLE && !module)) {
  69. return;
  70. }
  71. if (!key) {
  72. return;
  73. }
  74. if (key === OVERVIEW_PAGE_TITLE) {
  75. navigate(domainBaseUrl);
  76. return;
  77. }
  78. navigate(`${moduleURLBuilder(key as RoutableModuleNames)}/`);
  79. };
  80. const tabValue =
  81. hideDefaultTabs && tabs?.value ? tabs.value : selectedModule ?? OVERVIEW_PAGE_TITLE;
  82. const handleTabChange =
  83. hideDefaultTabs && tabs ? tabs.onTabChange : defaultHandleTabChange;
  84. const tabList: Tab[] = [
  85. {
  86. key: OVERVIEW_PAGE_TITLE,
  87. label: OVERVIEW_PAGE_TITLE,
  88. },
  89. ...filteredModules.map(moduleName => ({
  90. key: moduleName,
  91. label: MODULE_TITLES[moduleName],
  92. })),
  93. ];
  94. return (
  95. <Fragment>
  96. <Layout.Header>
  97. <Layout.HeaderContent>
  98. <Breadcrumbs crumbs={baseCrumbs} />
  99. <Layout.Title>{headerTitle}</Layout.Title>
  100. </Layout.HeaderContent>
  101. <Layout.HeaderActions>
  102. <ButtonBar gap={1}>
  103. {additonalHeaderActions}
  104. <FeedbackWidgetButton />
  105. </ButtonBar>
  106. </Layout.HeaderActions>
  107. <Tabs value={tabValue} onChange={handleTabChange}>
  108. {!hideDefaultTabs && (
  109. <TabList hideBorder>
  110. {tabList.map(tab => (
  111. <TabList.Item key={tab.key}>{tab.label}</TabList.Item>
  112. ))}
  113. </TabList>
  114. )}
  115. {hideDefaultTabs && tabs && tabs.tabList}
  116. </Tabs>
  117. </Layout.Header>
  118. </Fragment>
  119. );
  120. }
  121. const filterEnabledModules = (modules: ModuleName[], organization: Organization) => {
  122. return modules.filter(module => isModuleEnabled(module, organization));
  123. };