settingsNavigation.tsx 2.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  1. import {cloneElement, Component} from 'react';
  2. import styled from '@emotion/styled';
  3. import * as Sentry from '@sentry/react';
  4. import {space} from 'sentry/styles/space';
  5. import SettingsNavigationGroup from 'sentry/views/settings/components/settingsNavigationGroup';
  6. import type {NavigationProps, NavigationSection} from 'sentry/views/settings/types';
  7. type DefaultProps = {
  8. /**
  9. * Additional navigation configuration driven by hooks
  10. */
  11. hookConfigs: NavigationSection[];
  12. /**
  13. * Additional navigation elements driven from hooks
  14. */
  15. hooks: React.ReactElement[];
  16. /**
  17. * How far from the top of the page should the navigation be when stickied.
  18. */
  19. stickyTop: string;
  20. };
  21. type Props = DefaultProps &
  22. NavigationProps & {
  23. /**
  24. * The configuration for this navigation panel
  25. */
  26. navigationObjects: NavigationSection[];
  27. };
  28. class SettingsNavigation extends Component<Props> {
  29. static defaultProps: DefaultProps = {
  30. hooks: [],
  31. hookConfigs: [],
  32. stickyTop: '69px',
  33. };
  34. componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {
  35. Sentry.withScope(scope => {
  36. Object.keys(errorInfo).forEach(key => {
  37. // @ts-expect-error TS(7053): Element implicitly has an 'any' type because expre... Remove this comment to see the full error message
  38. scope.setExtra(key, errorInfo[key]);
  39. });
  40. scope.setExtra('url', window.location.href);
  41. Sentry.captureException(error);
  42. });
  43. }
  44. render() {
  45. const {navigationObjects, hooks, hookConfigs, stickyTop, ...otherProps} = this.props;
  46. const navWithHooks = navigationObjects.concat(hookConfigs);
  47. return (
  48. <PositionStickyWrapper stickyTop={stickyTop}>
  49. {navWithHooks.map(config => (
  50. <SettingsNavigationGroup key={config.name} {...otherProps} {...config} />
  51. ))}
  52. {hooks.map((Hook, i) => cloneElement(Hook, {key: `hook-${i}`}))}
  53. </PositionStickyWrapper>
  54. );
  55. }
  56. }
  57. const PositionStickyWrapper = styled('div')<{stickyTop: string}>`
  58. padding: ${space(4)};
  59. padding-right: ${space(2)};
  60. @media (min-width: ${p => p.theme.breakpoints.small}) {
  61. position: sticky;
  62. top: ${p => p.stickyTop};
  63. overflow: scroll;
  64. -ms-overflow-style: none;
  65. scrollbar-width: none;
  66. &::-webkit-scrollbar {
  67. display: none;
  68. }
  69. }
  70. `;
  71. export default SettingsNavigation;