]> source.dussan.org Git - sonarqube.git/commitdiff
Fix usage of button-link, replace it with ButtonLink component
authorGrégoire Aubert <gregoire.aubert@sonarsource.com>
Mon, 21 Jan 2019 10:11:08 +0000 (11:11 +0100)
committerSonarTech <sonartech@sonarsource.com>
Mon, 28 Jan 2019 19:21:01 +0000 (20:21 +0100)
48 files changed:
server/sonar-web/src/main/js/apps/coding-rules/components/RuleDetailsMeta.tsx
server/sonar-web/src/main/js/apps/coding-rules/components/__tests__/RuleDetailsMeta-test.tsx
server/sonar-web/src/main/js/apps/coding-rules/components/__tests__/__snapshots__/RuleDetailsMeta-test.tsx.snap
server/sonar-web/src/main/js/apps/groups/components/__tests__/__snapshots__/EditMembers-test.tsx.snap
server/sonar-web/src/main/js/apps/marketplace/components/PluginChangeLogButton.tsx
server/sonar-web/src/main/js/apps/overview/meta/MetaTags.tsx
server/sonar-web/src/main/js/apps/overview/meta/__tests__/__snapshots__/MetaTags-test.tsx.snap
server/sonar-web/src/main/js/apps/settings/components/DefinitionActions.tsx
server/sonar-web/src/main/js/apps/settings/components/__tests__/__snapshots__/DefinitionActions-test.tsx.snap
server/sonar-web/src/main/js/apps/system/components/system-upgrade/SystemUpgradeForm.tsx
server/sonar-web/src/main/js/apps/system/components/system-upgrade/SystemUpgradeIntermediate.tsx
server/sonar-web/src/main/js/apps/system/components/system-upgrade/SystemUpgradeItem.tsx
server/sonar-web/src/main/js/apps/system/components/system-upgrade/__tests__/SystemUpgradeIntermediate-test.tsx
server/sonar-web/src/main/js/apps/system/components/system-upgrade/__tests__/__snapshots__/SystemUpgradeForm-test.tsx.snap
server/sonar-web/src/main/js/apps/system/components/system-upgrade/__tests__/__snapshots__/SystemUpgradeIntermediate-test.tsx.snap
server/sonar-web/src/main/js/apps/system/components/system-upgrade/__tests__/__snapshots__/SystemUpgradeItem-test.tsx.snap
server/sonar-web/src/main/js/apps/webhooks/components/DeliveriesForm.tsx
server/sonar-web/src/main/js/apps/webhooks/components/LatestDeliveryForm.tsx
server/sonar-web/src/main/js/apps/webhooks/components/__tests__/__snapshots__/DeliveriesForm-test.tsx.snap
server/sonar-web/src/main/js/apps/webhooks/components/__tests__/__snapshots__/LatestDeliveryForm-test.tsx.snap
server/sonar-web/src/main/js/components/SourceViewer/components/MeasuresOverlay.tsx
server/sonar-web/src/main/js/components/SourceViewer/components/__tests__/__snapshots__/MeasuresOverlay-test.tsx.snap
server/sonar-web/src/main/js/components/issue/components/IssueAssign.tsx
server/sonar-web/src/main/js/components/issue/components/IssueChangelog.tsx
server/sonar-web/src/main/js/components/issue/components/IssueCommentAction.tsx
server/sonar-web/src/main/js/components/issue/components/IssueMessage.tsx
server/sonar-web/src/main/js/components/issue/components/IssueSeverity.tsx
server/sonar-web/src/main/js/components/issue/components/IssueTags.tsx
server/sonar-web/src/main/js/components/issue/components/IssueTransition.tsx
server/sonar-web/src/main/js/components/issue/components/IssueType.tsx
server/sonar-web/src/main/js/components/issue/components/SimilarIssuesFilter.tsx
server/sonar-web/src/main/js/components/issue/components/__tests__/IssueAssign-test.tsx
server/sonar-web/src/main/js/components/issue/components/__tests__/IssueChangelog-test.tsx
server/sonar-web/src/main/js/components/issue/components/__tests__/IssueCommentAction-test.tsx
server/sonar-web/src/main/js/components/issue/components/__tests__/IssueSeverity-test.tsx
server/sonar-web/src/main/js/components/issue/components/__tests__/IssueTags-test.tsx
server/sonar-web/src/main/js/components/issue/components/__tests__/IssueTransition-test.tsx
server/sonar-web/src/main/js/components/issue/components/__tests__/IssueType-test.tsx
server/sonar-web/src/main/js/components/issue/components/__tests__/__snapshots__/IssueAssign-test.tsx.snap
server/sonar-web/src/main/js/components/issue/components/__tests__/__snapshots__/IssueChangelog-test.tsx.snap
server/sonar-web/src/main/js/components/issue/components/__tests__/__snapshots__/IssueCommentAction-test.tsx.snap
server/sonar-web/src/main/js/components/issue/components/__tests__/__snapshots__/IssueMessage-test.tsx.snap
server/sonar-web/src/main/js/components/issue/components/__tests__/__snapshots__/IssueSeverity-test.tsx.snap
server/sonar-web/src/main/js/components/issue/components/__tests__/__snapshots__/IssueTags-test.tsx.snap
server/sonar-web/src/main/js/components/issue/components/__tests__/__snapshots__/IssueTransition-test.tsx.snap
server/sonar-web/src/main/js/components/issue/components/__tests__/__snapshots__/IssueType-test.tsx.snap
server/sonar-web/src/main/js/components/ui/buttons.css
server/sonar-web/src/main/js/components/ui/buttons.tsx

index 5cfcb6dbfe77fa142f762229d9ea2c0a063675a5..78ef447f8b715cd01f9668c797b783c9d98c9d3a 100644 (file)
@@ -21,20 +21,20 @@ import * as React from 'react';
 import { Link } from 'react-router';
 import RuleDetailsTagsPopup from './RuleDetailsTagsPopup';
 import SimilarRulesFilter from './SimilarRulesFilter';
-import { Query } from '../query';
-import { getRuleUrl } from '../../../helpers/urls';
-import LinkIcon from '../../../components/icons-components/LinkIcon';
-import RuleScopeIcon from '../../../components/icons-components/RuleScopeIcon';
-import Tooltip from '../../../components/controls/Tooltip';
+import DateFormatter from '../../../components/intl/DateFormatter';
 import DocTooltip from '../../../components/docs/DocTooltip';
-import { translate, translateWithParameters } from '../../../helpers/l10n';
+import Dropdown from '../../../components/controls/Dropdown';
 import IssueTypeIcon from '../../../components/ui/IssueTypeIcon';
+import LinkIcon from '../../../components/icons-components/LinkIcon';
+import RuleScopeIcon from '../../../components/icons-components/RuleScopeIcon';
 import SeverityHelper from '../../../components/shared/SeverityHelper';
-import Dropdown from '../../../components/controls/Dropdown';
 import TagsList from '../../../components/tags/TagsList';
-import DateFormatter from '../../../components/intl/DateFormatter';
-import { Button } from '../../../components/ui/buttons';
+import Tooltip from '../../../components/controls/Tooltip';
+import { ButtonLink } from '../../../components/ui/buttons';
 import { PopupPlacement } from '../../../components/ui/popups';
+import { Query } from '../query';
+import { getRuleUrl } from '../../../helpers/urls';
+import { translate, translateWithParameters } from '../../../helpers/l10n';
 
 interface Props {
   canWrite: boolean | undefined;
@@ -108,12 +108,12 @@ export default class RuleDetailsMeta extends React.PureComponent<Props> {
               />
             }
             overlayPlacement={PopupPlacement.BottomLeft}>
-            <Button className="button-link">
+            <ButtonLink>
               <TagsList
                 allowUpdate={canWrite}
                 tags={allTags.length > 0 ? allTags : [translate('coding_rules.no_tags')]}
               />
-            </Button>
+            </ButtonLink>
           </Dropdown>
         ) : (
           <TagsList
index e0d7a8553f1ed9e3bc8386c31ca1753b177f43ff..0b14669c104e4e1358569f3ea1bba79789ecf86b 100644 (file)
@@ -63,18 +63,18 @@ const EXTERNAL_RULE_WITH_DATA: T.RuleDetails = {
 };
 
 it('should display right meta info', () => {
-  expect(getWrapper()).toMatchSnapshot();
+  expect(shallowRender()).toMatchSnapshot();
   expect(
-    getWrapper({ hideSimilarRulesFilter: true, ruleDetails: EXTERNAL_RULE })
+    shallowRender({ hideSimilarRulesFilter: true, ruleDetails: EXTERNAL_RULE })
   ).toMatchSnapshot();
   expect(
-    getWrapper({ hideSimilarRulesFilter: true, ruleDetails: EXTERNAL_RULE_WITH_DATA })
+    shallowRender({ hideSimilarRulesFilter: true, ruleDetails: EXTERNAL_RULE_WITH_DATA })
   ).toMatchSnapshot();
 });
 
 it('should edit tags', () => {
   const onTagsChange = jest.fn();
-  const wrapper = getWrapper({ onTagsChange });
+  const wrapper = shallowRender({ onTagsChange });
   expect(wrapper.find('[data-meta="tags"]')).toMatchSnapshot();
   const overlay = wrapper
     .find('[data-meta="tags"]')
@@ -85,7 +85,7 @@ it('should edit tags', () => {
   expect(onTagsChange).toBeCalledWith(['foo', 'bar']);
 });
 
-function getWrapper(props = {}) {
+function shallowRender(props: Partial<RuleDetailsMeta['props']> = {}) {
   return shallow(
     <RuleDetailsMeta
       canWrite={true}
index 4f44e117aa73f99edfc08a36f096d0df14eb526f..d0de08cf38792d97d1510464c884cd4d12b94149 100644 (file)
@@ -116,9 +116,7 @@ exports[`should display right meta info 1`] = `
         }
         overlayPlacement="bottom-left"
       >
-        <Button
-          className="button-link"
-        >
+        <ButtonLink>
           <TagsList
             allowUpdate={true}
             tags={
@@ -127,7 +125,7 @@ exports[`should display right meta info 1`] = `
               ]
             }
           />
-        </Button>
+        </ButtonLink>
       </Dropdown>
     </li>
     <li
@@ -248,9 +246,7 @@ exports[`should display right meta info 3`] = `
         }
         overlayPlacement="bottom-left"
       >
-        <Button
-          className="button-link"
-        >
+        <ButtonLink>
           <TagsList
             allowUpdate={true}
             tags={
@@ -259,7 +255,7 @@ exports[`should display right meta info 3`] = `
               ]
             }
           />
-        </Button>
+        </ButtonLink>
       </Dropdown>
     </li>
     <Tooltip
@@ -296,9 +292,7 @@ exports[`should edit tags 1`] = `
     }
     overlayPlacement="bottom-left"
   >
-    <Button
-      className="button-link"
-    >
+    <ButtonLink>
       <TagsList
         allowUpdate={true}
         tags={
@@ -307,7 +301,7 @@ exports[`should edit tags 1`] = `
           ]
         }
       />
-    </Button>
+    </ButtonLink>
   </Dropdown>
 </li>
 `;
index 0da138c34d707acd8c00c28bca58bb610d34f137..57ca00c2b1e1533ce2b10711dad12b54c769ca77 100644 (file)
@@ -575,19 +575,24 @@ exports[`should edit members 2`] = `
                   <ResetButtonLink
                     onClick={[Function]}
                   >
-                    <Button
-                      className="button-link"
+                    <ButtonLink
                       onClick={[Function]}
                       type="reset"
                     >
-                      <button
-                        className="button button-link"
+                      <Button
+                        className="button-link"
                         onClick={[Function]}
                         type="reset"
                       >
-                        Done
-                      </button>
-                    </Button>
+                        <button
+                          className="button button-link"
+                          onClick={[Function]}
+                          type="reset"
+                        >
+                          Done
+                        </button>
+                      </Button>
+                    </ButtonLink>
                   </ResetButtonLink>
                 </footer>
               </div>
index 8127c36ec433638067b388590081825e9569d14d..b0483f272d0d3fe4e19b996fb4aac981fa706749 100644 (file)
  */
 import * as React from 'react';
 import PluginChangeLog from './PluginChangeLog';
-import { Release, Update } from '../../../api/plugins';
-import EllipsisIcon from '../../../components/icons-components/EllipsisIcon';
 import Dropdown from '../../../components/controls/Dropdown';
-import { Button } from '../../../components/ui/buttons';
+import EllipsisIcon from '../../../components/icons-components/EllipsisIcon';
+import { ButtonLink } from '../../../components/ui/buttons';
+import { Release, Update } from '../../../api/plugins';
 
 interface Props {
   release: Release;
@@ -34,9 +34,9 @@ export default function PluginChangeLogButton({ release, update }: Props) {
     <Dropdown
       className="display-inline-block little-spacer-left"
       overlay={<PluginChangeLog release={release} update={update} />}>
-      <Button className="button-link js-changelog issue-rule">
+      <ButtonLink className="js-changelog issue-rule">
         <EllipsisIcon />
-      </Button>
+      </ButtonLink>
     </Dropdown>
   );
 }
index 173aaa268f0cdaeddb9089ee84e1a53dd2f41aba..53036c8c2a6559848dad0c5f6b9b550cefb6a875 100644 (file)
  */
 import * as React from 'react';
 import MetaTagsSelector from './MetaTagsSelector';
-import { setProjectTags } from '../../../api/components';
-import { translate } from '../../../helpers/l10n';
-import TagsList from '../../../components/tags/TagsList';
-import { Button } from '../../../components/ui/buttons';
 import Dropdown from '../../../components/controls/Dropdown';
+import TagsList from '../../../components/tags/TagsList';
+import { ButtonLink } from '../../../components/ui/buttons';
 import { PopupPlacement } from '../../../components/ui/popups';
+import { setProjectTags } from '../../../api/components';
+import { translate } from '../../../helpers/l10n';
 
 interface Props {
   component: T.Component;
@@ -71,12 +71,9 @@ export default class MetaTags extends React.PureComponent<Props> {
               />
             }
             overlayPlacement={PopupPlacement.BottomLeft}>
-            <Button
-              className="button-link"
-              innerRef={tagsList => (this.tagsList = tagsList)}
-              stopPropagation={true}>
+            <ButtonLink innerRef={tagsList => (this.tagsList = tagsList)} stopPropagation={true}>
               <TagsList allowUpdate={true} tags={tags.length ? tags : [translate('no_tags')]} />
-            </Button>
+            </ButtonLink>
           </Dropdown>
         </div>
       );
index 7eb0fedde2c2c6870158ccdd1a133506c35882cb..b1bb719ee73e013387f4af7f24c06e1154da2c21 100644 (file)
@@ -21,8 +21,7 @@ exports[`should render with tags and admin rights 1`] = `
     }
     overlayPlacement="bottom-left"
   >
-    <Button
-      className="button-link"
+    <ButtonLink
       innerRef={[Function]}
       stopPropagation={true}
     >
@@ -35,7 +34,7 @@ exports[`should render with tags and admin rights 1`] = `
           ]
         }
       />
-    </Button>
+    </ButtonLink>
   </Dropdown>
 </div>
 `;
index 52518c28e5a911d1b0ecde808d482c4efbafff82..a4892c225bf0abcd0d2b8a53a9db19b32871260a 100644 (file)
@@ -106,9 +106,9 @@ export default class DefinitionActions extends React.PureComponent<Props, State>
           )}
 
           {hasValueChanged && (
-            <Button className="spacer-right button-link" onClick={this.props.onCancel}>
+            <ResetButtonLink className="spacer-right" onClick={this.props.onCancel}>
               {translate('cancel')}
-            </Button>
+            </ResetButtonLink>
           )}
 
           {showReset && (
index 046e36dbc27d59a58aa342210d25e27358e066b1..78ad17c3397aa61a1a43f820d3458d4036ebdda6 100644 (file)
@@ -12,12 +12,12 @@ exports[`disables save button on error 1`] = `
     >
       save
     </Button>
-    <Button
-      className="spacer-right button-link"
+    <ResetButtonLink
+      className="spacer-right"
       onClick={[Function]}
     >
       cancel
-    </Button>
+    </ResetButtonLink>
   </div>
 </Fragment>
 `;
@@ -34,12 +34,12 @@ exports[`displays cancel button when value changed and has error 1`] = `
     >
       save
     </Button>
-    <Button
-      className="spacer-right button-link"
+    <ResetButtonLink
+      className="spacer-right"
       onClick={[Function]}
     >
       cancel
-    </Button>
+    </ResetButtonLink>
   </div>
 </Fragment>
 `;
@@ -56,12 +56,12 @@ exports[`displays cancel button when value changed and no error 1`] = `
     >
       save
     </Button>
-    <Button
-      className="spacer-right button-link"
+    <ResetButtonLink
+      className="spacer-right"
       onClick={[Function]}
     >
       cancel
-    </Button>
+    </ResetButtonLink>
   </div>
 </Fragment>
 `;
@@ -132,12 +132,12 @@ exports[`displays save button when it can be saved 1`] = `
     >
       save
     </Button>
-    <Button
-      className="spacer-right button-link"
+    <ResetButtonLink
+      className="spacer-right"
       onClick={[Function]}
     >
       cancel
-    </Button>
+    </ResetButtonLink>
   </div>
 </Fragment>
 `;
index 05e6b339080dbb1441bccbc535b1335a435be9fb..65712b193e73141f6244895755ffa4501c36a94c 100644 (file)
@@ -22,6 +22,7 @@ import SystemUpgradeItem from './SystemUpgradeItem';
 import { SystemUpgrade } from '../../../../api/system';
 import Modal from '../../../../components/controls/Modal';
 import { translate } from '../../../../helpers/l10n';
+import { ResetButtonLink } from '../../../../components/ui/buttons';
 
 interface Props {
   systemUpgrades: SystemUpgrade[][];
@@ -35,12 +36,6 @@ interface State {
 export default class SystemUpgradeForm extends React.PureComponent<Props, State> {
   state: State = { upgrading: false };
 
-  handleCancelClick = (event: React.SyntheticEvent<HTMLElement>) => {
-    event.preventDefault();
-    event.stopPropagation();
-    this.props.onClose();
-  };
-
   render() {
     const { upgrading } = this.state;
     const { systemUpgrades } = this.props;
@@ -63,12 +58,14 @@ export default class SystemUpgradeForm extends React.PureComponent<Props, State>
         </div>
         <div className="modal-foot">
           {upgrading && <i className="spinner spacer-right" />}
-          <a className="pull-left" href="https://www.sonarqube.org/downloads/" target="_blank">
+          <a
+            className="pull-left"
+            href="https://www.sonarqube.org/downloads/"
+            rel="noopener noreferrer"
+            target="_blank">
             {translate('system.see_sonarqube_downloads')}
           </a>
-          <a href="#" onClick={this.handleCancelClick}>
-            {translate('cancel')}
-          </a>
+          <ResetButtonLink onClick={this.props.onClose}>{translate('cancel')}</ResetButtonLink>
         </div>
       </Modal>
     );
index 5c7b10c1d3101f4e29f7f2df67c36a8b9ae62b73..cd49bba50d111df0272aad2befe6f0aded11c751 100644 (file)
@@ -18,8 +18,9 @@
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
 import * as React from 'react';
-import DropdownIcon from '../../../../components/icons-components/DropdownIcon';
 import DateFormatter from '../../../../components/intl/DateFormatter';
+import DropdownIcon from '../../../../components/icons-components/DropdownIcon';
+import { ButtonLink } from '../../../../components/ui/buttons';
 import { SystemUpgrade } from '../../../../api/system';
 import { translate } from '../../../../helpers/l10n';
 
@@ -35,9 +36,7 @@ interface State {
 export default class SystemUpgradeIntermediate extends React.PureComponent<Props, State> {
   state: State = { showMore: false };
 
-  toggleIntermediatVersions = (event: React.SyntheticEvent<HTMLAnchorElement>) => {
-    event.preventDefault();
-    event.stopPropagation();
+  toggleIntermediatVersions = () => {
     this.setState(state => ({ showMore: !state.showMore }));
   };
 
@@ -50,15 +49,12 @@ export default class SystemUpgradeIntermediate extends React.PureComponent<Props
 
     return (
       <div className={this.props.className}>
-        <a
-          className="button-link little-spacer-bottom"
-          href="#"
-          onClick={this.toggleIntermediatVersions}>
+        <ButtonLink className="little-spacer-bottom" onClick={this.toggleIntermediatVersions}>
           {showMore
             ? translate('system.hide_intermediate_versions')
             : translate('system.show_intermediate_versions')}
           <DropdownIcon className="little-spacer-left" turned={showMore} />
-        </a>
+        </ButtonLink>
         {showMore &&
           upgrades.map(upgrade => (
             <div className="note system-upgrade-intermediate" key={upgrade.version}>
@@ -68,7 +64,11 @@ export default class SystemUpgradeIntermediate extends React.PureComponent<Props
                     <b className="little-spacer-right">SonarQube {upgrade.version}</b>
                     {formattedDate}
                     {upgrade.changeLogUrl && (
-                      <a className="spacer-left" href={upgrade.changeLogUrl} target="_blank">
+                      <a
+                        className="spacer-left"
+                        href={upgrade.changeLogUrl}
+                        rel="noopener noreferrer"
+                        target="_blank">
                         {translate('system.release_notes')}
                       </a>
                     )}
index 1eb64b96ad342a3e6a03cc5952a33bdae3ea7b67..93e9e7b48e6c30da5313ca3043ac3bf02e963ec8 100644 (file)
@@ -53,7 +53,11 @@ export default function SystemUpgradeItem({ type, systemUpgrades }: Props) {
           )}
         </DateFormatter>
         {lastUpgrade.changeLogUrl && (
-          <a className="spacer-left" href={lastUpgrade.changeLogUrl} target="_blank">
+          <a
+            className="spacer-left"
+            href={lastUpgrade.changeLogUrl}
+            rel="noopener noreferrer"
+            target="_blank">
             {translate('system.release_notes')}
           </a>
         )}
index 02c2288a7068c5595e4ffeed55233e4076a5e451..2463af35e3b03c9552c4ac29843244c86c3215b6 100644 (file)
@@ -51,8 +51,8 @@ it('should display correctly', () => {
 it('should allow to show and hide intermediates', () => {
   const wrapper = shallow(<SystemUpgradeIntermediate upgrades={UPGRADES} />);
   expect(wrapper.find('.system-upgrade-intermediate').exists()).toBeFalsy();
-  click(wrapper.find('a'));
+  click(wrapper.find('ButtonLink'));
   expect(wrapper.find('.system-upgrade-intermediate').exists()).toBeTruthy();
-  click(wrapper.find('a'));
+  click(wrapper.find('ButtonLink'));
   expect(wrapper.find('.system-upgrade-intermediate').exists()).toBeFalsy();
 });
index 230aaf0a0a4a4edfc7347f5d635cd7d8f963c7fa..d061c790af2780dbfb5479c0ac5c261d038949fd 100644 (file)
@@ -78,16 +78,16 @@ exports[`should display correctly 1`] = `
     <a
       className="pull-left"
       href="https://www.sonarqube.org/downloads/"
+      rel="noopener noreferrer"
       target="_blank"
     >
       system.see_sonarqube_downloads
     </a>
-    <a
-      href="#"
-      onClick={[Function]}
+    <ResetButtonLink
+      onClick={[MockFunction]}
     >
       cancel
-    </a>
+    </ResetButtonLink>
   </div>
 </Modal>
 `;
index 332f91e64a184ac7493ae4a5a577f951d849c6af..763ab35301a1a941ade2c4f41f6494fb142f051d 100644 (file)
@@ -2,9 +2,8 @@
 
 exports[`should display correctly 1`] = `
 <div>
-  <a
-    className="button-link little-spacer-bottom"
-    href="#"
+  <ButtonLink
+    className="little-spacer-bottom"
     onClick={[Function]}
   >
     system.show_intermediate_versions
@@ -12,15 +11,14 @@ exports[`should display correctly 1`] = `
       className="little-spacer-left"
       turned={false}
     />
-  </a>
+  </ButtonLink>
 </div>
 `;
 
 exports[`should display correctly 2`] = `
 <div>
-  <a
-    className="button-link little-spacer-bottom"
-    href="#"
+  <ButtonLink
+    className="little-spacer-bottom"
     onClick={[Function]}
   >
     system.hide_intermediate_versions
@@ -28,7 +26,7 @@ exports[`should display correctly 2`] = `
       className="little-spacer-left"
       turned={true}
     />
-  </a>
+  </ButtonLink>
   <div
     className="note system-upgrade-intermediate"
     key="5.6.6"
index e6dc74c9bba679d51364d881720f40223142cc1f..68d1a8b3ab78f773dedf9bd89410b177ec56eac2 100644 (file)
@@ -35,6 +35,7 @@ exports[`should display correctly 1`] = `
     <a
       className="spacer-left"
       href="changelogurl"
+      rel="noopener noreferrer"
       target="_blank"
     >
       system.release_notes
index e3c8d442cf15b32d18dd10248c5bea83f3ce0da9..b951845416a8eb57aa7519b692f0718e7e1ff37e 100644 (file)
  */
 import * as React from 'react';
 import DeliveryAccordion from './DeliveryAccordion';
-import { Button } from '../../../components/ui/buttons';
 import DeferredSpinner from '../../../components/common/DeferredSpinner';
 import ListFooter from '../../../components/controls/ListFooter';
 import Modal from '../../../components/controls/Modal';
-import { translateWithParameters, translate } from '../../../helpers/l10n';
+import { ResetButtonLink } from '../../../components/ui/buttons';
 import { searchDeliveries } from '../../../api/webhooks';
+import { translateWithParameters, translate } from '../../../helpers/l10n';
 
 interface Props {
   onClose: () => void;
@@ -113,9 +113,9 @@ export default class DeliveriesForm extends React.PureComponent<Props, State> {
           )}
         </div>
         <footer className="modal-foot">
-          <Button className="button-link js-modal-close" onClick={this.props.onClose}>
+          <ResetButtonLink className="js-modal-close" onClick={this.props.onClose}>
             {translate('close')}
-          </Button>
+          </ResetButtonLink>
         </footer>
       </Modal>
     );
index 95b1bd1261baf40271d220ef07a146eecf47e1a3..7ae4866d9a39b94d4198fc6dc2f4a867e0205f5f 100644 (file)
  */
 import * as React from 'react';
 import DeliveryItem from './DeliveryItem';
-import { Button } from '../../../components/ui/buttons';
 import Modal from '../../../components/controls/Modal';
-import { translateWithParameters, translate } from '../../../helpers/l10n';
+import { ResetButtonLink } from '../../../components/ui/buttons';
 import { getDelivery } from '../../../api/webhooks';
+import { translateWithParameters, translate } from '../../../helpers/l10n';
 
 interface Props {
   delivery: T.WebhookDelivery;
@@ -88,9 +88,9 @@ export default class LatestDeliveryForm extends React.PureComponent<Props, State
           payload={payload}
         />
         <footer className="modal-foot">
-          <Button className="button-link js-modal-close" onClick={this.props.onClose}>
+          <ResetButtonLink className="js-modal-close" onClick={this.props.onClose}>
             {translate('close')}
-          </Button>
+          </ResetButtonLink>
         </footer>
       </Modal>
     );
index 2e67b17be4c586f4f462a0691b9657c645a405c7..ea4185ec91dc709671102bd23c89b3e65255cd9d 100644 (file)
@@ -27,12 +27,12 @@ exports[`should render correctly 1`] = `
   <footer
     className="modal-foot"
   >
-    <Button
-      className="button-link js-modal-close"
+    <ResetButtonLink
+      className="js-modal-close"
       onClick={[MockFunction]}
     >
       close
-    </Button>
+    </ResetButtonLink>
   </footer>
 </Modal>
 `;
@@ -95,12 +95,12 @@ exports[`should render correctly 2`] = `
   <footer
     className="modal-foot"
   >
-    <Button
-      className="button-link js-modal-close"
+    <ResetButtonLink
+      className="js-modal-close"
       onClick={[MockFunction]}
     >
       close
-    </Button>
+    </ResetButtonLink>
   </footer>
 </Modal>
 `;
index 46cbcab9f4a457104d89a41b4d5532501cf6ba5f..ef329112c67e7d1951d764a92f48bb26be96a362 100644 (file)
@@ -28,12 +28,12 @@ exports[`should render correctly 1`] = `
   <footer
     className="modal-foot"
   >
-    <Button
-      className="button-link js-modal-close"
+    <ResetButtonLink
+      className="js-modal-close"
       onClick={[MockFunction]}
     >
       close
-    </Button>
+    </ResetButtonLink>
   </footer>
 </Modal>
 `;
@@ -67,12 +67,12 @@ exports[`should render correctly 2`] = `
   <footer
     className="modal-foot"
   >
-    <Button
-      className="button-link js-modal-close"
+    <ResetButtonLink
+      className="js-modal-close"
       onClick={[MockFunction]}
     >
       close
-    </Button>
+    </ResetButtonLink>
   </footer>
 </Modal>
 `;
index 4f078bda1e82b4c2ada9bd469dba8f5fe1a9ef28..e34b22faf4dead3bd4ba1e9a2bcbc3b04e6d8a46 100644 (file)
@@ -21,7 +21,7 @@ import * as React from 'react';
 import { Link } from 'react-router';
 import { keyBy, sortBy, groupBy } from 'lodash';
 import MeasuresOverlayMeasure from './MeasuresOverlayMeasure';
-import { Button } from '../../ui/buttons';
+import { ResetButtonLink } from '../../ui/buttons';
 import { getFacets } from '../../../api/issues';
 import { getMeasures } from '../../../api/measures';
 import { getAllMetrics } from '../../../api/metrics';
@@ -440,9 +440,7 @@ export default class MeasuresOverlay extends React.PureComponent<Props, State> {
         </div>
 
         <footer className="modal-foot">
-          <Button className="button-link" onClick={this.props.onClose}>
-            {translate('close')}
-          </Button>
+          <ResetButtonLink onClick={this.props.onClose}>{translate('close')}</ResetButtonLink>
         </footer>
       </Modal>
     );
index a6b23d821770e1ab2510bf3880d533ff4e298d7d..71583aa014bcb7504f69e98bcdfa6e0de5756f2b 100644 (file)
@@ -350,12 +350,11 @@ exports[`should render source file 1`] = `
   <footer
     className="modal-foot"
   >
-    <Button
-      className="button-link"
+    <ResetButtonLink
       onClick={[MockFunction]}
     >
       close
-    </Button>
+    </ResetButtonLink>
   </footer>
 </Modal>
 `;
@@ -1316,12 +1315,11 @@ exports[`should render source file 2`] = `
   <footer
     className="modal-foot"
   >
-    <Button
-      className="button-link"
+    <ResetButtonLink
       onClick={[MockFunction]}
     >
       close
-    </Button>
+    </ResetButtonLink>
   </footer>
 </Modal>
 `;
@@ -1464,12 +1462,11 @@ exports[`should render test file 1`] = `
   <footer
     className="modal-foot"
   >
-    <Button
-      className="button-link"
+    <ResetButtonLink
       onClick={[MockFunction]}
     >
       close
-    </Button>
+    </ResetButtonLink>
   </footer>
 </Modal>
 `;
index 3f6cfeeea1a3f12b5a15ff09a173ca859913c728..af3ba46ed6807d3d79f88141861da2342c8caf4f 100644 (file)
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
 import * as React from 'react';
-import SetAssigneePopup from '../popups/SetAssigneePopup';
 import Avatar from '../../ui/Avatar';
-import Toggler from '../../controls/Toggler';
 import DropdownIcon from '../../icons-components/DropdownIcon';
-import { Button } from '../../ui/buttons';
+import SetAssigneePopup from '../popups/SetAssigneePopup';
+import Toggler from '../../controls/Toggler';
+import { ButtonLink } from '../../ui/buttons';
 import { translate } from '../../../helpers/l10n';
 
 interface Props {
@@ -72,12 +72,12 @@ export default class IssueAssign extends React.PureComponent<Props> {
             onRequestClose={this.handleClose}
             open={this.props.isOpen && this.props.canAssign}
             overlay={<SetAssigneePopup issue={this.props.issue} onSelect={this.props.onAssign} />}>
-            <Button
-              className="button-link issue-action issue-action-with-options js-issue-assign"
+            <ButtonLink
+              className="issue-action issue-action-with-options js-issue-assign"
               onClick={this.toggleAssign}>
               {this.renderAssignee()}
               <DropdownIcon className="little-spacer-left" />
-            </Button>
+            </ButtonLink>
           </Toggler>
         </div>
       );
index 45506de4485f9e98d2f65c8527a7660a4925b8a6..8c22691e38640b6f74ae892260ea8b4f9c80e7db 100644 (file)
  */
 import * as React from 'react';
 import ChangelogPopup from '../popups/ChangelogPopup';
-import DropdownIcon from '../../icons-components/DropdownIcon';
 import DateFromNow from '../../intl/DateFromNow';
 import DateTimeFormatter from '../../intl/DateTimeFormatter';
+import DropdownIcon from '../../icons-components/DropdownIcon';
 import Toggler from '../../controls/Toggler';
 import Tooltip from '../../controls/Tooltip';
-import { Button } from '../../ui/buttons';
+import { ButtonLink } from '../../ui/buttons';
 
 interface Props {
   isOpen: boolean;
@@ -56,14 +56,14 @@ export default class IssueChangelog extends React.PureComponent<Props> {
           <Tooltip
             mouseEnterDelay={0.5}
             overlay={<DateTimeFormatter date={this.props.creationDate} />}>
-            <Button
-              className="button-link issue-action issue-action-with-options js-issue-show-changelog"
+            <ButtonLink
+              className="issue-action issue-action-with-options js-issue-show-changelog"
               onClick={this.handleClick}>
               <span className="issue-meta-label">
                 <DateFromNow date={this.props.creationDate} />
               </span>
               <DropdownIcon className="little-spacer-left" />
-            </Button>
+            </ButtonLink>
           </Tooltip>
         </Toggler>
       </div>
index 70ae7675aef11b5b4a3c2b6f663068762e468130..63e97cc98c90db853a16862ddc20f9e51f9c1204 100644 (file)
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
 import * as React from 'react';
-import { updateIssue } from '../actions';
-import Toggler from '../../controls/Toggler';
-import { Button } from '../../ui/buttons';
 import CommentPopup from '../popups/CommentPopup';
+import Toggler from '../../controls/Toggler';
+import { ButtonLink } from '../../ui/buttons';
 import { addIssueComment } from '../../../api/issues';
 import { translate } from '../../../helpers/l10n';
+import { updateIssue } from '../actions';
 
 interface Props {
   commentPlaceholder: string;
@@ -61,11 +61,9 @@ export default class IssueCommentAction extends React.PureComponent<Props> {
               toggleComment={this.props.toggleComment}
             />
           }>
-          <Button
-            className="button-link issue-action js-issue-comment"
-            onClick={this.handleCommentClick}>
+          <ButtonLink className="issue-action js-issue-comment" onClick={this.handleCommentClick}>
             <span className="issue-meta-label">{translate('issue.comment.formlink')}</span>
-          </Button>
+          </ButtonLink>
         </Toggler>
       </li>
     );
index cf36a5c024d4bf2b16d000e89ab70dd9734b40cf..51586026298f234306cea8201ae0f8acd8611210 100644 (file)
@@ -20,9 +20,9 @@
 import * as React from 'react';
 import EllipsisIcon from '../../icons-components/EllipsisIcon';
 import Tooltip from '../../controls/Tooltip';
-import { translate, translateWithParameters } from '../../../helpers/l10n';
-import { Button } from '../../ui/buttons';
+import { ButtonLink } from '../../ui/buttons';
 import { WorkspaceContextShape } from '../../workspace/context';
+import { translate, translateWithParameters } from '../../../helpers/l10n';
 
 interface Props {
   engine?: string;
@@ -45,12 +45,12 @@ export default class IssueMessage extends React.PureComponent<Props> {
     return (
       <div className="issue-message">
         {this.props.message}
-        <Button
+        <ButtonLink
           aria-label={translate('issue.rule_details')}
-          className="button-link issue-rule little-spacer-left"
+          className="issue-rule little-spacer-left"
           onClick={this.handleClick}>
           <EllipsisIcon />
-        </Button>
+        </ButtonLink>
         {this.props.engine && (
           <Tooltip
             overlay={translateWithParameters('issue.from_external_rule_engine', this.props.engine)}>
index a4b51e884b5d29bfc6aca84b6ad70f2a552dc2a5..2005cab4dcd408733157a5c5a87d18a066d13247 100644 (file)
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
 import * as React from 'react';
-import SetSeverityPopup from '../popups/SetSeverityPopup';
-import { setIssueSeverity, IssueResponse } from '../../../api/issues';
-import Toggler from '../../controls/Toggler';
 import DropdownIcon from '../../icons-components/DropdownIcon';
+import SetSeverityPopup from '../popups/SetSeverityPopup';
 import SeverityHelper from '../../shared/SeverityHelper';
-import { Button } from '../../ui/buttons';
+import Toggler from '../../controls/Toggler';
+import { ButtonLink } from '../../ui/buttons';
+import { setIssueSeverity, IssueResponse } from '../../../api/issues';
 import { RawQuery } from '../../../helpers/query';
 
 interface Props {
@@ -61,12 +61,12 @@ export default class IssueSeverity extends React.PureComponent<Props> {
             onRequestClose={this.handleClose}
             open={this.props.isOpen && this.props.canSetSeverity}
             overlay={<SetSeverityPopup issue={issue} onSelect={this.setSeverity} />}>
-            <Button
-              className="button-link issue-action issue-action-with-options js-issue-set-severity"
+            <ButtonLink
+              className="issue-action issue-action-with-options js-issue-set-severity"
               onClick={this.toggleSetSeverity}>
               <SeverityHelper className="issue-meta-label" severity={issue.severity} />
               <DropdownIcon className="little-spacer-left" />
-            </Button>
+            </ButtonLink>
           </Toggler>
         </div>
       );
index 189e8396c9c0847ea28cdcbaa68625459210c03d..2692b3f61ec7e1464a6fe3d1bc50cc7a08206fbb 100644 (file)
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
 import * as React from 'react';
-import { updateIssue } from '../actions';
 import SetIssueTagsPopup from '../popups/SetIssueTagsPopup';
-import { setIssueTags } from '../../../api/issues';
-import Toggler from '../../controls/Toggler';
 import TagsList from '../../tags/TagsList';
-import { Button } from '../../ui/buttons';
+import Toggler from '../../controls/Toggler';
+import { ButtonLink } from '../../ui/buttons';
+import { setIssueTags } from '../../../api/issues';
 import { translate } from '../../../helpers/l10n';
+import { updateIssue } from '../actions';
 
 interface Props {
   canSetTags: boolean;
@@ -71,8 +71,8 @@ export default class IssueTags extends React.PureComponent<Props> {
                 setTags={this.setTags}
               />
             }>
-            <Button
-              className={'js-issue-edit-tags button-link issue-action issue-action-with-options'}
+            <ButtonLink
+              className="issue-action issue-action-with-options js-issue-edit-tags"
               onClick={this.toggleSetTags}>
               <TagsList
                 allowUpdate={this.props.canSetTags}
@@ -80,7 +80,7 @@ export default class IssueTags extends React.PureComponent<Props> {
                   issue.tags && issue.tags.length > 0 ? issue.tags : [translate('issue.no_tag')]
                 }
               />
-            </Button>
+            </ButtonLink>
           </Toggler>
         </div>
       );
index 34489320d1009c961d6c0c008f523819c6f591b9..f464ccab2ceffc6af879afe4a0132ca953894ccc 100644 (file)
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
 import * as React from 'react';
-import { updateIssue } from '../actions';
-import SetTransitionPopup from '../popups/SetTransitionPopup';
-import { setIssueTransition } from '../../../api/issues';
-import Toggler from '../../controls/Toggler';
 import DropdownIcon from '../../icons-components/DropdownIcon';
+import SetTransitionPopup from '../popups/SetTransitionPopup';
 import StatusHelper from '../../shared/StatusHelper';
-import { Button } from '../../ui/buttons';
+import Toggler from '../../controls/Toggler';
+import { ButtonLink } from '../../ui/buttons';
+import { setIssueTransition } from '../../../api/issues';
+import { updateIssue } from '../actions';
 
 interface Props {
   hasTransitions: boolean;
@@ -63,8 +63,8 @@ export default class IssueTransition extends React.PureComponent<Props> {
             overlay={
               <SetTransitionPopup onSelect={this.setTransition} transitions={issue.transitions} />
             }>
-            <Button
-              className="button-link issue-action issue-action-with-options js-issue-transition"
+            <ButtonLink
+              className="issue-action issue-action-with-options js-issue-transition"
               onClick={this.toggleSetTransition}>
               <StatusHelper
                 className="issue-meta-label"
@@ -72,7 +72,7 @@ export default class IssueTransition extends React.PureComponent<Props> {
                 status={issue.status}
               />
               <DropdownIcon className="little-spacer-left" />
-            </Button>
+            </ButtonLink>
           </Toggler>
         </div>
       );
index 3788b2c687fb624adc30a2d91a2274f856b08e74..7cf5e86a3918ccd9844ef9af74fb61050674c9f7 100644 (file)
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
 import * as React from 'react';
-import SetTypePopup from '../popups/SetTypePopup';
-import { setIssueType, IssueResponse } from '../../../api/issues';
-import Toggler from '../../controls/Toggler';
 import DropdownIcon from '../../icons-components/DropdownIcon';
-import { Button } from '../../ui/buttons';
 import IssueTypeIcon from '../../ui/IssueTypeIcon';
+import SetTypePopup from '../popups/SetTypePopup';
+import Toggler from '../../controls/Toggler';
+import { ButtonLink } from '../../ui/buttons';
+import { setIssueType, IssueResponse } from '../../../api/issues';
 import { translate } from '../../../helpers/l10n';
 import { RawQuery } from '../../../helpers/query';
 
@@ -62,13 +62,13 @@ export default class IssueType extends React.PureComponent<Props> {
             onRequestClose={this.handleClose}
             open={this.props.isOpen && this.props.canSetType}
             overlay={<SetTypePopup issue={issue} onSelect={this.setType} />}>
-            <Button
-              className="button-link issue-action issue-action-with-options js-issue-set-type"
+            <ButtonLink
+              className="issue-action issue-action-with-options js-issue-set-type"
               onClick={this.toggleSetType}>
               <IssueTypeIcon className="little-spacer-right" query={issue.type} />
               {translate('issue.type', issue.type)}
               <DropdownIcon className="little-spacer-left" />
-            </Button>
+            </ButtonLink>
           </Toggler>
         </div>
       );
index 9270e8d8ca70ef137bad2ff71929e9d84916b606..407e14a5ce6d7d7fdec1af7f77399bc64be25634 100644 (file)
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
 import * as React from 'react';
-import SimilarIssuesPopup from '../popups/SimilarIssuesPopup';
-import Toggler from '../../controls/Toggler';
 import DropdownIcon from '../../icons-components/DropdownIcon';
 import FilterIcon from '../../icons-components/FilterIcon';
-import { Button } from '../../ui/buttons';
+import SimilarIssuesPopup from '../popups/SimilarIssuesPopup';
+import Toggler from '../../controls/Toggler';
+import { ButtonLink } from '../../ui/buttons';
 import { translate } from '../../../helpers/l10n';
 
 interface Props {
@@ -55,14 +55,14 @@ export default class SimilarIssuesFilter extends React.PureComponent<Props> {
           onRequestClose={this.handleClose}
           open={this.props.isOpen}
           overlay={<SimilarIssuesPopup issue={this.props.issue} onFilter={this.handleFilter} />}>
-          <Button
+          <ButtonLink
             aria-label={translate('issue.filter_similar_issues')}
-            className="js-issue-filter button-link issue-action issue-action-with-options"
+            className="issue-action issue-action-with-options js-issue-filter"
             onClick={this.togglePopup}
             title={translate('issue.filter_similar_issues')}>
             <FilterIcon className="icon-half-transparent" />
             <DropdownIcon className="icon-half-transparent" />
-          </Button>
+          </ButtonLink>
         </Toggler>
       </div>
     );
index 9c5b0d95fe1d742a06d9117635b9f212b867919c..b3d325671245dc2ed342a8a93138900b42dc2428 100644 (file)
@@ -30,44 +30,31 @@ const issue = {
 };
 
 it('should render without the action when the correct rights are missing', () => {
-  const element = shallow(
-    <IssueAssign
-      canAssign={false}
-      isOpen={false}
-      issue={issue}
-      onAssign={jest.fn()}
-      togglePopup={jest.fn()}
-    />
-  );
-  expect(element).toMatchSnapshot();
+  expect(shallowRender({ canAssign: false })).toMatchSnapshot();
 });
 
 it('should render with the action', () => {
-  const element = shallow(
-    <IssueAssign
-      canAssign={true}
-      isOpen={false}
-      issue={issue}
-      onAssign={jest.fn()}
-      togglePopup={jest.fn()}
-    />
-  );
-  expect(element).toMatchSnapshot();
+  expect(shallowRender()).toMatchSnapshot();
 });
 
 it('should open the popup when the button is clicked', () => {
-  const toggle = jest.fn();
-  const element = shallow(
+  const togglePopup = jest.fn();
+  const element = shallowRender({ togglePopup });
+  click(element.find('ButtonLink'));
+  expect(togglePopup.mock.calls).toMatchSnapshot();
+  element.setProps({ isOpen: true });
+  expect(element).toMatchSnapshot();
+});
+
+function shallowRender(props: Partial<IssueAssign['props']> = {}) {
+  return shallow(
     <IssueAssign
       canAssign={true}
       isOpen={false}
       issue={issue}
       onAssign={jest.fn()}
-      togglePopup={toggle}
+      togglePopup={jest.fn()}
+      {...props}
     />
   );
-  click(element.find('Button'));
-  expect(toggle.mock.calls).toMatchSnapshot();
-  element.setProps({ isOpen: true });
-  expect(element).toMatchSnapshot();
-});
+}
index 0439969f4230b6e8e943434bf248bfeb6f081425..84cc1d412a43ad6296ee5798781b8cedcb86129f 100644 (file)
@@ -29,29 +29,27 @@ const issue = {
 };
 
 it('should render correctly', () => {
-  const element = shallow(
-    <IssueChangelog
-      creationDate="2017-03-01T09:36:01+0100"
-      isOpen={false}
-      issue={issue}
-      togglePopup={jest.fn()}
-    />
-  );
+  const element = shallowRender();
   expect(element).toMatchSnapshot();
 });
 
 it('should open the popup when the button is clicked', () => {
-  const toggle = jest.fn();
-  const element = shallow(
+  const togglePopup = jest.fn();
+  const element = shallowRender({ togglePopup });
+  click(element.find('ButtonLink'));
+  expect(togglePopup.mock.calls).toMatchSnapshot();
+  element.setProps({ isOpen: true });
+  expect(element).toMatchSnapshot();
+});
+
+function shallowRender(props: Partial<IssueChangelog['props']> = {}) {
+  return shallow(
     <IssueChangelog
       creationDate="2017-03-01T09:36:01+0100"
       isOpen={false}
       issue={issue}
-      togglePopup={toggle}
+      togglePopup={jest.fn()}
+      {...props}
     />
   );
-  click(element.find('Button'));
-  expect(toggle.mock.calls).toMatchSnapshot();
-  element.setProps({ isOpen: true });
-  expect(element).toMatchSnapshot();
-});
+}
index 6b362d4094b83b4cf692d57b3efc72d89289fde9..8cf54201ad5d85685630dbd59d1fa6e34fe7f741 100644 (file)
@@ -23,29 +23,26 @@ import IssueCommentAction from '../IssueCommentAction';
 import { click } from '../../../../helpers/testUtils';
 
 it('should render correctly', () => {
-  const element = shallow(
-    <IssueCommentAction
-      commentPlaceholder=""
-      issueKey="issue-key"
-      onChange={jest.fn()}
-      toggleComment={jest.fn()}
-    />
-  );
-  expect(element).toMatchSnapshot();
+  expect(shallowRender()).toMatchSnapshot();
 });
 
 it('should open the popup when the button is clicked', () => {
-  const toggle = jest.fn();
-  const element = shallow(
+  const toggleComment = jest.fn();
+  const element = shallowRender({ toggleComment });
+  click(element.find('ButtonLink'));
+  expect(toggleComment.mock.calls.length).toBe(1);
+  element.setProps({ currentPopup: 'comment' });
+  expect(element).toMatchSnapshot();
+});
+
+function shallowRender(props: Partial<IssueCommentAction['props']> = {}) {
+  return shallow(
     <IssueCommentAction
       commentPlaceholder=""
       issueKey="issue-key"
       onChange={jest.fn()}
-      toggleComment={toggle}
+      toggleComment={jest.fn()}
+      {...props}
     />
   );
-  click(element.find('Button'));
-  expect(toggle.mock.calls.length).toBe(1);
-  element.setProps({ currentPopup: 'comment' });
-  expect(element).toMatchSnapshot();
-});
+}
index d690b3d89d011e413a09b8250652ab464727c832..517e907e034d39ed5560027aecaf70b60d360491 100644 (file)
@@ -22,49 +22,34 @@ import { shallow } from 'enzyme';
 import IssueSeverity from '../IssueSeverity';
 import { click } from '../../../../helpers/testUtils';
 
-const issue = {
-  severity: 'BLOCKER'
-};
+const issue = { severity: 'BLOCKER' };
 
 it('should render without the action when the correct rights are missing', () => {
-  const element = shallow(
-    <IssueSeverity
-      canSetSeverity={false}
-      isOpen={false}
-      issue={issue}
-      setIssueProperty={jest.fn()}
-      togglePopup={jest.fn()}
-    />
-  );
-  expect(element).toMatchSnapshot();
+  expect(shallowRender({ canSetSeverity: false })).toMatchSnapshot();
 });
 
 it('should render with the action', () => {
-  const element = shallow(
-    <IssueSeverity
-      canSetSeverity={true}
-      isOpen={false}
-      issue={issue}
-      setIssueProperty={jest.fn()}
-      togglePopup={jest.fn()}
-    />
-  );
-  expect(element).toMatchSnapshot();
+  expect(shallowRender()).toMatchSnapshot();
 });
 
 it('should open the popup when the button is clicked', () => {
-  const toggle = jest.fn();
-  const element = shallow(
+  const togglePopup = jest.fn();
+  const element = shallowRender({ togglePopup });
+  click(element.find('ButtonLink'));
+  expect(togglePopup.mock.calls).toMatchSnapshot();
+  element.setProps({ isOpen: true });
+  expect(element).toMatchSnapshot();
+});
+
+function shallowRender(props: Partial<IssueSeverity['props']> = {}) {
+  return shallow(
     <IssueSeverity
       canSetSeverity={true}
       isOpen={false}
       issue={issue}
       setIssueProperty={jest.fn()}
-      togglePopup={toggle}
+      togglePopup={jest.fn()}
+      {...props}
     />
   );
-  click(element.find('Button'));
-  expect(toggle.mock.calls).toMatchSnapshot();
-  element.setProps({ isOpen: true });
-  expect(element).toMatchSnapshot();
-});
+}
index 7acb16f9f0342f803bf24a30def39e9ffe02af7a..01647557f6b5514509f8aa82e58768d8b7c94ded 100644 (file)
@@ -22,51 +22,34 @@ import { shallow } from 'enzyme';
 import IssueTags from '../IssueTags';
 import { click } from '../../../../helpers/testUtils';
 
-const issue = {
-  key: 'issuekey',
-  projectOrganization: 'foo',
-  tags: ['mytag', 'test']
-};
+const issue = { key: 'issuekey', projectOrganization: 'foo', tags: ['mytag', 'test'] };
 
 it('should render without the action when the correct rights are missing', () => {
-  const element = shallow(
-    <IssueTags
-      canSetTags={false}
-      isOpen={false}
-      issue={{ ...issue, tags: [] }}
-      onChange={jest.fn()}
-      togglePopup={jest.fn()}
-    />
-  );
-  expect(element).toMatchSnapshot();
+  expect(shallowRender({ canSetTags: false, issue: { ...issue, tags: [] } })).toMatchSnapshot();
 });
 
 it('should render with the action', () => {
-  const element = shallow(
-    <IssueTags
-      canSetTags={true}
-      isOpen={false}
-      issue={issue}
-      onChange={jest.fn()}
-      togglePopup={jest.fn()}
-    />
-  );
-  expect(element).toMatchSnapshot();
+  expect(shallowRender()).toMatchSnapshot();
 });
 
 it('should open the popup when the button is clicked', () => {
-  const toggle = jest.fn();
-  const element = shallow(
+  const togglePopup = jest.fn();
+  const element = shallowRender({ togglePopup });
+  click(element.find('ButtonLink'));
+  expect(togglePopup.mock.calls).toMatchSnapshot();
+  element.setProps({ isOpen: true });
+  expect(element).toMatchSnapshot();
+});
+
+function shallowRender(props: Partial<IssueTags['props']> = {}) {
+  return shallow(
     <IssueTags
       canSetTags={true}
       isOpen={false}
       issue={issue}
       onChange={jest.fn()}
-      togglePopup={toggle}
+      togglePopup={jest.fn()}
+      {...props}
     />
   );
-  click(element.find('Button'));
-  expect(toggle.mock.calls).toMatchSnapshot();
-  element.setProps({ isOpen: true });
-  expect(element).toMatchSnapshot();
-});
+}
index e2cfb1a4029c14e58a05593c6bf3c6294e1dc692..74d1f1331291e0ec9a143eb915ff39a25c32d1b6 100644 (file)
@@ -29,66 +29,49 @@ const issue = {
 };
 
 it('should render without the action when there is no transitions', () => {
-  const element = shallow(
-    <IssueTransition
-      hasTransitions={false}
-      isOpen={false}
-      issue={{
-        key: 'foo1234',
-        transitions: [],
-        status: 'CLOSED'
-      }}
-      onChange={jest.fn()}
-      togglePopup={jest.fn()}
-    />
-  );
-  expect(element).toMatchSnapshot();
+  expect(
+    shallowRender({
+      hasTransitions: false,
+      issue: { key: 'foo1234', transitions: [], status: 'CLOSED' }
+    })
+  ).toMatchSnapshot();
 });
 
 it('should render with the action', () => {
-  const element = shallow(
-    <IssueTransition
-      hasTransitions={true}
-      isOpen={false}
-      issue={issue}
-      onChange={jest.fn()}
-      togglePopup={jest.fn()}
-    />
-  );
-  expect(element).toMatchSnapshot();
+  expect(shallowRender()).toMatchSnapshot();
 });
 
 it('should render with a resolution', () => {
-  const element = shallow(
-    <IssueTransition
-      hasTransitions={true}
-      isOpen={false}
-      issue={{
+  expect(
+    shallowRender({
+      issue: {
         key: 'foo1234',
         transitions: ['reopen'],
         status: 'RESOLVED',
         resolution: 'FIXED'
-      }}
-      onChange={jest.fn()}
-      togglePopup={jest.fn()}
-    />
-  );
-  expect(element).toMatchSnapshot();
+      }
+    })
+  ).toMatchSnapshot();
 });
 
 it('should open the popup when the button is clicked', () => {
-  const toggle = jest.fn();
-  const element = shallow(
+  const togglePopup = jest.fn();
+  const element = shallowRender({ togglePopup });
+  click(element.find('ButtonLink'));
+  expect(togglePopup.mock.calls).toMatchSnapshot();
+  element.setProps({ isOpen: true });
+  expect(element).toMatchSnapshot();
+});
+
+function shallowRender(props: Partial<IssueTransition['props']> = {}) {
+  return shallow(
     <IssueTransition
       hasTransitions={true}
       isOpen={false}
       issue={issue}
       onChange={jest.fn()}
-      togglePopup={toggle}
+      togglePopup={jest.fn()}
+      {...props}
     />
   );
-  click(element.find('Button'));
-  expect(toggle.mock.calls).toMatchSnapshot();
-  element.setProps({ isOpen: true });
-  expect(element).toMatchSnapshot();
-});
+}
index bb7312a1e6409b4cdd07624e99e45b1b56909ec8..014b655597914dc4031a9b88ced1111896416a1f 100644 (file)
@@ -22,49 +22,34 @@ import { shallow } from 'enzyme';
 import IssueType from '../IssueType';
 import { click } from '../../../../helpers/testUtils';
 
-const issue: Pick<T.Issue, 'type'> = {
-  type: 'BUG'
-};
+const issue: Pick<T.Issue, 'type'> = { type: 'BUG' };
 
 it('should render without the action when the correct rights are missing', () => {
-  const element = shallow(
-    <IssueType
-      canSetType={false}
-      isOpen={false}
-      issue={issue}
-      setIssueProperty={jest.fn()}
-      togglePopup={jest.fn()}
-    />
-  );
-  expect(element).toMatchSnapshot();
+  expect(shallowRender({ canSetType: false })).toMatchSnapshot();
 });
 
 it('should render with the action', () => {
-  const element = shallow(
-    <IssueType
-      canSetType={true}
-      isOpen={false}
-      issue={issue}
-      setIssueProperty={jest.fn()}
-      togglePopup={jest.fn()}
-    />
-  );
-  expect(element).toMatchSnapshot();
+  expect(shallowRender()).toMatchSnapshot();
 });
 
 it('should open the popup when the button is clicked', () => {
-  const toggle = jest.fn();
-  const element = shallow(
+  const togglePopup = jest.fn();
+  const element = shallowRender({ togglePopup });
+  click(element.find('ButtonLink'));
+  expect(togglePopup.mock.calls).toMatchSnapshot();
+  element.setProps({ isOpen: true });
+  expect(element).toMatchSnapshot();
+});
+
+function shallowRender(props: Partial<IssueType['props']> = {}) {
+  return shallow(
     <IssueType
       canSetType={true}
       isOpen={false}
       issue={issue}
       setIssueProperty={jest.fn()}
-      togglePopup={toggle}
+      togglePopup={jest.fn()}
+      {...props}
     />
   );
-  click(element.find('Button'));
-  expect(toggle.mock.calls).toMatchSnapshot();
-  element.setProps({ isOpen: true });
-  expect(element).toMatchSnapshot();
-});
+}
index 935728e035ad0954db781db117a1a8206017118a..0b8921f3cd4eb11f5b0f61a361f7d48c01f66471 100644 (file)
@@ -31,8 +31,8 @@ exports[`should open the popup when the button is clicked 2`] = `
       />
     }
   >
-    <Button
-      className="button-link issue-action issue-action-with-options js-issue-assign"
+    <ButtonLink
+      className="issue-action issue-action-with-options js-issue-assign"
       onClick={[Function]}
     >
       <span>
@@ -55,7 +55,7 @@ exports[`should open the popup when the button is clicked 2`] = `
       <DropdownIcon
         className="little-spacer-left"
       />
-    </Button>
+    </ButtonLink>
   </Toggler>
 </div>
 `;
@@ -82,8 +82,8 @@ exports[`should render with the action 1`] = `
       />
     }
   >
-    <Button
-      className="button-link issue-action issue-action-with-options js-issue-assign"
+    <ButtonLink
+      className="issue-action issue-action-with-options js-issue-assign"
       onClick={[Function]}
     >
       <span>
@@ -106,7 +106,7 @@ exports[`should render with the action 1`] = `
       <DropdownIcon
         className="little-spacer-left"
       />
-    </Button>
+    </ButtonLink>
   </Toggler>
 </div>
 `;
index fad46a6b759839f10203b737465f1a0992bd3190..fbce7a8945eb5deefe5f122803ee48beaa270787 100644 (file)
@@ -36,8 +36,8 @@ exports[`should open the popup when the button is clicked 2`] = `
         />
       }
     >
-      <Button
-        className="button-link issue-action issue-action-with-options js-issue-show-changelog"
+      <ButtonLink
+        className="issue-action issue-action-with-options js-issue-show-changelog"
         onClick={[Function]}
       >
         <span
@@ -50,7 +50,7 @@ exports[`should open the popup when the button is clicked 2`] = `
         <DropdownIcon
           className="little-spacer-left"
         />
-      </Button>
+      </ButtonLink>
     </Tooltip>
   </Toggler>
 </div>
@@ -83,8 +83,8 @@ exports[`should render correctly 1`] = `
         />
       }
     >
-      <Button
-        className="button-link issue-action issue-action-with-options js-issue-show-changelog"
+      <ButtonLink
+        className="issue-action issue-action-with-options js-issue-show-changelog"
         onClick={[Function]}
       >
         <span
@@ -97,7 +97,7 @@ exports[`should render correctly 1`] = `
         <DropdownIcon
           className="little-spacer-left"
         />
-      </Button>
+      </ButtonLink>
     </Tooltip>
   </Toggler>
 </div>
index 0e6d7be6ca98c15740c42ed5f1485154eb6d3ce9..dd0111a0502fd1de24fbc1986ae536384656de04 100644 (file)
@@ -28,8 +28,8 @@ exports[`should open the popup when the button is clicked 1`] = `
       />
     }
   >
-    <Button
-      className="button-link issue-action js-issue-comment"
+    <ButtonLink
+      className="issue-action js-issue-comment"
       onClick={[Function]}
     >
       <span
@@ -37,7 +37,7 @@ exports[`should open the popup when the button is clicked 1`] = `
       >
         issue.comment.formlink
       </span>
-    </Button>
+    </ButtonLink>
   </Toggler>
 </li>
 `;
@@ -58,8 +58,8 @@ exports[`should render correctly 1`] = `
       />
     }
   >
-    <Button
-      className="button-link issue-action js-issue-comment"
+    <ButtonLink
+      className="issue-action js-issue-comment"
       onClick={[Function]}
     >
       <span
@@ -67,7 +67,7 @@ exports[`should render correctly 1`] = `
       >
         issue.comment.formlink
       </span>
-    </Button>
+    </ButtonLink>
   </Toggler>
 </li>
 `;
index edda212b2f0f2a474f660a18a5c32bfab8321d13..2c54ba0f2af9e4a727cb8886025900f02c6d2979 100644 (file)
@@ -5,12 +5,12 @@ exports[`should render with the message and a link to open the rule 1`] = `
   className="issue-message"
 >
   Reduce the number of conditional operators (4) used in the expression
-  <Button
+  <ButtonLink
     aria-label="issue.rule_details"
-    className="button-link issue-rule little-spacer-left"
+    className="issue-rule little-spacer-left"
     onClick={[Function]}
   >
     <EllipsisIcon />
-  </Button>
+  </ButtonLink>
 </div>
 `;
index 898a75fd3d669f5ce271ca6df77e8cf50f68e972..666c4bb4d4741faf372665fc44b16e060b89eec1 100644 (file)
@@ -27,8 +27,8 @@ exports[`should open the popup when the button is clicked 2`] = `
       />
     }
   >
-    <Button
-      className="button-link issue-action issue-action-with-options js-issue-set-severity"
+    <ButtonLink
+      className="issue-action issue-action-with-options js-issue-set-severity"
       onClick={[Function]}
     >
       <SeverityHelper
@@ -38,7 +38,7 @@ exports[`should open the popup when the button is clicked 2`] = `
       <DropdownIcon
         className="little-spacer-left"
       />
-    </Button>
+    </ButtonLink>
   </Toggler>
 </div>
 `;
@@ -61,8 +61,8 @@ exports[`should render with the action 1`] = `
       />
     }
   >
-    <Button
-      className="button-link issue-action issue-action-with-options js-issue-set-severity"
+    <ButtonLink
+      className="issue-action issue-action-with-options js-issue-set-severity"
       onClick={[Function]}
     >
       <SeverityHelper
@@ -72,7 +72,7 @@ exports[`should render with the action 1`] = `
       <DropdownIcon
         className="little-spacer-left"
       />
-    </Button>
+    </ButtonLink>
   </Toggler>
 </div>
 `;
index ca33fb7f1ec4efaee5885c66bfb9fb9252f72355..33b1bf6a40bc0aa9cd1941c93a4dd65d801faead 100644 (file)
@@ -29,8 +29,8 @@ exports[`should open the popup when the button is clicked 2`] = `
       />
     }
   >
-    <Button
-      className="js-issue-edit-tags button-link issue-action issue-action-with-options"
+    <ButtonLink
+      className="issue-action issue-action-with-options js-issue-edit-tags"
       onClick={[Function]}
     >
       <TagsList
@@ -42,7 +42,7 @@ exports[`should open the popup when the button is clicked 2`] = `
           ]
         }
       />
-    </Button>
+    </ButtonLink>
   </Toggler>
 </div>
 `;
@@ -67,8 +67,8 @@ exports[`should render with the action 1`] = `
       />
     }
   >
-    <Button
-      className="js-issue-edit-tags button-link issue-action issue-action-with-options"
+    <ButtonLink
+      className="issue-action issue-action-with-options js-issue-edit-tags"
       onClick={[Function]}
     >
       <TagsList
@@ -80,7 +80,7 @@ exports[`should render with the action 1`] = `
           ]
         }
       />
-    </Button>
+    </ButtonLink>
   </Toggler>
 </div>
 `;
index dcfe4ff35ea0e1e49a43781a0adf40114c8c08e8..f5decbbd71b1e00b4d0faf0bd636c5a6827f4633 100644 (file)
@@ -30,8 +30,8 @@ exports[`should open the popup when the button is clicked 2`] = `
       />
     }
   >
-    <Button
-      className="button-link issue-action issue-action-with-options js-issue-transition"
+    <ButtonLink
+      className="issue-action issue-action-with-options js-issue-transition"
       onClick={[Function]}
     >
       <StatusHelper
@@ -41,7 +41,7 @@ exports[`should open the popup when the button is clicked 2`] = `
       <DropdownIcon
         className="little-spacer-left"
       />
-    </Button>
+    </ButtonLink>
   </Toggler>
 </div>
 `;
@@ -64,8 +64,8 @@ exports[`should render with a resolution 1`] = `
       />
     }
   >
-    <Button
-      className="button-link issue-action issue-action-with-options js-issue-transition"
+    <ButtonLink
+      className="issue-action issue-action-with-options js-issue-transition"
       onClick={[Function]}
     >
       <StatusHelper
@@ -76,7 +76,7 @@ exports[`should render with a resolution 1`] = `
       <DropdownIcon
         className="little-spacer-left"
       />
-    </Button>
+    </ButtonLink>
   </Toggler>
 </div>
 `;
@@ -102,8 +102,8 @@ exports[`should render with the action 1`] = `
       />
     }
   >
-    <Button
-      className="button-link issue-action issue-action-with-options js-issue-transition"
+    <ButtonLink
+      className="issue-action issue-action-with-options js-issue-transition"
       onClick={[Function]}
     >
       <StatusHelper
@@ -113,7 +113,7 @@ exports[`should render with the action 1`] = `
       <DropdownIcon
         className="little-spacer-left"
       />
-    </Button>
+    </ButtonLink>
   </Toggler>
 </div>
 `;
index 585eae8a6cbb6b193ea42ef3faee02d57aa59211..6af3b059348ccb533e1a4f664827d1e9b00d4f17 100644 (file)
@@ -27,8 +27,8 @@ exports[`should open the popup when the button is clicked 2`] = `
       />
     }
   >
-    <Button
-      className="button-link issue-action issue-action-with-options js-issue-set-type"
+    <ButtonLink
+      className="issue-action issue-action-with-options js-issue-set-type"
       onClick={[Function]}
     >
       <IssueTypeIcon
@@ -39,7 +39,7 @@ exports[`should open the popup when the button is clicked 2`] = `
       <DropdownIcon
         className="little-spacer-left"
       />
-    </Button>
+    </ButtonLink>
   </Toggler>
 </div>
 `;
@@ -62,8 +62,8 @@ exports[`should render with the action 1`] = `
       />
     }
   >
-    <Button
-      className="button-link issue-action issue-action-with-options js-issue-set-type"
+    <ButtonLink
+      className="issue-action issue-action-with-options js-issue-set-type"
       onClick={[Function]}
     >
       <IssueTypeIcon
@@ -74,7 +74,7 @@ exports[`should render with the action 1`] = `
       <DropdownIcon
         className="little-spacer-left"
       />
-    </Button>
+    </ButtonLink>
   </Toggler>
 </div>
 `;
index e8379ade0fee262e933f1555bcf57e1981d28fe5..05df1afe1819f2362d046e6343da5c4753f68817 100644 (file)
 
 /* #region .button-link */
 .button-link {
-  display: inline;
+  display: inline-flex;
   height: auto; /* Keep this to not inherit the height from .button */
   line-height: 1;
   margin: 0;
index f49d2184cf4536058831e9981f0ae2c11bb34267..a0dd58c14554fcbc352c9c55ea08495e47d1af19 100644 (file)
@@ -76,13 +76,17 @@ export class Button extends React.PureComponent<ButtonProps> {
   }
 }
 
+export function ButtonLink({ className, ...props }: ButtonProps) {
+  return <Button {...props} className={classNames('button-link', className)} />;
+}
+
 export function SubmitButton(props: T.Omit<ButtonProps, 'type'>) {
   // do not prevent default to actually submit a form
   return <Button {...props} preventDefault={false} type="submit" />;
 }
 
-export function ResetButtonLink({ className, ...props }: T.Omit<ButtonProps, 'type'>) {
-  return <Button {...props} className={classNames('button-link', className)} type="reset" />;
+export function ResetButtonLink(props: T.Omit<ButtonProps, 'type'>) {
+  return <ButtonLink {...props} type="reset" />;
 }
 
 interface ButtonIconProps {