settingsNavigation.tsx 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. import {cloneElement, Component} from 'react';
  2. import styled from '@emotion/styled';
  3. import * as Sentry from '@sentry/react';
  4. import {NAV_GROUP_LABELS} from 'sentry/components/nav/constants';
  5. import {prefersStackedNav} from 'sentry/components/nav/prefersStackedNav';
  6. import {SecondaryNav} from 'sentry/components/nav/secondary';
  7. import {PrimaryNavGroup} from 'sentry/components/nav/types';
  8. import {space} from 'sentry/styles/space';
  9. import SettingsNavigationGroup from 'sentry/views/settings/components/settingsNavigationGroup';
  10. import SettingsNavigationGroupDeprecated from 'sentry/views/settings/components/settingsNavigationGroupDeprecated';
  11. import type {NavigationProps, NavigationSection} from 'sentry/views/settings/types';
  12. type DefaultProps = {
  13. /**
  14. * Additional navigation configuration driven by hooks
  15. */
  16. hookConfigs: NavigationSection[];
  17. /**
  18. * Additional navigation elements driven from hooks
  19. */
  20. hooks: React.ReactElement[];
  21. /**
  22. * How far from the top of the page should the navigation be when stickied.
  23. */
  24. stickyTop: string;
  25. };
  26. type Props = DefaultProps &
  27. NavigationProps & {
  28. /**
  29. * The configuration for this navigation panel
  30. */
  31. navigationObjects: NavigationSection[];
  32. };
  33. function SettingsSecondaryNavigation({
  34. navigationObjects,
  35. hookConfigs,
  36. hooks,
  37. ...otherProps
  38. }: Props) {
  39. const navWithHooks = navigationObjects.concat(hookConfigs);
  40. return (
  41. <SecondaryNav group={PrimaryNavGroup.SETTINGS}>
  42. <SecondaryNav.Header>
  43. {NAV_GROUP_LABELS[PrimaryNavGroup.SETTINGS]}
  44. </SecondaryNav.Header>
  45. <SecondaryNav.Body>
  46. {navWithHooks.map(config => (
  47. <SettingsNavigationGroup key={config.name} {...otherProps} {...config} />
  48. ))}
  49. {hooks.map((Hook, i) => cloneElement(Hook, {key: `hook-${i}`}))}
  50. </SecondaryNav.Body>
  51. </SecondaryNav>
  52. );
  53. }
  54. class SettingsNavigation extends Component<Props> {
  55. static defaultProps: DefaultProps = {
  56. hooks: [],
  57. hookConfigs: [],
  58. stickyTop: '69px',
  59. };
  60. componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {
  61. Sentry.withScope(scope => {
  62. Object.keys(errorInfo).forEach(key => {
  63. // @ts-expect-error TS(7053): Element implicitly has an 'any' type because expre... Remove this comment to see the full error message
  64. scope.setExtra(key, errorInfo[key]);
  65. });
  66. scope.setExtra('url', window.location.href);
  67. Sentry.captureException(error);
  68. });
  69. }
  70. render() {
  71. const {navigationObjects, hooks, hookConfigs, stickyTop, ...otherProps} = this.props;
  72. const navWithHooks = navigationObjects.concat(hookConfigs);
  73. if (prefersStackedNav()) {
  74. return (
  75. <SettingsSecondaryNavigation
  76. navigationObjects={navigationObjects}
  77. hooks={hooks}
  78. hookConfigs={hookConfigs}
  79. stickyTop={stickyTop}
  80. {...otherProps}
  81. />
  82. );
  83. }
  84. return (
  85. <PositionStickyWrapper stickyTop={stickyTop}>
  86. {navWithHooks.map(config => (
  87. <SettingsNavigationGroupDeprecated
  88. key={config.name}
  89. {...otherProps}
  90. {...config}
  91. />
  92. ))}
  93. {hooks.map((Hook, i) => cloneElement(Hook, {key: `hook-${i}`}))}
  94. </PositionStickyWrapper>
  95. );
  96. }
  97. }
  98. const PositionStickyWrapper = styled('div')<{stickyTop: string}>`
  99. padding: ${space(4)};
  100. padding-right: ${space(2)};
  101. @media (min-width: ${p => p.theme.breakpoints.small}) {
  102. position: sticky;
  103. top: ${p => p.stickyTop};
  104. overflow: scroll;
  105. -ms-overflow-style: none;
  106. scrollbar-width: none;
  107. &::-webkit-scrollbar {
  108. display: none;
  109. }
  110. }
  111. `;
  112. export default SettingsNavigation;