switchOrganization.tsx 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. import {Fragment} from 'react';
  2. import styled from '@emotion/styled';
  3. import sortBy from 'lodash/sortBy';
  4. import DropdownMenu from 'sentry/components/dropdownMenu';
  5. import SidebarDropdownMenu from 'sentry/components/sidebar/sidebarDropdownMenu.styled';
  6. import SidebarMenuItem from 'sentry/components/sidebar/sidebarMenuItem';
  7. import SidebarOrgSummary from 'sentry/components/sidebar/sidebarOrgSummary';
  8. import {IconAdd, IconChevron} from 'sentry/icons';
  9. import {t} from 'sentry/locale';
  10. import space from 'sentry/styles/space';
  11. import {OrganizationSummary} from 'sentry/types';
  12. import withOrganizations from 'sentry/utils/withOrganizations';
  13. import Divider from './divider.styled';
  14. type Props = {
  15. canCreateOrganization: boolean;
  16. organizations: OrganizationSummary[];
  17. };
  18. /**
  19. * Switch Organization Menu Label + Sub Menu
  20. */
  21. const SwitchOrganization = ({organizations, canCreateOrganization}: Props) => (
  22. <DropdownMenu isNestedDropdown>
  23. {({isOpen, getMenuProps, getActorProps}) => (
  24. <Fragment>
  25. <SwitchOrganizationMenuActor
  26. data-test-id="sidebar-switch-org"
  27. {...getActorProps({})}
  28. onClick={e => {
  29. // This overwrites `DropdownMenu.getActorProps.onClick` which normally handles clicks on actor
  30. // to toggle visibility of menu. Instead, do nothing because it is nested and we only want it
  31. // to appear when hovered on. Will also stop menu from closing when clicked on (which seems to be common
  32. // behavior);
  33. // Stop propagation so that dropdown menu doesn't close here
  34. e.stopPropagation();
  35. }}
  36. >
  37. {t('Switch organization')}
  38. <SubMenuCaret>
  39. <IconChevron size="xs" direction="right" />
  40. </SubMenuCaret>
  41. </SwitchOrganizationMenuActor>
  42. {isOpen && (
  43. <SwitchOrganizationMenu
  44. data-test-id="sidebar-switch-org-menu"
  45. {...getMenuProps({})}
  46. >
  47. <OrganizationList role="list">
  48. {sortBy(organizations, ['status.id']).map(organization => {
  49. const url = `/organizations/${organization.slug}/`;
  50. return (
  51. <SidebarMenuItem key={organization.slug} to={url}>
  52. <SidebarOrgSummary organization={organization} />
  53. </SidebarMenuItem>
  54. );
  55. })}
  56. </OrganizationList>
  57. {organizations && !!organizations.length && canCreateOrganization && (
  58. <Divider css={{marginTop: 0}} />
  59. )}
  60. {canCreateOrganization && (
  61. <SidebarMenuItem
  62. data-test-id="sidebar-create-org"
  63. to="/organizations/new/"
  64. style={{alignItems: 'center'}}
  65. >
  66. <MenuItemLabelWithIcon>
  67. <StyledIconAdd />
  68. <span>{t('Create a new organization')}</span>
  69. </MenuItemLabelWithIcon>
  70. </SidebarMenuItem>
  71. )}
  72. </SwitchOrganizationMenu>
  73. )}
  74. </Fragment>
  75. )}
  76. </DropdownMenu>
  77. );
  78. const SwitchOrganizationContainer = withOrganizations(SwitchOrganization);
  79. export {SwitchOrganization};
  80. export default SwitchOrganizationContainer;
  81. const StyledIconAdd = styled(IconAdd)`
  82. margin-right: ${space(1)};
  83. color: ${p => p.theme.gray300};
  84. `;
  85. const MenuItemLabelWithIcon = styled('span')`
  86. line-height: 1;
  87. display: flex;
  88. align-items: center;
  89. padding: ${space(1)} 0;
  90. `;
  91. const SubMenuCaret = styled('span')`
  92. color: ${p => p.theme.gray300};
  93. transition: 0.1s color linear;
  94. &:hover,
  95. &:active {
  96. color: ${p => p.theme.subText};
  97. }
  98. `;
  99. // Menu Item in dropdown to "Switch organization"
  100. const SwitchOrganizationMenuActor = styled('span')`
  101. display: flex;
  102. justify-content: space-between;
  103. align-items: center;
  104. margin: 0 -${p => p.theme.sidebar.menuSpacing};
  105. padding: 0 ${p => p.theme.sidebar.menuSpacing};
  106. `;
  107. const SwitchOrganizationMenu = styled('div')`
  108. ${SidebarDropdownMenu};
  109. top: 0;
  110. left: 256px;
  111. `;
  112. const OrganizationList = styled('div')`
  113. max-height: 350px;
  114. overflow-y: auto;
  115. `;