organizationCrumb.tsx 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. import {browserHistory, RouteComponentProps} from 'react-router';
  2. import styled from '@emotion/styled';
  3. import IdBadge from 'sentry/components/idBadge';
  4. import OrganizationsStore from 'sentry/stores/organizationsStore';
  5. import {useLegacyStore} from 'sentry/stores/useLegacyStore';
  6. import {Organization} from 'sentry/types';
  7. import recreateRoute from 'sentry/utils/recreateRoute';
  8. import {resolveRoute} from 'sentry/utils/resolveRoute';
  9. import useOrganization from 'sentry/utils/useOrganization';
  10. import BreadcrumbDropdown from 'sentry/views/settings/components/settingsBreadcrumb/breadcrumbDropdown';
  11. import findFirstRouteWithoutRouteParam from 'sentry/views/settings/components/settingsBreadcrumb/findFirstRouteWithoutRouteParam';
  12. import MenuItem from 'sentry/views/settings/components/settingsBreadcrumb/menuItem';
  13. import {CrumbLink} from '.';
  14. type Props = RouteComponentProps<{projectId?: string}, {}>;
  15. function OrganizationCrumb({params, routes, route, ...props}: Props) {
  16. const {organizations} = useLegacyStore(OrganizationsStore);
  17. const organization = useOrganization();
  18. const handleSelect = (item: {value: Organization}) => {
  19. // If we are currently in a project context, and we're attempting to switch organizations,
  20. // then we need to default to index route (e.g. `route`)
  21. //
  22. // Otherwise, find the last route without a router param
  23. // e.g. if you are on API details, we want the API listing
  24. // This fails if our route tree is not nested
  25. const hasProjectParam = !!params.projectId;
  26. let destinationRoute = hasProjectParam
  27. ? route
  28. : findFirstRouteWithoutRouteParam(routes.slice(routes.indexOf(route)));
  29. // It's possible there is no route without route params (e.g. organization settings index),
  30. // in which case, we can use the org settings index route (e.g. `route`)
  31. if (!hasProjectParam && typeof destinationRoute === 'undefined') {
  32. destinationRoute = route;
  33. }
  34. if (destinationRoute === undefined) {
  35. return;
  36. }
  37. const itemOrg = item.value;
  38. const path = recreateRoute(destinationRoute, {
  39. routes,
  40. params: {...params, orgId: itemOrg.slug},
  41. });
  42. const resolvedUrl = resolveRoute(path, organization, itemOrg);
  43. // If we have a shift in domains, we can't use history
  44. if (resolvedUrl.startsWith('http')) {
  45. window.location.assign(resolvedUrl);
  46. } else {
  47. browserHistory.push(resolvedUrl);
  48. }
  49. };
  50. if (!organization) {
  51. return null;
  52. }
  53. const hasMenu = organizations.length > 1;
  54. const orgSettings = `/settings/${organization.slug}/`;
  55. return (
  56. <BreadcrumbDropdown
  57. name={
  58. <CrumbLink to={orgSettings}>
  59. <BadgeWrapper>
  60. <IdBadge avatarSize={18} organization={organization} />
  61. </BadgeWrapper>
  62. </CrumbLink>
  63. }
  64. onSelect={handleSelect}
  65. hasMenu={hasMenu}
  66. route={route}
  67. items={organizations.map((org, index) => ({
  68. index,
  69. value: org,
  70. label: (
  71. <MenuItem>
  72. <IdBadge organization={org} />
  73. </MenuItem>
  74. ),
  75. }))}
  76. {...props}
  77. />
  78. );
  79. }
  80. const BadgeWrapper = styled('div')`
  81. display: flex;
  82. align-items: center;
  83. `;
  84. export {OrganizationCrumb};