navigation.tsx 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. import {Fragment, useEffect, useRef} from 'react';
  2. import {IssueViewNavItems} from 'sentry/components/nav/issueViews/issueViewNavItems';
  3. import {useUpdateGroupSearchViewLastVisited} from 'sentry/components/nav/issueViews/useUpdateGroupSearchViewLastVisited';
  4. import {usePrefersStackedNav} from 'sentry/components/nav/prefersStackedNav';
  5. import {SecondaryNav} from 'sentry/components/nav/secondary';
  6. import {PrimaryNavGroup} from 'sentry/components/nav/types';
  7. import {t} from 'sentry/locale';
  8. import type {RouteComponentProps} from 'sentry/types/legacyReactRouter';
  9. import useOrganization from 'sentry/utils/useOrganization';
  10. import {useParams} from 'sentry/utils/useParams';
  11. import type {IssueView} from 'sentry/views/issueList/issueViews/issueViews';
  12. import {useFetchGroupSearchViews} from 'sentry/views/issueList/queries/useFetchGroupSearchViews';
  13. interface IssuesWrapperProps extends RouteComponentProps {
  14. children: React.ReactNode;
  15. }
  16. export function IssueNavigation({children}: IssuesWrapperProps) {
  17. const organization = useOrganization();
  18. const sectionRef = useRef<HTMLDivElement>(null);
  19. const {viewId} = useParams<{viewId?: string}>();
  20. const {data: groupSearchViews} = useFetchGroupSearchViews({
  21. orgSlug: organization.slug,
  22. });
  23. const {mutate: updateViewLastVisited} = useUpdateGroupSearchViewLastVisited();
  24. useEffect(() => {
  25. if (groupSearchViews && viewId) {
  26. const view = groupSearchViews.find(v => v.id === viewId);
  27. if (view) {
  28. updateViewLastVisited({viewId: view.id});
  29. }
  30. }
  31. }, [groupSearchViews, viewId, updateViewLastVisited]);
  32. const prefersStackedNav = usePrefersStackedNav();
  33. if (!prefersStackedNav) {
  34. return children;
  35. }
  36. const baseUrl = `/organizations/${organization.slug}/issues`;
  37. return (
  38. <Fragment>
  39. <SecondaryNav group={PrimaryNavGroup.ISSUES}>
  40. <SecondaryNav.Header>{t('Issues')}</SecondaryNav.Header>
  41. <SecondaryNav.Body>
  42. <SecondaryNav.Section>
  43. <SecondaryNav.Item to={`${baseUrl}/`} end>
  44. {t('Feed')}
  45. </SecondaryNav.Item>
  46. <SecondaryNav.Item to={`${baseUrl}/feedback/`}>
  47. {t('Feedback')}
  48. </SecondaryNav.Item>
  49. </SecondaryNav.Section>
  50. {groupSearchViews && (
  51. <SecondaryNav.Section title={t('Views')}>
  52. <IssueViewNavItems
  53. loadedViews={groupSearchViews.map(
  54. (
  55. {
  56. id,
  57. name,
  58. query: viewQuery,
  59. querySort: viewQuerySort,
  60. environments: viewEnvironments,
  61. projects: viewProjects,
  62. timeFilters: viewTimeFilters,
  63. isAllProjects,
  64. },
  65. index
  66. ): IssueView => {
  67. const tabId = id ?? `default${index.toString()}`;
  68. return {
  69. id: tabId,
  70. key: tabId,
  71. label: name,
  72. query: viewQuery,
  73. querySort: viewQuerySort,
  74. environments: viewEnvironments,
  75. projects: isAllProjects ? [-1] : viewProjects,
  76. timeFilters: viewTimeFilters,
  77. isCommitted: true,
  78. };
  79. }
  80. )}
  81. sectionRef={sectionRef}
  82. baseUrl={baseUrl}
  83. />
  84. </SecondaryNav.Section>
  85. )}
  86. <SecondaryNav.Section title={t('Configure')}>
  87. <SecondaryNav.Item
  88. to={`${baseUrl}/alerts/rules/`}
  89. activeTo={`${baseUrl}/alerts/`}
  90. >
  91. {t('Alerts')}
  92. </SecondaryNav.Item>
  93. </SecondaryNav.Section>
  94. </SecondaryNav.Body>
  95. </SecondaryNav>
  96. {children}
  97. </Fragment>
  98. );
  99. }