You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

BranchLikeNavigation.tsx 4.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. /*
  2. * SonarQube
  3. * Copyright (C) 2009-2024 SonarSource SA
  4. * mailto:info AT sonarsource DOT com
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU Lesser General Public
  8. * License as published by the Free Software Foundation; either
  9. * version 3 of the License, or (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public License
  17. * along with this program; if not, write to the Free Software Foundation,
  18. * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  19. */
  20. import styled from '@emotion/styled';
  21. import { ButtonSecondary, Popup, PopupPlacement, PopupZLevel } from 'design-system';
  22. import * as React from 'react';
  23. import EscKeydownHandler from '../../../../../components/controls/EscKeydownHandler';
  24. import FocusOutHandler from '../../../../../components/controls/FocusOutHandler';
  25. import OutsideClickHandler from '../../../../../components/controls/OutsideClickHandler';
  26. import { useBranchesQuery } from '../../../../../queries/branch';
  27. import { ComponentQualifier } from '../../../../../types/component';
  28. import { Feature } from '../../../../../types/features';
  29. import { Component } from '../../../../../types/types';
  30. import withAvailableFeatures, {
  31. WithAvailableFeaturesProps,
  32. } from '../../../available-features/withAvailableFeatures';
  33. import BranchHelpTooltip from './BranchHelpTooltip';
  34. import CurrentBranchLike from './CurrentBranchLike';
  35. import Menu from './Menu';
  36. import PRLink from './PRLink';
  37. export interface BranchLikeNavigationProps extends WithAvailableFeaturesProps {
  38. component: Component;
  39. }
  40. export function BranchLikeNavigation(props: BranchLikeNavigationProps) {
  41. const {
  42. component,
  43. component: { configuration },
  44. } = props;
  45. const { data: { branchLikes, branchLike: currentBranchLike } = { branchLikes: [] } } =
  46. useBranchesQuery(component);
  47. const [isMenuOpen, setIsMenuOpen] = React.useState(false);
  48. if (currentBranchLike === undefined) {
  49. return null;
  50. }
  51. const isApplication = component.qualifier === ComponentQualifier.Application;
  52. const branchSupportEnabled = props.hasFeature(Feature.BranchSupport);
  53. const canAdminComponent = configuration?.showSettings;
  54. const hasManyBranches = branchLikes.length >= 2;
  55. const isMenuEnabled = branchSupportEnabled && hasManyBranches;
  56. const currentBranchLikeElement = <CurrentBranchLike currentBranchLike={currentBranchLike} />;
  57. const handleOutsideClick = () => {
  58. setIsMenuOpen(false);
  59. };
  60. return (
  61. <>
  62. <SlashSeparator className=" sw-mx-2" />
  63. <div className="sw-flex sw-items-center it__branch-like-navigation-toggler-container">
  64. <Popup
  65. allowResizing
  66. overlay={
  67. isMenuOpen && (
  68. <FocusOutHandler onFocusOut={handleOutsideClick}>
  69. <EscKeydownHandler onKeydown={handleOutsideClick}>
  70. <OutsideClickHandler onClickOutside={handleOutsideClick}>
  71. <Menu
  72. branchLikes={branchLikes}
  73. canAdminComponent={canAdminComponent}
  74. component={component}
  75. currentBranchLike={currentBranchLike}
  76. onClose={() => {
  77. setIsMenuOpen(false);
  78. }}
  79. />
  80. </OutsideClickHandler>
  81. </EscKeydownHandler>
  82. </FocusOutHandler>
  83. )
  84. }
  85. placement={PopupPlacement.BottomLeft}
  86. zLevel={PopupZLevel.Global}
  87. >
  88. <ButtonSecondary
  89. className="sw-max-w-abs-800 sw-px-3"
  90. onClick={() => {
  91. setIsMenuOpen(!isMenuOpen);
  92. }}
  93. disabled={!isMenuEnabled}
  94. aria-expanded={isMenuOpen}
  95. aria-haspopup="menu"
  96. >
  97. {currentBranchLikeElement}
  98. </ButtonSecondary>
  99. </Popup>
  100. <div className="sw-ml-2">
  101. <BranchHelpTooltip
  102. component={component}
  103. isApplication={isApplication}
  104. hasManyBranches={hasManyBranches}
  105. canAdminComponent={canAdminComponent}
  106. branchSupportEnabled={branchSupportEnabled}
  107. />
  108. </div>
  109. <PRLink currentBranchLike={currentBranchLike} component={component} />
  110. </div>
  111. </>
  112. );
  113. }
  114. export default withAvailableFeatures(React.memo(BranchLikeNavigation));
  115. const SlashSeparator = styled.span`
  116. &:after {
  117. content: '/';
  118. color: rgba(68, 68, 68, 0.3);
  119. }
  120. `;