domainViewHeader.tsx 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. import {Fragment} from 'react';
  2. import styled from '@emotion/styled';
  3. import {Breadcrumbs, type Crumb} from 'sentry/components/breadcrumbs';
  4. import ButtonBar from 'sentry/components/buttonBar';
  5. import FeedbackWidgetButton from 'sentry/components/feedback/widget/feedbackWidgetButton';
  6. import * as Layout from 'sentry/components/layouts/thirds';
  7. import {TabList} from 'sentry/components/tabs';
  8. import type {TabListItemProps} from 'sentry/components/tabs/item';
  9. import {IconBusiness} from 'sentry/icons';
  10. import {space} from 'sentry/styles/space';
  11. import useOrganization from 'sentry/utils/useOrganization';
  12. import {useModuleTitles} from 'sentry/views/insights/common/utils/useModuleTitle';
  13. import {
  14. type RoutableModuleNames,
  15. useModuleURLBuilder,
  16. } from 'sentry/views/insights/common/utils/useModuleURL';
  17. import {OVERVIEW_PAGE_TITLE} from 'sentry/views/insights/pages/settings';
  18. import {isModuleEnabled, isModuleVisible} from 'sentry/views/insights/pages/utils';
  19. import type {ModuleName} from 'sentry/views/insights/types';
  20. export type Props = {
  21. domainBaseUrl: string;
  22. domainTitle: string;
  23. modules: ModuleName[];
  24. selectedModule: ModuleName | undefined;
  25. additionalBreadCrumbs?: Crumb[];
  26. additonalHeaderActions?: React.ReactNode;
  27. headerTitle?: React.ReactNode;
  28. hideDefaultTabs?: boolean;
  29. tabs?: {onTabChange: (key: string) => void; tabList: React.ReactNode; value: string};
  30. };
  31. export function DomainViewHeader({
  32. modules,
  33. headerTitle,
  34. domainTitle,
  35. selectedModule,
  36. hideDefaultTabs,
  37. additonalHeaderActions,
  38. additionalBreadCrumbs = [],
  39. domainBaseUrl,
  40. tabs,
  41. }: Props) {
  42. const organization = useOrganization();
  43. const moduleURLBuilder = useModuleURLBuilder();
  44. const crumbs: Crumb[] = [
  45. {
  46. label: domainTitle,
  47. to: domainBaseUrl,
  48. preservePageFilters: true,
  49. },
  50. ...additionalBreadCrumbs,
  51. ];
  52. const tabValue =
  53. hideDefaultTabs && tabs?.value ? tabs.value : selectedModule ?? OVERVIEW_PAGE_TITLE;
  54. const tabList: TabListItemProps[] = [
  55. {
  56. key: OVERVIEW_PAGE_TITLE,
  57. children: OVERVIEW_PAGE_TITLE,
  58. to: domainBaseUrl,
  59. },
  60. ...modules
  61. .filter(moduleName => isModuleVisible(moduleName, organization))
  62. .map(moduleName => ({
  63. key: moduleName,
  64. children: <TabLabel moduleName={moduleName} />,
  65. to: `${moduleURLBuilder(moduleName as RoutableModuleNames)}/`,
  66. })),
  67. ];
  68. return (
  69. <Fragment>
  70. <Layout.Header>
  71. <Layout.HeaderContent>
  72. {crumbs.length > 1 && <Breadcrumbs crumbs={crumbs} />}
  73. <Layout.Title>{headerTitle || domainTitle}</Layout.Title>
  74. </Layout.HeaderContent>
  75. <Layout.HeaderActions>
  76. <ButtonBar gap={1}>
  77. <FeedbackWidgetButton />
  78. {additonalHeaderActions}
  79. </ButtonBar>
  80. </Layout.HeaderActions>
  81. <Layout.HeaderTabs value={tabValue} onChange={tabs?.onTabChange}>
  82. {!hideDefaultTabs && (
  83. <TabList hideBorder>
  84. {tabList.map(tab => (
  85. <TabList.Item {...tab} key={tab.key} />
  86. ))}
  87. </TabList>
  88. )}
  89. {hideDefaultTabs && tabs && tabs.tabList}
  90. </Layout.HeaderTabs>
  91. </Layout.Header>
  92. </Fragment>
  93. );
  94. }
  95. function TabLabel({moduleName}: {moduleName: ModuleName}) {
  96. const moduleTitles = useModuleTitles();
  97. const organization = useOrganization();
  98. const showBusinessIcon = !isModuleEnabled(moduleName, organization);
  99. if (showBusinessIcon) {
  100. return (
  101. <TabWithIconContainer>
  102. {moduleTitles[moduleName]}
  103. <IconBusiness />
  104. </TabWithIconContainer>
  105. );
  106. }
  107. return <Fragment>{moduleTitles[moduleName]}</Fragment>;
  108. }
  109. const TabWithIconContainer = styled('div')`
  110. display: inline-flex;
  111. align-items: center;
  112. text-align: left;
  113. gap: ${space(0.5)};
  114. `;