aboutsummaryrefslogtreecommitdiffstats
path: root/server
diff options
context:
space:
mode:
authorStas Vilchik <stas.vilchik@sonarsource.com>2018-02-21 16:36:42 +0100
committerGitHub <noreply@github.com>2018-02-21 16:36:42 +0100
commite353cd6f2bd37ea143d5806e9ee85323cddd1f97 (patch)
treebaed6993aa339baa41e32e653b457a9f66ee1a24 /server
parenta90637886c930df4d6da31e48e72b90707374730 (diff)
downloadsonarqube-e353cd6f2bd37ea143d5806e9ee85323cddd1f97.tar.gz
sonarqube-e353cd6f2bd37ea143d5806e9ee85323cddd1f97.zip
create and use Button component (#3087)
Diffstat (limited to 'server')
-rw-r--r--server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/LoginPage.java5
-rw-r--r--server/sonar-web/src/main/js/api/quality-profiles.ts8
-rw-r--r--server/sonar-web/src/main/js/app/components/nav/settings/SettingsEditionsNotif.tsx6
-rw-r--r--server/sonar-web/src/main/js/app/components/nav/settings/__tests__/__snapshots__/SettingsEditionsNotif-test.tsx.snap5
-rw-r--r--server/sonar-web/src/main/js/apps/account/organizations/CreateOrganizationForm.tsx47
-rw-r--r--server/sonar-web/src/main/js/apps/account/organizations/UserOrganizations.tsx19
-rw-r--r--server/sonar-web/src/main/js/apps/background-tasks/components/WorkersForm.tsx13
-rw-r--r--server/sonar-web/src/main/js/apps/background-tasks/components/__tests__/__snapshots__/WorkersForm-test.tsx.snap22
-rw-r--r--server/sonar-web/src/main/js/apps/coding-rules/components/ActivationButton.tsx13
-rw-r--r--server/sonar-web/src/main/js/apps/coding-rules/components/ActivationFormModal.tsx36
-rw-r--r--server/sonar-web/src/main/js/apps/coding-rules/components/BulkChange.tsx5
-rw-r--r--server/sonar-web/src/main/js/apps/coding-rules/components/BulkChangeModal.tsx18
-rw-r--r--server/sonar-web/src/main/js/apps/coding-rules/components/CustomRuleButton.tsx8
-rw-r--r--server/sonar-web/src/main/js/apps/coding-rules/components/CustomRuleFormModal.tsx33
-rw-r--r--server/sonar-web/src/main/js/apps/coding-rules/components/RemoveExtendedDescriptionModal.tsx18
-rw-r--r--server/sonar-web/src/main/js/apps/coding-rules/components/RuleDetails.tsx9
-rw-r--r--server/sonar-web/src/main/js/apps/coding-rules/components/RuleDetailsCustomRules.tsx13
-rw-r--r--server/sonar-web/src/main/js/apps/coding-rules/components/RuleDetailsDescription.tsx35
-rw-r--r--server/sonar-web/src/main/js/apps/coding-rules/components/RuleDetailsMeta.tsx11
-rw-r--r--server/sonar-web/src/main/js/apps/coding-rules/components/RuleDetailsProfiles.tsx15
-rw-r--r--server/sonar-web/src/main/js/apps/coding-rules/components/RuleListItem.tsx9
-rw-r--r--server/sonar-web/src/main/js/apps/custom-measures/components/CreateButton.tsx5
-rw-r--r--server/sonar-web/src/main/js/apps/custom-measures/components/Form.tsx16
-rw-r--r--server/sonar-web/src/main/js/apps/custom-measures/components/__tests__/Form-test.tsx2
-rw-r--r--server/sonar-web/src/main/js/apps/custom-measures/components/__tests__/__snapshots__/CreateButton-test.tsx.snap10
-rw-r--r--server/sonar-web/src/main/js/apps/custom-measures/components/__tests__/__snapshots__/Form-test.tsx.snap22
-rw-r--r--server/sonar-web/src/main/js/apps/custom-metrics/components/CreateButton.tsx5
-rw-r--r--server/sonar-web/src/main/js/apps/custom-metrics/components/Form.tsx13
-rw-r--r--server/sonar-web/src/main/js/apps/custom-metrics/components/__tests__/Form-test.tsx2
-rw-r--r--server/sonar-web/src/main/js/apps/custom-metrics/components/__tests__/__snapshots__/CreateButton-test.tsx.snap8
-rw-r--r--server/sonar-web/src/main/js/apps/custom-metrics/components/__tests__/__snapshots__/Form-test.tsx.snap11
-rw-r--r--server/sonar-web/src/main/js/apps/groups/components/EditMembers.tsx12
-rw-r--r--server/sonar-web/src/main/js/apps/groups/components/Form.tsx9
-rw-r--r--server/sonar-web/src/main/js/apps/groups/components/Header.tsx9
-rw-r--r--server/sonar-web/src/main/js/apps/groups/components/__tests__/EditGroup-test.tsx2
-rw-r--r--server/sonar-web/src/main/js/apps/groups/components/__tests__/EditMembers-test.tsx5
-rw-r--r--server/sonar-web/src/main/js/apps/groups/components/__tests__/Form-test.tsx2
-rw-r--r--server/sonar-web/src/main/js/apps/groups/components/__tests__/Header-test.tsx2
-rw-r--r--server/sonar-web/src/main/js/apps/groups/components/__tests__/__snapshots__/EditGroup-test.tsx.snap6
-rw-r--r--server/sonar-web/src/main/js/apps/groups/components/__tests__/__snapshots__/EditMembers-test.tsx.snap6
-rw-r--r--server/sonar-web/src/main/js/apps/groups/components/__tests__/__snapshots__/Form-test.tsx.snap11
-rw-r--r--server/sonar-web/src/main/js/apps/groups/components/__tests__/__snapshots__/Header-test.tsx.snap8
-rw-r--r--server/sonar-web/src/main/js/apps/maintenance/components/App.tsx9
-rw-r--r--server/sonar-web/src/main/js/apps/maintenance/components/__tests__/App-test.tsx2
-rw-r--r--server/sonar-web/src/main/js/apps/maintenance/components/__tests__/__snapshots__/App-test.tsx.snap5
-rw-r--r--server/sonar-web/src/main/js/apps/marketplace/PendingActions.tsx18
-rw-r--r--server/sonar-web/src/main/js/apps/marketplace/__tests__/__snapshots__/PendingActions-test.tsx.snap8
-rw-r--r--server/sonar-web/src/main/js/apps/marketplace/components/EditionBox.tsx9
-rw-r--r--server/sonar-web/src/main/js/apps/marketplace/components/LicenseEditionForm.tsx21
-rw-r--r--server/sonar-web/src/main/js/apps/marketplace/components/PluginActions.tsx19
-rw-r--r--server/sonar-web/src/main/js/apps/marketplace/components/PluginChangeLogButton.tsx19
-rw-r--r--server/sonar-web/src/main/js/apps/marketplace/components/PluginUpdateButton.tsx12
-rw-r--r--server/sonar-web/src/main/js/apps/marketplace/components/UninstallEditionForm.tsx17
-rw-r--r--server/sonar-web/src/main/js/apps/marketplace/components/__tests__/LicenseEditionForm-test.tsx19
-rw-r--r--server/sonar-web/src/main/js/apps/marketplace/components/__tests__/UninstallEditionForm-test.tsx2
-rw-r--r--server/sonar-web/src/main/js/apps/marketplace/components/__tests__/__snapshots__/EditionBox-test.tsx.snap8
-rw-r--r--server/sonar-web/src/main/js/apps/marketplace/components/__tests__/__snapshots__/LicenseEditionForm-test.tsx.snap38
-rw-r--r--server/sonar-web/src/main/js/apps/marketplace/components/__tests__/__snapshots__/UninstallEditionForm-test.tsx.snap11
-rw-r--r--server/sonar-web/src/main/js/apps/overview/badges/BadgeButton.tsx11
-rw-r--r--server/sonar-web/src/main/js/apps/overview/badges/BadgesModal.tsx30
-rw-r--r--server/sonar-web/src/main/js/apps/overview/badges/__tests__/BadgeButton-test.tsx2
-rw-r--r--server/sonar-web/src/main/js/apps/overview/badges/__tests__/BadgesModal-test.tsx2
-rw-r--r--server/sonar-web/src/main/js/apps/overview/badges/__tests__/__snapshots__/BadgeButton-test.tsx.snap12
-rw-r--r--server/sonar-web/src/main/js/apps/overview/badges/__tests__/__snapshots__/BadgesModal-test.tsx.snap10
-rw-r--r--server/sonar-web/src/main/js/apps/overview/meta/MetaTags.tsx13
-rw-r--r--server/sonar-web/src/main/js/apps/overview/meta/__tests__/MetaTags-test.tsx4
-rw-r--r--server/sonar-web/src/main/js/apps/overview/meta/__tests__/__snapshots__/MetaTags-test.tsx.snap24
-rw-r--r--server/sonar-web/src/main/js/apps/permission-templates/components/Form.tsx13
-rw-r--r--server/sonar-web/src/main/js/apps/permission-templates/components/Header.tsx9
-rw-r--r--server/sonar-web/src/main/js/apps/permissions/project/components/ApplyTemplate.tsx9
-rw-r--r--server/sonar-web/src/main/js/apps/permissions/project/components/PageHeader.tsx9
-rw-r--r--server/sonar-web/src/main/js/apps/portfolio/components/Subscription.tsx15
-rw-r--r--server/sonar-web/src/main/js/apps/portfolio/components/__tests__/__snapshots__/Subscription-test.tsx.snap8
-rw-r--r--server/sonar-web/src/main/js/apps/projectBranches/components/DeleteBranchModal.tsx14
-rw-r--r--server/sonar-web/src/main/js/apps/projectBranches/components/RenameBranchModal.tsx16
-rw-r--r--server/sonar-web/src/main/js/apps/projectBranches/components/SettingForm.tsx22
-rw-r--r--server/sonar-web/src/main/js/apps/projectBranches/components/__tests__/DeleteBranchModal-test.tsx2
-rw-r--r--server/sonar-web/src/main/js/apps/projectBranches/components/__tests__/LongBranchesPattern-test.tsx4
-rw-r--r--server/sonar-web/src/main/js/apps/projectBranches/components/__tests__/RenameBranchModal-test.tsx2
-rw-r--r--server/sonar-web/src/main/js/apps/projectBranches/components/__tests__/SettingForm-test.tsx2
-rw-r--r--server/sonar-web/src/main/js/apps/projectBranches/components/__tests__/__snapshots__/DeleteBranchModal-test.tsx.snap24
-rw-r--r--server/sonar-web/src/main/js/apps/projectBranches/components/__tests__/__snapshots__/RenameBranchModal-test.tsx.snap36
-rw-r--r--server/sonar-web/src/main/js/apps/projectBranches/components/__tests__/__snapshots__/SettingForm-test.tsx.snap28
-rw-r--r--server/sonar-web/src/main/js/apps/projects/components/ClearAll.tsx25
-rw-r--r--server/sonar-web/src/main/js/apps/projects/components/__tests__/ClearAll-test.tsx2
-rw-r--r--server/sonar-web/src/main/js/apps/projects/components/__tests__/ProjectsSortingSelect-test.tsx3
-rw-r--r--server/sonar-web/src/main/js/apps/projects/components/__tests__/__snapshots__/ClearAll-test.tsx.snap6
-rw-r--r--server/sonar-web/src/main/js/apps/projectsManagement/BulkApplyTemplateModal.tsx14
-rw-r--r--server/sonar-web/src/main/js/apps/projectsManagement/ChangeVisibilityForm.tsx19
-rw-r--r--server/sonar-web/src/main/js/apps/projectsManagement/CreateProjectForm.tsx27
-rw-r--r--server/sonar-web/src/main/js/apps/projectsManagement/DeleteModal.tsx18
-rw-r--r--server/sonar-web/src/main/js/apps/projectsManagement/Header.tsx11
-rw-r--r--server/sonar-web/src/main/js/apps/projectsManagement/RestoreAccessModal.tsx14
-rw-r--r--server/sonar-web/src/main/js/apps/projectsManagement/Search.tsx27
-rw-r--r--server/sonar-web/src/main/js/apps/projectsManagement/__tests__/BulkApplyTemplateModal-test.tsx4
-rw-r--r--server/sonar-web/src/main/js/apps/projectsManagement/__tests__/DeleteModal-test.tsx4
-rw-r--r--server/sonar-web/src/main/js/apps/projectsManagement/__tests__/__snapshots__/BulkApplyTemplateModal-test.tsx.snap72
-rw-r--r--server/sonar-web/src/main/js/apps/projectsManagement/__tests__/__snapshots__/ChangeVisibilityForm-test.tsx.snap33
-rw-r--r--server/sonar-web/src/main/js/apps/projectsManagement/__tests__/__snapshots__/CreateProjectForm-test.tsx.snap68
-rw-r--r--server/sonar-web/src/main/js/apps/projectsManagement/__tests__/__snapshots__/DeleteModal-test.tsx.snap44
-rw-r--r--server/sonar-web/src/main/js/apps/projectsManagement/__tests__/__snapshots__/Header-test.tsx.snap6
-rw-r--r--server/sonar-web/src/main/js/apps/projectsManagement/__tests__/__snapshots__/Search-test.tsx.snap16
-rw-r--r--server/sonar-web/src/main/js/apps/quality-gates/components/Condition.tsx43
-rw-r--r--server/sonar-web/src/main/js/apps/quality-gates/components/CopyQualityGateForm.tsx18
-rw-r--r--server/sonar-web/src/main/js/apps/quality-gates/components/CreateQualityGateForm.tsx16
-rw-r--r--server/sonar-web/src/main/js/apps/quality-gates/components/DeleteConditionForm.tsx18
-rw-r--r--server/sonar-web/src/main/js/apps/quality-gates/components/DeleteQualityGateForm.tsx18
-rw-r--r--server/sonar-web/src/main/js/apps/quality-gates/components/DetailsHeader.tsx37
-rw-r--r--server/sonar-web/src/main/js/apps/quality-gates/components/ListHeader.tsx16
-rw-r--r--server/sonar-web/src/main/js/apps/quality-gates/components/RenameQualityGateForm.tsx16
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/changelog/ChangelogSearch.tsx11
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/changelog/__tests__/ChangelogSearch-test.tsx10
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/components/CopyProfileForm.tsx16
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/components/DeleteProfileForm.tsx19
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/components/RenameProfileForm.tsx16
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/details/ChangeParentForm.tsx16
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileInheritance.tsx39
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/details/ProfilePermissions.tsx11
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/details/ProfilePermissionsForm.tsx11
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/details/ProfilePermissionsGroup.tsx10
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/details/ProfilePermissionsUser.tsx13
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileProjects.tsx18
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/ProfilePermissions-test.tsx2
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/ProfilePermissionsGroup-test.tsx4
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/ProfilePermissionsUser-test.tsx4
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfilePermissions-test.tsx.snap4
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfilePermissionsForm-test.tsx.snap66
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/home/CreateProfileForm.tsx23
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/home/PageHeader.tsx35
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/home/RestoreProfileForm.tsx18
-rw-r--r--server/sonar-web/src/main/js/apps/sessions/components/LoginForm.tsx29
-rw-r--r--server/sonar-web/src/main/js/apps/sessions/components/__tests__/__snapshots__/LoginForm-test.tsx.snap14
-rw-r--r--server/sonar-web/src/main/js/apps/system/components/ChangeLogLevelForm.tsx26
-rw-r--r--server/sonar-web/src/main/js/apps/system/components/PageActions.tsx44
-rw-r--r--server/sonar-web/src/main/js/apps/system/components/__tests__/__snapshots__/ChangeLogLevelForm-test.tsx.snap18
-rw-r--r--server/sonar-web/src/main/js/apps/system/components/__tests__/__snapshots__/PageActions-test.tsx.snap8
-rw-r--r--server/sonar-web/src/main/js/apps/system/components/system-upgrade/SystemUpgradeNotif.tsx18
-rw-r--r--server/sonar-web/src/main/js/apps/system/components/system-upgrade/__tests__/SystemUpgradeNotif-test.tsx2
-rw-r--r--server/sonar-web/src/main/js/apps/system/components/system-upgrade/__tests__/__snapshots__/SystemUpgradeNotif-test.tsx.snap4
-rw-r--r--server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/__snapshots__/NewOrganizationForm-test.js.snap36
-rw-r--r--server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/__snapshots__/NewProjectForm-test.js.snap36
-rw-r--r--server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/__snapshots__/TokenStep-test.js.snap36
-rw-r--r--server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/__tests__/__snapshots__/Command-test.js.snap15
-rw-r--r--server/sonar-web/src/main/js/apps/users/Header.tsx16
-rw-r--r--server/sonar-web/src/main/js/apps/users/__tests__/__snapshots__/Header-test.tsx.snap4
-rw-r--r--server/sonar-web/src/main/js/apps/users/components/DeactivateForm.tsx18
-rw-r--r--server/sonar-web/src/main/js/apps/users/components/PasswordForm.tsx45
-rw-r--r--server/sonar-web/src/main/js/apps/users/components/TokensForm.tsx18
-rw-r--r--server/sonar-web/src/main/js/apps/users/components/TokensFormItem.tsx15
-rw-r--r--server/sonar-web/src/main/js/apps/users/components/UserForm.tsx57
-rw-r--r--server/sonar-web/src/main/js/components/common/FiltersHeader.tsx38
-rw-r--r--server/sonar-web/src/main/js/components/common/RestartForm.tsx15
-rw-r--r--server/sonar-web/src/main/js/components/controls/ActionsDropdown.tsx5
-rw-r--r--server/sonar-web/src/main/js/components/controls/ClipboardButton.tsx11
-rw-r--r--server/sonar-web/src/main/js/components/controls/ConfirmButton.tsx28
-rw-r--r--server/sonar-web/src/main/js/components/controls/Dropdown.tsx12
-rw-r--r--server/sonar-web/src/main/js/components/controls/SimpleModal.tsx20
-rw-r--r--server/sonar-web/src/main/js/components/controls/__tests__/Dropdown-test.tsx7
-rw-r--r--server/sonar-web/src/main/js/components/controls/__tests__/SimpleModal-test.tsx11
-rw-r--r--server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/ClipboardButton-test.tsx.snap10
-rw-r--r--server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/SimpleModal-test.tsx.snap12
-rw-r--r--server/sonar-web/src/main/js/components/facet/FacetHeader.tsx15
-rw-r--r--server/sonar-web/src/main/js/components/facet/__tests__/__snapshots__/FacetHeader-test.tsx.snap6
-rw-r--r--server/sonar-web/src/main/js/components/ui/buttons.css19
-rw-r--r--server/sonar-web/src/main/js/components/ui/buttons.tsx101
-rw-r--r--server/sonar-web/src/main/js/helpers/testUtils.ts10
166 files changed, 1347 insertions, 1425 deletions
diff --git a/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/LoginPage.java b/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/LoginPage.java
index a11730125aa..3f765429d47 100644
--- a/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/LoginPage.java
+++ b/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/LoginPage.java
@@ -22,7 +22,6 @@ package org.sonarqube.qa.util.pageobjects;
import com.codeborne.selenide.Condition;
import com.codeborne.selenide.Selenide;
import com.codeborne.selenide.SelenideElement;
-import org.openqa.selenium.By;
public class LoginPage {
@@ -49,7 +48,7 @@ public class LoginPage {
public LoginPage submitWrongCredentials(String login, String password) {
Selenide.$("#login").val(login);
Selenide.$("#password").val(password);
- Selenide.$(By.name("commit")).click();
+ Selenide.$("[type=submit]").click();
return Selenide.page(LoginPage.class);
}
@@ -60,7 +59,7 @@ public class LoginPage {
private static <T> T submitCredentials(String login, String password, Class<T> expectedResultPage) {
Selenide.$("#login").val(login);
Selenide.$("#password").val(password);
- Selenide.$(By.name("commit")).click();
+ Selenide.$("[type=submit]").click();
Selenide.$("#login").should(Condition.disappear);
return Selenide.page(expectedResultPage);
}
diff --git a/server/sonar-web/src/main/js/api/quality-profiles.ts b/server/sonar-web/src/main/js/api/quality-profiles.ts
index 736de049edb..e589638ac76 100644
--- a/server/sonar-web/src/main/js/api/quality-profiles.ts
+++ b/server/sonar-web/src/main/js/api/quality-profiles.ts
@@ -112,7 +112,7 @@ export function getProfileProjects(data: RequestData): Promise<any> {
}
export function getProfileInheritance(profileKey: string): Promise<any> {
- return getJSON('/api/qualityprofiles/inheritance', { profileKey });
+ return getJSON('/api/qualityprofiles/inheritance', { profileKey }).catch(throwGlobalError);
}
export function setDefaultProfile(profileKey: string): Promise<void> {
@@ -135,8 +135,10 @@ export function changeProfileParent(profileKey: string, parentKey: string): Prom
return post('/api/qualityprofiles/change_parent', { profileKey, parentKey });
}
-export function getImporters(): Promise<any> {
- return getJSON('/api/qualityprofiles/importers').then(r => r.importers);
+export function getImporters(): Promise<
+ Array<{ key: string; languages: Array<string>; name: string }>
+> {
+ return getJSON('/api/qualityprofiles/importers').then(r => r.importers, throwGlobalError);
}
export function getExporters(): Promise<any> {
diff --git a/server/sonar-web/src/main/js/app/components/nav/settings/SettingsEditionsNotif.tsx b/server/sonar-web/src/main/js/app/components/nav/settings/SettingsEditionsNotif.tsx
index e5a5d8dfef4..3c8850a95ef 100644
--- a/server/sonar-web/src/main/js/app/components/nav/settings/SettingsEditionsNotif.tsx
+++ b/server/sonar-web/src/main/js/app/components/nav/settings/SettingsEditionsNotif.tsx
@@ -21,6 +21,7 @@ import * as React from 'react';
import { FormattedMessage } from 'react-intl';
import NavBarNotif from '../../../../components/nav/NavBarNotif';
import RestartForm from '../../../../components/common/RestartForm';
+import { Button } from '../../../../components/ui/buttons';
import { dismissErrorMessage, Edition, EditionStatus } from '../../../../api/marketplace';
import { translate, translateWithParameters } from '../../../../helpers/l10n';
@@ -86,6 +87,7 @@ export default class SettingsEditionsNotif extends React.PureComponent<Props, St
url: (
<a
href="https://redirect.sonarsource.com/doc/data-center-edition.html"
+ rel="noopener noreferrer"
target="_blank">
{edition.name}
</a>
@@ -95,9 +97,9 @@ export default class SettingsEditionsNotif extends React.PureComponent<Props, St
</span>
)}
{!preventRestart && (
- <button className="js-restart spacer-left" onClick={this.handleOpenRestart} type="button">
+ <Button className="js-restart spacer-left" onClick={this.handleOpenRestart}>
{translate('marketplace.restart')}
- </button>
+ </Button>
)}
{!preventRestart &&
this.state.openRestart && <RestartForm onClose={this.hanleCloseRestart} />}
diff --git a/server/sonar-web/src/main/js/app/components/nav/settings/__tests__/__snapshots__/SettingsEditionsNotif-test.tsx.snap b/server/sonar-web/src/main/js/app/components/nav/settings/__tests__/__snapshots__/SettingsEditionsNotif-test.tsx.snap
index 1b1380978bf..f843a2d29ba 100644
--- a/server/sonar-web/src/main/js/app/components/nav/settings/__tests__/__snapshots__/SettingsEditionsNotif-test.tsx.snap
+++ b/server/sonar-web/src/main/js/app/components/nav/settings/__tests__/__snapshots__/SettingsEditionsNotif-test.tsx.snap
@@ -30,13 +30,12 @@ exports[`should display a ready notification 1`] = `
<span>
marketplace.edition_status.AUTOMATIC_READY
</span>
- <button
+ <Button
className="js-restart spacer-left"
onClick={[Function]}
- type="button"
>
marketplace.restart
- </button>
+ </Button>
</NavBarNotif>
`;
diff --git a/server/sonar-web/src/main/js/apps/account/organizations/CreateOrganizationForm.tsx b/server/sonar-web/src/main/js/apps/account/organizations/CreateOrganizationForm.tsx
index 53117d71a12..04254a29e1a 100644
--- a/server/sonar-web/src/main/js/apps/account/organizations/CreateOrganizationForm.tsx
+++ b/server/sonar-web/src/main/js/apps/account/organizations/CreateOrganizationForm.tsx
@@ -25,6 +25,7 @@ import { createOrganization } from '../../organizations/actions';
import { Organization } from '../../../app/types';
import Modal from '../../../components/controls/Modal';
import { translate } from '../../../helpers/l10n';
+import { SubmitButton, ResetButtonLink } from '../../../components/ui/buttons';
interface DispatchProps {
createOrganization: (fields: Partial<Organization>) => Promise<{ key: string }>;
@@ -136,16 +137,16 @@ class CreateOrganizationForm extends React.PureComponent<Props, State> {
<em className="mandatory">*</em>
</label>
<input
- id="organization-name"
autoFocus={true}
+ disabled={this.state.loading}
+ id="organization-name"
+ maxLength={64}
+ minLength={2}
name="name"
+ onChange={this.handleNameChange}
required={true}
type="text"
- minLength={2}
- maxLength={64}
value={this.state.name}
- disabled={this.state.loading}
- onChange={this.handleNameChange}
/>
<div className="modal-field-description">
{translate('organization.name.description')}
@@ -154,14 +155,14 @@ class CreateOrganizationForm extends React.PureComponent<Props, State> {
<div className="modal-field">
<label htmlFor="organization-key">{translate('organization.key')}</label>
<input
+ disabled={this.state.loading}
id="organization-key"
+ maxLength={64}
+ minLength={2}
name="key"
+ onChange={this.handleKeyChange}
type="text"
- minLength={2}
- maxLength={64}
value={this.state.key}
- disabled={this.state.loading}
- onChange={this.handleKeyChange}
/>
<div className="modal-field-description">
{translate('organization.key.description')}
@@ -170,13 +171,13 @@ class CreateOrganizationForm extends React.PureComponent<Props, State> {
<div className="modal-field">
<label htmlFor="organization-avatar">{translate('organization.avatar')}</label>
<input
+ disabled={this.state.loading}
id="organization-avatar"
+ maxLength={256}
name="avatar"
+ onChange={this.handleAvatarInputChange}
type="text"
- maxLength={256}
value={this.state.avatar}
- disabled={this.state.loading}
- onChange={this.handleAvatarInputChange}
/>
<div className="modal-field-description">
{translate('organization.avatar.description')}
@@ -187,20 +188,20 @@ class CreateOrganizationForm extends React.PureComponent<Props, State> {
{translate('organization.avatar.preview')}
{':'}
</div>
- <img src={this.state.avatarImage} alt="" height={30} />
+ <img alt="" height={30} src={this.state.avatarImage} />
</div>
)}
</div>
<div className="modal-field">
<label htmlFor="organization-description">{translate('description')}</label>
<textarea
+ disabled={this.state.loading}
id="organization-description"
+ maxLength={256}
name="description"
+ onChange={this.handleDescriptionChange}
rows={3}
- maxLength={256}
value={this.state.description}
- disabled={this.state.loading}
- onChange={this.handleDescriptionChange}
/>
<div className="modal-field-description">
{translate('organization.description.description')}
@@ -209,13 +210,13 @@ class CreateOrganizationForm extends React.PureComponent<Props, State> {
<div className="modal-field">
<label htmlFor="organization-url">{translate('organization.url')}</label>
<input
+ disabled={this.state.loading}
id="organization-url"
+ maxLength={256}
name="url"
+ onChange={this.handleUrlChange}
type="text"
- maxLength={256}
value={this.state.url}
- disabled={this.state.loading}
- onChange={this.handleUrlChange}
/>
<div className="modal-field-description">
{translate('organization.url.description')}
@@ -226,12 +227,8 @@ class CreateOrganizationForm extends React.PureComponent<Props, State> {
<footer className="modal-foot">
<div>
{this.state.loading && <i className="spinner spacer-right" />}
- <button disabled={this.state.loading} type="submit">
- {translate('create')}
- </button>
- <button className="button-link" onClick={this.props.onClose} type="reset">
- {translate('cancel')}
- </button>
+ <SubmitButton disabled={this.state.loading}>{translate('create')}</SubmitButton>
+ <ResetButtonLink onClick={this.props.onClose}>{translate('cancel')}</ResetButtonLink>
</div>
</footer>
</form>
diff --git a/server/sonar-web/src/main/js/apps/account/organizations/UserOrganizations.tsx b/server/sonar-web/src/main/js/apps/account/organizations/UserOrganizations.tsx
index 6ec85e94b43..9bf4071c8b0 100644
--- a/server/sonar-web/src/main/js/apps/account/organizations/UserOrganizations.tsx
+++ b/server/sonar-web/src/main/js/apps/account/organizations/UserOrganizations.tsx
@@ -26,6 +26,7 @@ import { fetchIfAnyoneCanCreateOrganizations } from './actions';
import { translate } from '../../../helpers/l10n';
import { getAppState, getMyOrganizations, getGlobalSettingValue } from '../../../store/rootReducer';
import { Organization } from '../../../app/types';
+import { Button } from '../../../components/ui/buttons';
interface StateProps {
anyoneCanCreate?: { value: string };
@@ -63,18 +64,12 @@ class UserOrganizations extends React.PureComponent<Props, State> {
}
};
- openCreateOrganizationForm = () => this.setState({ createOrganization: true });
-
- closeCreateOrganizationForm = () => this.setState({ createOrganization: false });
-
- handleCreateClick = (event: React.SyntheticEvent<HTMLButtonElement>) => {
- event.preventDefault();
- event.currentTarget.blur();
- this.openCreateOrganizationForm();
+ openCreateOrganizationForm = () => {
+ this.setState({ createOrganization: true });
};
- handleCreate = () => {
- this.closeCreateOrganizationForm();
+ closeCreateOrganizationForm = () => {
+ this.setState({ createOrganization: false });
};
render() {
@@ -91,7 +86,7 @@ class UserOrganizations extends React.PureComponent<Props, State> {
{canCreateOrganizations && (
<div className="clearfix">
<div className="boxed-group-actions">
- <button onClick={this.handleCreateClick}>{translate('create')}</button>
+ <Button onClick={this.openCreateOrganizationForm}>{translate('create')}</Button>
</div>
</div>
)}
@@ -107,7 +102,7 @@ class UserOrganizations extends React.PureComponent<Props, State> {
{this.state.createOrganization && (
<CreateOrganizationForm
onClose={this.closeCreateOrganizationForm}
- onCreate={this.handleCreate}
+ onCreate={this.closeCreateOrganizationForm}
/>
)}
</div>
diff --git a/server/sonar-web/src/main/js/apps/background-tasks/components/WorkersForm.tsx b/server/sonar-web/src/main/js/apps/background-tasks/components/WorkersForm.tsx
index 91c5b7d3747..52d5eee1094 100644
--- a/server/sonar-web/src/main/js/apps/background-tasks/components/WorkersForm.tsx
+++ b/server/sonar-web/src/main/js/apps/background-tasks/components/WorkersForm.tsx
@@ -22,6 +22,7 @@ import { times } from 'lodash';
import { setWorkerCount } from '../../../api/ce';
import Modal from '../../../components/controls/Modal';
import Select from '../../../components/controls/Select';
+import { SubmitButton, ResetButtonLink } from '../../../components/ui/buttons';
import { translate } from '../../../helpers/l10n';
const MAX_WORKERS = 10;
@@ -55,7 +56,9 @@ export default class WorkersForm extends React.PureComponent<Props, State> {
this.mounted = false;
}
- handleClose = () => this.props.onClose();
+ handleClose = () => {
+ this.props.onClose();
+ };
handleWorkerCountChange = (option: { value: number }) =>
this.setState({ newWorkerCount: option.value });
@@ -105,12 +108,8 @@ export default class WorkersForm extends React.PureComponent<Props, State> {
<footer className="modal-foot">
<div>
{this.state.submitting && <i className="spinner spacer-right" />}
- <button disabled={this.state.submitting} type="submit">
- {translate('save')}
- </button>
- <button type="reset" className="button-link" onClick={this.handleClose}>
- {translate('cancel')}
- </button>
+ <SubmitButton disabled={this.state.submitting}>{translate('save')}</SubmitButton>
+ <ResetButtonLink onClick={this.handleClose}>{translate('cancel')}</ResetButtonLink>
</div>
</footer>
</form>
diff --git a/server/sonar-web/src/main/js/apps/background-tasks/components/__tests__/__snapshots__/WorkersForm-test.tsx.snap b/server/sonar-web/src/main/js/apps/background-tasks/components/__tests__/__snapshots__/WorkersForm-test.tsx.snap
index 4b9dfd60686..0b1320c6cb2 100644
--- a/server/sonar-web/src/main/js/apps/background-tasks/components/__tests__/__snapshots__/WorkersForm-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/background-tasks/components/__tests__/__snapshots__/WorkersForm-test.tsx.snap
@@ -79,19 +79,16 @@ exports[`changes select 1`] = `
className="modal-foot"
>
<div>
- <button
+ <SubmitButton
disabled={false}
- type="submit"
>
save
- </button>
- <button
- className="button-link"
+ </SubmitButton>
+ <ResetButtonLink
onClick={[Function]}
- type="reset"
>
cancel
- </button>
+ </ResetButtonLink>
</div>
</footer>
</form>
@@ -177,19 +174,16 @@ exports[`changes select 2`] = `
className="modal-foot"
>
<div>
- <button
+ <SubmitButton
disabled={false}
- type="submit"
>
save
- </button>
- <button
- className="button-link"
+ </SubmitButton>
+ <ResetButtonLink
onClick={[Function]}
- type="reset"
>
cancel
- </button>
+ </ResetButtonLink>
</div>
</footer>
</form>
diff --git a/server/sonar-web/src/main/js/apps/coding-rules/components/ActivationButton.tsx b/server/sonar-web/src/main/js/apps/coding-rules/components/ActivationButton.tsx
index 97ae4439f34..043d71b134a 100644
--- a/server/sonar-web/src/main/js/apps/coding-rules/components/ActivationButton.tsx
+++ b/server/sonar-web/src/main/js/apps/coding-rules/components/ActivationButton.tsx
@@ -21,6 +21,7 @@ import * as React from 'react';
import ActivationFormModal from './ActivationFormModal';
import { Profile as BaseProfile } from '../../../api/quality-profiles';
import { Rule, RuleDetails, RuleActivation } from '../../../app/types';
+import { Button } from '../../../components/ui/buttons';
interface Props {
activation?: RuleActivation;
@@ -50,23 +51,23 @@ export default class ActivationButton extends React.PureComponent<Props, State>
this.mounted = false;
}
- handleButtonClick = (event: React.SyntheticEvent<HTMLButtonElement>) => {
- event.preventDefault();
- event.currentTarget.blur();
+ handleButtonClick = () => {
this.setState({ modal: true });
};
- handleCloseModal = () => this.setState({ modal: false });
+ handleCloseModal = () => {
+ this.setState({ modal: false });
+ };
render() {
return (
<>
- <button
+ <Button
className={this.props.className}
id="coding-rules-quality-profile-activate"
onClick={this.handleButtonClick}>
{this.props.buttonText}
- </button>
+ </Button>
{this.state.modal && (
<ActivationFormModal
diff --git a/server/sonar-web/src/main/js/apps/coding-rules/components/ActivationFormModal.tsx b/server/sonar-web/src/main/js/apps/coding-rules/components/ActivationFormModal.tsx
index c410a105cae..97fa22a0402 100644
--- a/server/sonar-web/src/main/js/apps/coding-rules/components/ActivationFormModal.tsx
+++ b/server/sonar-web/src/main/js/apps/coding-rules/components/ActivationFormModal.tsx
@@ -27,6 +27,7 @@ import { Rule, RuleDetails, RuleActivation } from '../../../app/types';
import { SEVERITIES } from '../../../helpers/constants';
import { translate } from '../../../helpers/l10n';
import { sortProfiles } from '../../quality-profiles/utils';
+import { SubmitButton, ResetButtonLink } from '../../../components/ui/buttons';
interface Props {
activation?: RuleActivation;
@@ -84,8 +85,8 @@ export default class ActivationFormModal extends React.PureComponent<Props, Stat
};
// Choose QP which a user can administrate, which are the same language and which are not built-in
- getQualityProfilesWithDepth = ({ profiles } = this.props) =>
- sortProfiles(
+ getQualityProfilesWithDepth = ({ profiles } = this.props) => {
+ return sortProfiles(
profiles.filter(
profile =>
!profile.isBuiltIn &&
@@ -98,11 +99,6 @@ export default class ActivationFormModal extends React.PureComponent<Props, Stat
// Decrease depth by 1, so the top level starts at 0
depth: profile.depth - 1
}));
-
- handleCancelClick = (event: React.SyntheticEvent<HTMLButtonElement>) => {
- event.preventDefault();
- event.currentTarget.blur();
- this.props.onClose();
};
handleFormSubmit = (event: React.SyntheticEvent<HTMLFormElement>) => {
@@ -137,11 +133,17 @@ export default class ActivationFormModal extends React.PureComponent<Props, Stat
this.setState((state: State) => ({ params: { ...state.params, [name]: value } }));
};
- handleProfileChange = ({ value }: { value: string }) => this.setState({ profile: value });
+ handleProfileChange = ({ value }: { value: string }) => {
+ this.setState({ profile: value });
+ };
- handleSeverityChange = ({ value }: { value: string }) => this.setState({ severity: value });
+ handleSeverityChange = ({ value }: { value: string }) => {
+ this.setState({ severity: value });
+ };
- renderSeverityOption = ({ value }: { value: string }) => <SeverityHelper severity={value} />;
+ renderSeverityOption = ({ value }: { value: string }) => {
+ return <SeverityHelper severity={value} />;
+ };
render() {
const { activation, rule } = this.props;
@@ -188,11 +190,11 @@ export default class ActivationFormModal extends React.PureComponent<Props, Stat
clearable={false}
disabled={submitting}
onChange={this.handleSeverityChange}
+ optionRenderer={this.renderSeverityOption}
options={SEVERITIES.map(severity => ({
label: translate('severity', severity),
value: severity
}))}
- optionRenderer={this.renderSeverityOption}
searchable={false}
value={severity}
valueRenderer={this.renderSeverityOption}
@@ -241,16 +243,12 @@ export default class ActivationFormModal extends React.PureComponent<Props, Stat
<footer className="modal-foot">
{submitting && <i className="spinner spacer-right" />}
- <button disabled={submitting || activeInAllProfiles} type="submit">
+ <SubmitButton disabled={submitting || activeInAllProfiles}>
{isUpdateMode ? translate('save') : translate('coding_rules.activate')}
- </button>
- <button
- className="button-link"
- disabled={submitting}
- onClick={this.handleCancelClick}
- type="reset">
+ </SubmitButton>
+ <ResetButtonLink disabled={submitting} onClick={this.props.onClose}>
{translate('cancel')}
- </button>
+ </ResetButtonLink>
</footer>
</form>
</Modal>
diff --git a/server/sonar-web/src/main/js/apps/coding-rules/components/BulkChange.tsx b/server/sonar-web/src/main/js/apps/coding-rules/components/BulkChange.tsx
index 5b4d9e3c665..63d039166cc 100644
--- a/server/sonar-web/src/main/js/apps/coding-rules/components/BulkChange.tsx
+++ b/server/sonar-web/src/main/js/apps/coding-rules/components/BulkChange.tsx
@@ -23,6 +23,7 @@ import BulkChangeModal from './BulkChangeModal';
import { Query } from '../query';
import { Profile } from '../../../api/quality-profiles';
import Dropdown from '../../../components/controls/Dropdown';
+import { Button } from '../../../components/ui/buttons';
import { translate } from '../../../helpers/l10n';
interface Props {
@@ -109,9 +110,9 @@ export default class BulkChange extends React.PureComponent<Props, State> {
this.closeDropdown = closeDropdown;
return (
<div className={classNames('pull-left dropdown', { open })}>
- <button className="js-bulk-change" onClick={onToggleClick}>
+ <Button className="js-bulk-change" onClick={onToggleClick}>
{translate('bulk_change')}
- </button>
+ </Button>
<ul className="dropdown-menu">
<li>
<a href="#" onClick={this.handleActivateClick}>
diff --git a/server/sonar-web/src/main/js/apps/coding-rules/components/BulkChangeModal.tsx b/server/sonar-web/src/main/js/apps/coding-rules/components/BulkChangeModal.tsx
index f7981285692..948d3743693 100644
--- a/server/sonar-web/src/main/js/apps/coding-rules/components/BulkChangeModal.tsx
+++ b/server/sonar-web/src/main/js/apps/coding-rules/components/BulkChangeModal.tsx
@@ -25,6 +25,7 @@ import Modal from '../../../components/controls/Modal';
import Select from '../../../components/controls/Select';
import { translate, translateWithParameters } from '../../../helpers/l10n';
import { formatMeasure } from '../../../helpers/measures';
+import { SubmitButton, ResetButtonLink } from '../../../components/ui/buttons';
interface Props {
action: string;
@@ -73,12 +74,6 @@ export default class BulkChangeModal extends React.PureComponent<Props, State> {
this.mounted = false;
}
- handleCloseClick = (event: React.SyntheticEvent<HTMLButtonElement>) => {
- event.preventDefault();
- event.currentTarget.blur();
- this.props.onClose();
- };
-
handleProfileSelect = (options: { value: string }[]) => {
const selectedProfiles = options.map(option => option.value);
this.setState({ selectedProfiles });
@@ -238,16 +233,13 @@ export default class BulkChangeModal extends React.PureComponent<Props, State> {
<footer className="modal-foot">
{this.state.submitting && <i className="spinner spacer-right" />}
{!this.state.finished && (
- <button
- disabled={this.state.submitting}
- id="coding-rules-submit-bulk-change"
- type="submit">
+ <SubmitButton disabled={this.state.submitting} id="coding-rules-submit-bulk-change">
{translate('apply')}
- </button>
+ </SubmitButton>
)}
- <button className="button-link" onClick={this.handleCloseClick} type="reset">
+ <ResetButtonLink onClick={this.props.onClose}>
{this.state.finished ? translate('close') : translate('cancel')}
- </button>
+ </ResetButtonLink>
</footer>
</form>
</Modal>
diff --git a/server/sonar-web/src/main/js/apps/coding-rules/components/CustomRuleButton.tsx b/server/sonar-web/src/main/js/apps/coding-rules/components/CustomRuleButton.tsx
index 5882d70b307..6c8e466d200 100644
--- a/server/sonar-web/src/main/js/apps/coding-rules/components/CustomRuleButton.tsx
+++ b/server/sonar-web/src/main/js/apps/coding-rules/components/CustomRuleButton.tsx
@@ -22,9 +22,7 @@ import CustomRuleFormModal from './CustomRuleFormModal';
import { RuleDetails } from '../../../app/types';
interface Props {
- children: (
- props: { onClick: (event: React.SyntheticEvent<HTMLButtonElement>) => void }
- ) => React.ReactNode;
+ children: (props: { onClick: () => void }) => React.ReactNode;
customRule?: RuleDetails;
onDone: (newRuleDetails: RuleDetails) => void;
organization: string | undefined;
@@ -47,9 +45,7 @@ export default class CustomRuleButton extends React.PureComponent<Props, State>
this.mounted = false;
}
- handleClick = (event: React.SyntheticEvent<HTMLButtonElement>) => {
- event.preventDefault();
- event.currentTarget.blur();
+ handleClick = () => {
this.setState({ modal: true });
};
diff --git a/server/sonar-web/src/main/js/apps/coding-rules/components/CustomRuleFormModal.tsx b/server/sonar-web/src/main/js/apps/coding-rules/components/CustomRuleFormModal.tsx
index 426c180a43a..e3076a11b3f 100644
--- a/server/sonar-web/src/main/js/apps/coding-rules/components/CustomRuleFormModal.tsx
+++ b/server/sonar-web/src/main/js/apps/coding-rules/components/CustomRuleFormModal.tsx
@@ -29,6 +29,7 @@ import TypeHelper from '../../../components/shared/TypeHelper';
import SeverityHelper from '../../../components/shared/SeverityHelper';
import { createRule, updateRule } from '../../../api/rules';
import { csvEscape } from '../../../helpers/csv';
+import { SubmitButton, ResetButtonLink } from '../../../components/ui/buttons';
interface Props {
customRule?: RuleDetails;
@@ -84,12 +85,6 @@ export default class CustomRuleFormModal extends React.PureComponent<Props, Stat
this.mounted = false;
}
- handleCancelClick = (event: React.SyntheticEvent<HTMLButtonElement>) => {
- event.preventDefault();
- event.currentTarget.blur();
- this.props.onClose();
- };
-
prepareRequest = () => {
/* eslint-disable camelcase */
const { customRule, organization, templateRule } = this.props;
@@ -248,11 +243,11 @@ export default class CustomRuleFormModal extends React.PureComponent<Props, Stat
clearable={false}
disabled={this.state.submitting}
onChange={this.handleTypeChange}
+ optionRenderer={this.renderTypeOption}
options={TYPES.map(type => ({
label: translate('issue.type', type),
value: type
}))}
- optionRenderer={this.renderTypeOption}
searchable={false}
value={this.state.type}
valueRenderer={this.renderTypeOption}
@@ -274,11 +269,11 @@ export default class CustomRuleFormModal extends React.PureComponent<Props, Stat
clearable={false}
disabled={this.state.submitting}
onChange={this.handleSeverityChange}
+ optionRenderer={this.renderSeverityOption}
options={SEVERITIES.map(severity => ({
label: translate('severity', severity),
value: severity
}))}
- optionRenderer={this.renderSeverityOption}
searchable={false}
value={this.state.severity}
valueRenderer={this.renderSeverityOption}
@@ -345,21 +340,19 @@ export default class CustomRuleFormModal extends React.PureComponent<Props, Stat
renderSubmitButton = () => {
if (this.state.reactivating) {
return (
- <button
+ <SubmitButton
disabled={this.state.submitting}
- id="coding-rules-custom-rule-creation-reactivate"
- type="submit">
+ id="coding-rules-custom-rule-creation-reactivate">
{translate('coding_rules.reactivate')}
- </button>
+ </SubmitButton>
);
} else {
return (
- <button
+ <SubmitButton
disabled={this.state.submitting}
- id="coding-rules-custom-rule-creation-create"
- type="submit">
+ id="coding-rules-custom-rule-creation-create">
{translate(this.props.customRule ? 'save' : 'create')}
- </button>
+ </SubmitButton>
);
}
};
@@ -399,14 +392,12 @@ export default class CustomRuleFormModal extends React.PureComponent<Props, Stat
<div className="modal-foot">
{submitting && <i className="spinner spacer-right" />}
{this.renderSubmitButton()}
- <button
- className="button-link"
+ <ResetButtonLink
disabled={submitting}
id="coding-rules-custom-rule-creation-cancel"
- onClick={this.handleCancelClick}
- type="reset">
+ onClick={this.props.onClose}>
{translate('cancel')}
- </button>
+ </ResetButtonLink>
</div>
</form>
</Modal>
diff --git a/server/sonar-web/src/main/js/apps/coding-rules/components/RemoveExtendedDescriptionModal.tsx b/server/sonar-web/src/main/js/apps/coding-rules/components/RemoveExtendedDescriptionModal.tsx
index 95a7ee29f44..d3a15539858 100644
--- a/server/sonar-web/src/main/js/apps/coding-rules/components/RemoveExtendedDescriptionModal.tsx
+++ b/server/sonar-web/src/main/js/apps/coding-rules/components/RemoveExtendedDescriptionModal.tsx
@@ -19,6 +19,7 @@
*/
import * as React from 'react';
import SimpleModal from '../../../components/controls/SimpleModal';
+import { SubmitButton, ResetButtonLink } from '../../../components/ui/buttons';
import { translate } from '../../../helpers/l10n';
interface Props {
@@ -30,8 +31,8 @@ export default function RemoveExtendedDescriptionModal({ onCancel, onSubmit }: P
const header = translate('coding_rules.remove_extended_description');
return (
<SimpleModal header={header} onClose={onCancel} onSubmit={onSubmit}>
- {({ onCloseClick, onSubmitClick, submitting }) => (
- <>
+ {({ onCloseClick, onFormSubmit, submitting }) => (
+ <form onSubmit={onFormSubmit}>
<header className="modal-head">
<h2>{header}</h2>
</header>
@@ -42,18 +43,15 @@ export default function RemoveExtendedDescriptionModal({ onCancel, onSubmit }: P
<footer className="modal-foot">
{submitting && <i className="spinner spacer-right" />}
- <button
+ <SubmitButton
className="button-red"
disabled={submitting}
- id="coding-rules-detail-extend-description-remove-submit"
- onClick={onSubmitClick}>
+ id="coding-rules-detail-extend-description-remove-submit">
{translate('remove')}
- </button>
- <a href="#" onClick={onCloseClick}>
- {translate('cancel')}
- </a>
+ </SubmitButton>
+ <ResetButtonLink onClick={onCloseClick}>{translate('cancel')}</ResetButtonLink>
</footer>
- </>
+ </form>
)}
</SimpleModal>
);
diff --git a/server/sonar-web/src/main/js/apps/coding-rules/components/RuleDetails.tsx b/server/sonar-web/src/main/js/apps/coding-rules/components/RuleDetails.tsx
index 331e1c908e2..e951e3b9d44 100644
--- a/server/sonar-web/src/main/js/apps/coding-rules/components/RuleDetails.tsx
+++ b/server/sonar-web/src/main/js/apps/coding-rules/components/RuleDetails.tsx
@@ -31,6 +31,7 @@ import { getRuleDetails, deleteRule, updateRule } from '../../../api/rules';
import { RuleActivation, RuleDetails as IRuleDetails } from '../../../app/types';
import DeferredSpinner from '../../../components/common/DeferredSpinner';
import ConfirmButton from '../../../components/controls/ConfirmButton';
+import { Button } from '../../../components/ui/buttons';
import { translate, translateWithParameters } from '../../../helpers/l10n';
interface Props {
@@ -183,12 +184,12 @@ export default class RuleDetails extends React.PureComponent<Props, State> {
organization={organization}
templateRule={ruleDetails}>
{({ onClick }) => (
- <button
+ <Button
className="js-edit-custom"
id="coding-rules-detail-custom-rule-change"
onClick={onClick}>
{translate('edit')}
- </button>
+ </Button>
)}
</CustomRuleButton>
<ConfirmButton
@@ -201,12 +202,12 @@ export default class RuleDetails extends React.PureComponent<Props, State> {
modalHeader={translate('coding_rules.delete_rule')}
onConfirm={this.handleDelete}>
{({ onClick }) => (
- <button
+ <Button
className="button-red spacer-left js-delete"
id="coding-rules-detail-rule-delete"
onClick={onClick}>
{translate('delete')}
- </button>
+ </Button>
)}
</ConfirmButton>
</div>
diff --git a/server/sonar-web/src/main/js/apps/coding-rules/components/RuleDetailsCustomRules.tsx b/server/sonar-web/src/main/js/apps/coding-rules/components/RuleDetailsCustomRules.tsx
index d080327593f..ac0e20cafed 100644
--- a/server/sonar-web/src/main/js/apps/coding-rules/components/RuleDetailsCustomRules.tsx
+++ b/server/sonar-web/src/main/js/apps/coding-rules/components/RuleDetailsCustomRules.tsx
@@ -26,6 +26,7 @@ import { Rule, RuleDetails } from '../../../app/types';
import DeferredSpinner from '../../../components/common/DeferredSpinner';
import ConfirmButton from '../../../components/controls/ConfirmButton';
import SeverityHelper from '../../../components/shared/SeverityHelper';
+import { Button } from '../../../components/ui/buttons';
import { translate, translateWithParameters } from '../../../helpers/l10n';
import { getRuleUrl } from '../../../helpers/urls';
@@ -100,7 +101,7 @@ export default class RuleDetailsCustomRules extends React.PureComponent<Props, S
};
renderRule = (rule: Rule) => (
- <tr key={rule.key} data-rule={rule.key}>
+ <tr data-rule={rule.key} key={rule.key}>
<td className="coding-rules-detail-list-name">
<Link to={getRuleUrl(rule.key, this.props.organization)}>{rule.name}</Link>
</td>
@@ -132,9 +133,9 @@ export default class RuleDetailsCustomRules extends React.PureComponent<Props, S
modalHeader={translate('coding_rules.delete_rule')}
onConfirm={this.handleRuleDelete}>
{({ onClick }) => (
- <button className="button-red js-delete-custom-rule" onClick={onClick}>
+ <Button className="button-red js-delete-custom-rule" onClick={onClick}>
{translate('delete')}
- </button>
+ </Button>
)}
</ConfirmButton>
</td>
@@ -158,16 +159,16 @@ export default class RuleDetailsCustomRules extends React.PureComponent<Props, S
organization={this.props.organization}
templateRule={this.props.ruleDetails}>
{({ onClick }) => (
- <button className="js-create-custom-rule spacer-left" onClick={onClick}>
+ <Button className="js-create-custom-rule spacer-left" onClick={onClick}>
{translate('coding_rules.create')}
- </button>
+ </Button>
)}
</CustomRuleButton>
)}
<DeferredSpinner loading={loading}>
{rules.length > 0 && (
- <table id="coding-rules-detail-custom-rules" className="coding-rules-detail-list">
+ <table className="coding-rules-detail-list" id="coding-rules-detail-custom-rules">
<tbody>{sortBy(rules, rule => rule.name).map(this.renderRule)}</tbody>
</table>
)}
diff --git a/server/sonar-web/src/main/js/apps/coding-rules/components/RuleDetailsDescription.tsx b/server/sonar-web/src/main/js/apps/coding-rules/components/RuleDetailsDescription.tsx
index b21425fa10a..c353a8c5c77 100644
--- a/server/sonar-web/src/main/js/apps/coding-rules/components/RuleDetailsDescription.tsx
+++ b/server/sonar-web/src/main/js/apps/coding-rules/components/RuleDetailsDescription.tsx
@@ -22,6 +22,7 @@ import RemoveExtendedDescriptionModal from './RemoveExtendedDescriptionModal';
import { updateRule } from '../../../api/rules';
import { RuleDetails } from '../../../app/types';
import MarkdownTips from '../../../components/common/MarkdownTips';
+import { Button, ResetButtonLink } from '../../../components/ui/buttons';
import { translate } from '../../../helpers/l10n';
interface Props {
@@ -58,21 +59,15 @@ export default class RuleDetailsDescription extends React.PureComponent<Props, S
handleDescriptionChange = (event: React.SyntheticEvent<HTMLTextAreaElement>) =>
this.setState({ description: event.currentTarget.value });
- handleCancelClick = (event: React.SyntheticEvent<HTMLButtonElement>) => {
- event.preventDefault();
- event.currentTarget.blur();
+ handleCancelClick = () => {
this.setState({ descriptionForm: false });
};
- handleSaveClick = (event: React.SyntheticEvent<HTMLButtonElement>) => {
- event.preventDefault();
- event.currentTarget.blur();
+ handleSaveClick = () => {
this.updateDescription(this.state.description);
};
- handleRemoveDescriptionClick = (event: React.SyntheticEvent<HTMLButtonElement>) => {
- event.preventDefault();
- event.currentTarget.blur();
+ handleRemoveDescriptionClick = () => {
this.setState({ removeDescriptionModal: true });
};
@@ -107,9 +102,7 @@ export default class RuleDetailsDescription extends React.PureComponent<Props, S
);
};
- handleExtendDescriptionClick = (event: React.SyntheticEvent<HTMLButtonElement>) => {
- event.preventDefault();
- event.currentTarget.blur();
+ handleExtendDescriptionClick = () => {
this.setState({
// set description` to the current `mdNote` each time the form is open
description: this.props.ruleDetails.mdNote || '',
@@ -126,11 +119,11 @@ export default class RuleDetailsDescription extends React.PureComponent<Props, S
/>
)}
{this.props.canWrite && (
- <button
+ <Button
id="coding-rules-detail-extend-description"
onClick={this.handleExtendDescriptionClick}>
{translate('coding_rules.extend_description')}
- </button>
+ </Button>
)}
</div>
);
@@ -153,21 +146,21 @@ export default class RuleDetailsDescription extends React.PureComponent<Props, S
</tr>
<tr>
<td>
- <button
+ <Button
disabled={this.state.submitting}
id="coding-rules-detail-extend-description-submit"
onClick={this.handleSaveClick}>
{translate('save')}
- </button>
+ </Button>
{this.props.ruleDetails.mdNote !== undefined && (
<>
- <button
+ <Button
className="button-red spacer-left"
disabled={this.state.submitting}
id="coding-rules-detail-extend-description-remove"
onClick={this.handleRemoveDescriptionClick}>
{translate('remove')}
- </button>
+ </Button>
{this.state.removeDescriptionModal && (
<RemoveExtendedDescriptionModal
onCancel={this.handleCancelRemoving}
@@ -176,13 +169,13 @@ export default class RuleDetailsDescription extends React.PureComponent<Props, S
)}
</>
)}
- <button
- className="spacer-left button-link"
+ <ResetButtonLink
+ className="spacer-left"
disabled={this.state.submitting}
id="coding-rules-detail-extend-description-cancel"
onClick={this.handleCancelClick}>
{translate('cancel')}
- </button>
+ </ResetButtonLink>
{this.state.submitting && <i className="spinner spacer-left" />}
</td>
<td className="text-right">
diff --git a/server/sonar-web/src/main/js/apps/coding-rules/components/RuleDetailsMeta.tsx b/server/sonar-web/src/main/js/apps/coding-rules/components/RuleDetailsMeta.tsx
index 310af7e4bee..fa43eebc44a 100644
--- a/server/sonar-web/src/main/js/apps/coding-rules/components/RuleDetailsMeta.tsx
+++ b/server/sonar-web/src/main/js/apps/coding-rules/components/RuleDetailsMeta.tsx
@@ -33,6 +33,7 @@ import SeverityHelper from '../../../components/shared/SeverityHelper';
import BubblePopupHelper from '../../../components/common/BubblePopupHelper';
import TagsList from '../../../components/tags/TagsList';
import DateFormatter from '../../../components/intl/DateFormatter';
+import { Button } from '../../../components/ui/buttons';
interface Props {
canWrite: boolean | undefined;
@@ -50,9 +51,7 @@ interface State {
export default class RuleDetailsMeta extends React.PureComponent<Props, State> {
state: State = { tagsPopup: false };
- handleTagsClick = (event: React.SyntheticEvent<HTMLButtonElement>) => {
- event.preventDefault();
- event.currentTarget.blur();
+ handleTagsClick = () => {
this.setState(state => ({ tagsPopup: !state.tagsPopup }));
};
@@ -106,7 +105,6 @@ export default class RuleDetailsMeta extends React.PureComponent<Props, State> {
{this.props.canWrite ? (
<BubblePopupHelper
isOpen={this.state.tagsPopup}
- position="bottomleft"
popup={
<RuleDetailsTagsPopup
organization={this.props.organization}
@@ -115,13 +113,14 @@ export default class RuleDetailsMeta extends React.PureComponent<Props, State> {
tags={tags}
/>
}
+ position="bottomleft"
togglePopup={this.handleTagsPopupToggle}>
- <button className="button-link" onClick={this.handleTagsClick}>
+ <Button className="button-link" onClick={this.handleTagsClick}>
<TagsList
allowUpdate={canWrite}
tags={allTags.length > 0 ? allTags : [translate('coding_rules.no_tags')]}
/>
- </button>
+ </Button>
</BubblePopupHelper>
) : (
<TagsList
diff --git a/server/sonar-web/src/main/js/apps/coding-rules/components/RuleDetailsProfiles.tsx b/server/sonar-web/src/main/js/apps/coding-rules/components/RuleDetailsProfiles.tsx
index 551b6d1402a..bb80abd464f 100644
--- a/server/sonar-web/src/main/js/apps/coding-rules/components/RuleDetailsProfiles.tsx
+++ b/server/sonar-web/src/main/js/apps/coding-rules/components/RuleDetailsProfiles.tsx
@@ -30,6 +30,7 @@ import { getQualityProfileUrl } from '../../../helpers/urls';
import BuiltInQualityProfileBadge from '../../quality-profiles/components/BuiltInQualityProfileBadge';
import Tooltip from '../../../components/controls/Tooltip';
import SeverityHelper from '../../../components/shared/SeverityHelper';
+import { Button } from '../../../components/ui/buttons';
interface Props {
activations: RuleActivation[] | undefined;
@@ -193,11 +194,11 @@ export default class RuleDetailsProfiles extends React.PureComponent<Props, Stat
modalHeader={translate('coding_rules.revert_to_parent_definition')}
onConfirm={this.handleRevert}>
{({ onClick }) => (
- <button
+ <Button
className="coding-rules-detail-quality-profile-revert button-red spacer-left"
onClick={onClick}>
{translate('coding_rules.revert_to_parent_definition')}
- </button>
+ </Button>
)}
</ConfirmButton>
)
@@ -209,11 +210,11 @@ export default class RuleDetailsProfiles extends React.PureComponent<Props, Stat
modalHeader={translate('coding_rules.deactivate')}
onConfirm={this.handleDeactivate}>
{({ onClick }) => (
- <button
+ <Button
className="coding-rules-detail-quality-profile-deactivate button-red spacer-left"
onClick={onClick}>
{translate('coding_rules.deactivate')}
- </button>
+ </Button>
)}
</ConfirmButton>
)}
@@ -233,7 +234,7 @@ export default class RuleDetailsProfiles extends React.PureComponent<Props, Stat
const parentActivation = activations.find(x => x.qProfile === profile.parentKey);
return (
- <tr key={profile.key} data-profile={profile.key}>
+ <tr data-profile={profile.key} key={profile.key}>
<td className="coding-rules-detail-quality-profile-name">
<Link to={getQualityProfileUrl(profile.name, profile.language, this.props.organization)}>
{profile.name}
@@ -281,8 +282,8 @@ export default class RuleDetailsProfiles extends React.PureComponent<Props, Stat
{activations.length > 0 && (
<table
- id="coding-rules-detail-quality-profiles"
- className="coding-rules-detail-quality-profiles width100">
+ className="coding-rules-detail-quality-profiles width100"
+ id="coding-rules-detail-quality-profiles">
<tbody>{activations.map(this.renderActivation)}</tbody>
</table>
)}
diff --git a/server/sonar-web/src/main/js/apps/coding-rules/components/RuleListItem.tsx b/server/sonar-web/src/main/js/apps/coding-rules/components/RuleListItem.tsx
index 3f9852c418d..3b70690ca5f 100644
--- a/server/sonar-web/src/main/js/apps/coding-rules/components/RuleListItem.tsx
+++ b/server/sonar-web/src/main/js/apps/coding-rules/components/RuleListItem.tsx
@@ -28,6 +28,7 @@ import { Rule, RuleInheritance } from '../../../app/types';
import ConfirmButton from '../../../components/controls/ConfirmButton';
import Tooltip from '../../../components/controls/Tooltip';
import SeverityIcon from '../../../components/shared/SeverityIcon';
+import { Button } from '../../../components/ui/buttons';
import IssueTypeIcon from '../../../components/ui/IssueTypeIcon';
import { translate, translateWithParameters } from '../../../helpers/l10n';
@@ -141,18 +142,18 @@ export default class RuleListItem extends React.PureComponent<Props> {
modalHeader={translate('coding_rules.deactivate')}
onConfirm={this.handleDeactivate}>
{({ onClick }) => (
- <button
+ <Button
className="coding-rules-detail-quality-profile-deactivate button-red"
onClick={onClick}>
{translate('coding_rules.deactivate')}
- </button>
+ </Button>
)}
</ConfirmButton>
) : (
<Tooltip overlay={translate('coding_rules.can_not_deactivate')} placement="left">
- <button className="coding-rules-detail-quality-profile-deactivate button-red disabled">
+ <Button className="coding-rules-detail-quality-profile-deactivate button-red disabled">
{translate('coding_rules.deactivate')}
- </button>
+ </Button>
</Tooltip>
);
};
diff --git a/server/sonar-web/src/main/js/apps/custom-measures/components/CreateButton.tsx b/server/sonar-web/src/main/js/apps/custom-measures/components/CreateButton.tsx
index feea67a5ab4..c8a7dd6049c 100644
--- a/server/sonar-web/src/main/js/apps/custom-measures/components/CreateButton.tsx
+++ b/server/sonar-web/src/main/js/apps/custom-measures/components/CreateButton.tsx
@@ -19,6 +19,7 @@
*/
import * as React from 'react';
import Form from './Form';
+import { Button } from '../../../components/ui/buttons';
import { translate } from '../../../helpers/l10n';
interface Props {
@@ -55,9 +56,9 @@ export default class CreateButton extends React.PureComponent<Props, State> {
render() {
return (
<>
- <button id="custom-measures-create" onClick={this.handleClick} type="button">
+ <Button id="custom-measures-create" onClick={this.handleClick}>
{translate('create')}
- </button>
+ </Button>
{this.state.modal && (
<Form
confirmButtonText={translate('create')}
diff --git a/server/sonar-web/src/main/js/apps/custom-measures/components/Form.tsx b/server/sonar-web/src/main/js/apps/custom-measures/components/Form.tsx
index 6b814dd735a..3f584725f8a 100644
--- a/server/sonar-web/src/main/js/apps/custom-measures/components/Form.tsx
+++ b/server/sonar-web/src/main/js/apps/custom-measures/components/Form.tsx
@@ -23,6 +23,7 @@ import { CustomMeasure, Metric } from '../../../app/types';
import DeferredSpinner from '../../../components/common/DeferredSpinner';
import Select from '../../../components/controls/Select';
import SimpleModal from '../../../components/controls/SimpleModal';
+import { SubmitButton, ResetButtonLink } from '../../../components/ui/buttons';
import { translate } from '../../../helpers/l10n';
interface Props {
@@ -186,20 +187,17 @@ export default class Form extends React.PureComponent<Props, State> {
<footer className="modal-foot">
<DeferredSpinner className="spacer-right" loading={submitting} />
- <button
+ <SubmitButton
disabled={forbidSubmitting || submitting}
- id="create-custom-measure-submit"
- type="submit">
+ id="create-custom-measure-submit">
{this.props.confirmButtonText}
- </button>
- <button
- className="button-link"
+ </SubmitButton>
+ <ResetButtonLink
disabled={submitting}
id="create-custom-measure-cancel"
- onClick={onCloseClick}
- type="reset">
+ onClick={onCloseClick}>
{translate('cancel')}
- </button>
+ </ResetButtonLink>
</footer>
</form>
)}
diff --git a/server/sonar-web/src/main/js/apps/custom-measures/components/__tests__/Form-test.tsx b/server/sonar-web/src/main/js/apps/custom-measures/components/__tests__/Form-test.tsx
index e6252db478f..1cfc6991abd 100644
--- a/server/sonar-web/src/main/js/apps/custom-measures/components/__tests__/Form-test.tsx
+++ b/server/sonar-web/src/main/js/apps/custom-measures/components/__tests__/Form-test.tsx
@@ -62,6 +62,6 @@ it('should render form', async () => {
expect(onClose).toBeCalled();
onClose.mockClear();
- click(form.find('button[type="reset"]'));
+ click(form.find('ResetButtonLink'));
expect(onClose).toBeCalled();
});
diff --git a/server/sonar-web/src/main/js/apps/custom-measures/components/__tests__/__snapshots__/CreateButton-test.tsx.snap b/server/sonar-web/src/main/js/apps/custom-measures/components/__tests__/__snapshots__/CreateButton-test.tsx.snap
index 78c55c67890..8973f165fae 100644
--- a/server/sonar-web/src/main/js/apps/custom-measures/components/__tests__/__snapshots__/CreateButton-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/custom-measures/components/__tests__/__snapshots__/CreateButton-test.tsx.snap
@@ -2,25 +2,23 @@
exports[`should create new custom measure 1`] = `
<React.Fragment>
- <button
+ <Button
id="custom-measures-create"
onClick={[Function]}
- type="button"
>
create
- </button>
+ </Button>
</React.Fragment>
`;
exports[`should create new custom measure 2`] = `
<React.Fragment>
- <button
+ <Button
id="custom-measures-create"
onClick={[Function]}
- type="button"
>
create
- </button>
+ </Button>
<Form
confirmButtonText="create"
header="custom_measures.create_custom_measure"
diff --git a/server/sonar-web/src/main/js/apps/custom-measures/components/__tests__/__snapshots__/Form-test.tsx.snap b/server/sonar-web/src/main/js/apps/custom-measures/components/__tests__/__snapshots__/Form-test.tsx.snap
index 17057ba3704..858183d2219 100644
--- a/server/sonar-web/src/main/js/apps/custom-measures/components/__tests__/__snapshots__/Form-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/custom-measures/components/__tests__/__snapshots__/Form-test.tsx.snap
@@ -83,22 +83,19 @@ exports[`should render form 1`] = `
loading={false}
timeout={100}
/>
- <button
+ <SubmitButton
disabled={true}
id="create-custom-measure-submit"
- type="submit"
>
confirmButtonText
- </button>
- <button
- className="button-link"
+ </SubmitButton>
+ <ResetButtonLink
disabled={false}
id="create-custom-measure-cancel"
onClick={[Function]}
- type="reset"
>
cancel
- </button>
+ </ResetButtonLink>
</footer>
</form>
</Modal>
@@ -197,22 +194,19 @@ exports[`should render form 2`] = `
loading={false}
timeout={100}
/>
- <button
+ <SubmitButton
disabled={false}
id="create-custom-measure-submit"
- type="submit"
>
confirmButtonText
- </button>
- <button
- className="button-link"
+ </SubmitButton>
+ <ResetButtonLink
disabled={false}
id="create-custom-measure-cancel"
onClick={[Function]}
- type="reset"
>
cancel
- </button>
+ </ResetButtonLink>
</footer>
</form>
</Modal>
diff --git a/server/sonar-web/src/main/js/apps/custom-metrics/components/CreateButton.tsx b/server/sonar-web/src/main/js/apps/custom-metrics/components/CreateButton.tsx
index e3b67e82d84..582f306f40f 100644
--- a/server/sonar-web/src/main/js/apps/custom-metrics/components/CreateButton.tsx
+++ b/server/sonar-web/src/main/js/apps/custom-metrics/components/CreateButton.tsx
@@ -19,6 +19,7 @@
*/
import * as React from 'react';
import Form, { MetricProps } from './Form';
+import { Button } from '../../../components/ui/buttons';
import { translate } from '../../../helpers/l10n';
interface Props {
@@ -56,9 +57,9 @@ export default class CreateButton extends React.PureComponent<Props, State> {
render() {
return (
<>
- <button id="metrics-create" onClick={this.handleClick}>
+ <Button id="metrics-create" onClick={this.handleClick}>
{translate('custom_metrics.create_metric')}
- </button>
+ </Button>
{this.state.modal && (
<Form
confirmButtonText={translate('create')}
diff --git a/server/sonar-web/src/main/js/apps/custom-metrics/components/Form.tsx b/server/sonar-web/src/main/js/apps/custom-metrics/components/Form.tsx
index 0922d9a9b40..89c4fc9ba20 100644
--- a/server/sonar-web/src/main/js/apps/custom-metrics/components/Form.tsx
+++ b/server/sonar-web/src/main/js/apps/custom-metrics/components/Form.tsx
@@ -23,6 +23,7 @@ import DeferredSpinner from '../../../components/common/DeferredSpinner';
import SimpleModal from '../../../components/controls/SimpleModal';
import { translate } from '../../../helpers/l10n';
import Select, { Creatable } from '../../../components/controls/Select';
+import { SubmitButton, ResetButtonLink } from '../../../components/ui/buttons';
export interface MetricProps {
description: string;
@@ -168,17 +169,15 @@ export default class Form extends React.PureComponent<Props, State> {
<footer className="modal-foot">
<DeferredSpinner className="spacer-right" loading={submitting} />
- <button disabled={submitting} id="create-metric-submit" type="submit">
+ <SubmitButton disabled={submitting} id="create-metric-submit">
{this.props.confirmButtonText}
- </button>
- <button
- className="button-link"
+ </SubmitButton>
+ <ResetButtonLink
disabled={submitting}
id="create-metric-cancel"
- onClick={onCloseClick}
- type="reset">
+ onClick={onCloseClick}>
{translate('cancel')}
- </button>
+ </ResetButtonLink>
</footer>
</form>
)}
diff --git a/server/sonar-web/src/main/js/apps/custom-metrics/components/__tests__/Form-test.tsx b/server/sonar-web/src/main/js/apps/custom-metrics/components/__tests__/Form-test.tsx
index a2b633095d9..1e828bc139e 100644
--- a/server/sonar-web/src/main/js/apps/custom-metrics/components/__tests__/Form-test.tsx
+++ b/server/sonar-web/src/main/js/apps/custom-metrics/components/__tests__/Form-test.tsx
@@ -54,6 +54,6 @@ it('should render form', async () => {
expect(onClose).toBeCalled();
onClose.mockClear();
- click(wrapper.find('button[type="reset"]'));
+ click(wrapper.find('ResetButtonLink'));
expect(onClose).toBeCalled();
});
diff --git a/server/sonar-web/src/main/js/apps/custom-metrics/components/__tests__/__snapshots__/CreateButton-test.tsx.snap b/server/sonar-web/src/main/js/apps/custom-metrics/components/__tests__/__snapshots__/CreateButton-test.tsx.snap
index fcc3412a7a6..46c2ffc4706 100644
--- a/server/sonar-web/src/main/js/apps/custom-metrics/components/__tests__/__snapshots__/CreateButton-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/custom-metrics/components/__tests__/__snapshots__/CreateButton-test.tsx.snap
@@ -2,23 +2,23 @@
exports[`should create new group 1`] = `
<React.Fragment>
- <button
+ <Button
id="metrics-create"
onClick={[Function]}
>
custom_metrics.create_metric
- </button>
+ </Button>
</React.Fragment>
`;
exports[`should create new group 2`] = `
<React.Fragment>
- <button
+ <Button
id="metrics-create"
onClick={[Function]}
>
custom_metrics.create_metric
- </button>
+ </Button>
<Form
confirmButtonText="create"
domains={
diff --git a/server/sonar-web/src/main/js/apps/custom-metrics/components/__tests__/__snapshots__/Form-test.tsx.snap b/server/sonar-web/src/main/js/apps/custom-metrics/components/__tests__/__snapshots__/Form-test.tsx.snap
index 0eea472611e..f0baf33640e 100644
--- a/server/sonar-web/src/main/js/apps/custom-metrics/components/__tests__/__snapshots__/Form-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/custom-metrics/components/__tests__/__snapshots__/Form-test.tsx.snap
@@ -144,22 +144,19 @@ exports[`should render form 1`] = `
loading={false}
timeout={100}
/>
- <button
+ <SubmitButton
disabled={false}
id="create-metric-submit"
- type="submit"
>
confirmButtonText
- </button>
- <button
- className="button-link"
+ </SubmitButton>
+ <ResetButtonLink
disabled={false}
id="create-metric-cancel"
onClick={[Function]}
- type="reset"
>
cancel
- </button>
+ </ResetButtonLink>
</footer>
</form>
</Modal>
diff --git a/server/sonar-web/src/main/js/apps/groups/components/EditMembers.tsx b/server/sonar-web/src/main/js/apps/groups/components/EditMembers.tsx
index a83ee573e55..9b62320e86b 100644
--- a/server/sonar-web/src/main/js/apps/groups/components/EditMembers.tsx
+++ b/server/sonar-web/src/main/js/apps/groups/components/EditMembers.tsx
@@ -23,7 +23,7 @@ import { Group } from '../../../app/types';
import Modal from '../../../components/controls/Modal';
import BulletListIcon from '../../../components/icons-components/BulletListIcon';
import SelectList from '../../../components/SelectList';
-import { ButtonIcon } from '../../../components/ui/buttons';
+import { ButtonIcon, ResetButtonLink } from '../../../components/ui/buttons';
import { translate } from '../../../helpers/l10n';
import { getBaseUrl } from '../../../helpers/urls';
@@ -64,12 +64,6 @@ export default class EditMembers extends React.PureComponent<Props, State> {
}
};
- handleCloseClick = (event: React.SyntheticEvent<HTMLElement>) => {
- event.preventDefault();
- event.currentTarget.blur();
- this.handleModalClose();
- };
-
renderSelectList = () => {
if (this.container) {
const extra = { name: this.props.group.name, organization: this.props.organization };
@@ -114,9 +108,7 @@ export default class EditMembers extends React.PureComponent<Props, State> {
</div>
<footer className="modal-foot">
- <button className="button-link" onClick={this.handleCloseClick} type="reset">
- {translate('Done')}
- </button>
+ <ResetButtonLink onClick={this.handleModalClose}>{translate('Done')}</ResetButtonLink>
</footer>
</Modal>
)}
diff --git a/server/sonar-web/src/main/js/apps/groups/components/Form.tsx b/server/sonar-web/src/main/js/apps/groups/components/Form.tsx
index 23452cef400..8d1e4fc8434 100644
--- a/server/sonar-web/src/main/js/apps/groups/components/Form.tsx
+++ b/server/sonar-web/src/main/js/apps/groups/components/Form.tsx
@@ -21,6 +21,7 @@ import * as React from 'react';
import { Group } from '../../../app/types';
import DeferredSpinner from '../../../components/common/DeferredSpinner';
import SimpleModal from '../../../components/controls/SimpleModal';
+import { ResetButtonLink, SubmitButton } from '../../../components/ui/buttons';
import { translate } from '../../../helpers/l10n';
interface Props {
@@ -102,12 +103,8 @@ export default class Form extends React.PureComponent<Props, State> {
<footer className="modal-foot">
<DeferredSpinner className="spacer-right" loading={submitting} />
- <button disabled={submitting} type="submit">
- {this.props.confirmButtonText}
- </button>
- <button className="button-link" onClick={onCloseClick} type="reset">
- {translate('cancel')}
- </button>
+ <SubmitButton disabled={submitting}>{this.props.confirmButtonText}</SubmitButton>
+ <ResetButtonLink onClick={onCloseClick}>{translate('cancel')}</ResetButtonLink>
</footer>
</form>
)}
diff --git a/server/sonar-web/src/main/js/apps/groups/components/Header.tsx b/server/sonar-web/src/main/js/apps/groups/components/Header.tsx
index 36f13bad647..cd2be39f671 100644
--- a/server/sonar-web/src/main/js/apps/groups/components/Header.tsx
+++ b/server/sonar-web/src/main/js/apps/groups/components/Header.tsx
@@ -20,6 +20,7 @@
import * as React from 'react';
import Form from './Form';
import DeferredSpinner from '../../../components/common/DeferredSpinner';
+import { Button } from '../../../components/ui/buttons';
import { translate } from '../../../helpers/l10n';
interface Props {
@@ -43,9 +44,7 @@ export default class Header extends React.PureComponent<Props, State> {
this.mounted = false;
}
- handleCreateClick = (event: React.SyntheticEvent<HTMLButtonElement>) => {
- event.preventDefault();
- event.currentTarget.blur();
+ handleCreateClick = () => {
this.setState({ createModal: true });
};
@@ -68,9 +67,9 @@ export default class Header extends React.PureComponent<Props, State> {
<DeferredSpinner loading={this.props.loading} />
<div className="page-actions">
- <button id="groups-create" onClick={this.handleCreateClick}>
+ <Button id="groups-create" onClick={this.handleCreateClick}>
{translate('groups.create_group')}
- </button>
+ </Button>
</div>
<p className="page-description">{translate('user_groups.page.description')}</p>
diff --git a/server/sonar-web/src/main/js/apps/groups/components/__tests__/EditGroup-test.tsx b/server/sonar-web/src/main/js/apps/groups/components/__tests__/EditGroup-test.tsx
index 578b79d356d..d650c321233 100644
--- a/server/sonar-web/src/main/js/apps/groups/components/__tests__/EditGroup-test.tsx
+++ b/server/sonar-web/src/main/js/apps/groups/components/__tests__/EditGroup-test.tsx
@@ -31,7 +31,7 @@ it('should edit group', () => {
<EditGroup group={group} onEdit={onEdit}>
{props => {
({ onClick } = props);
- return <button />;
+ return <div />;
}}
</EditGroup>
);
diff --git a/server/sonar-web/src/main/js/apps/groups/components/__tests__/EditMembers-test.tsx b/server/sonar-web/src/main/js/apps/groups/components/__tests__/EditMembers-test.tsx
index a4a9297d329..a480e466c8a 100644
--- a/server/sonar-web/src/main/js/apps/groups/components/__tests__/EditMembers-test.tsx
+++ b/server/sonar-web/src/main/js/apps/groups/components/__tests__/EditMembers-test.tsx
@@ -29,11 +29,10 @@ it('should edit members', () => {
const wrapper = shallow(<EditMembers group={group} onEdit={onEdit} organization="org" />);
expect(wrapper).toMatchSnapshot();
- wrapper.find('ButtonIcon').prop<Function>('onClick')();
- wrapper.update();
+ click(wrapper.find('ButtonIcon'));
expect(wrapper).toMatchSnapshot();
- click(wrapper.find('button[type="reset"]'));
+ click(wrapper.find('ResetButtonLink'));
expect(onEdit).toBeCalled();
expect(wrapper).toMatchSnapshot();
});
diff --git a/server/sonar-web/src/main/js/apps/groups/components/__tests__/Form-test.tsx b/server/sonar-web/src/main/js/apps/groups/components/__tests__/Form-test.tsx
index b89f7249231..744b90c813d 100644
--- a/server/sonar-web/src/main/js/apps/groups/components/__tests__/Form-test.tsx
+++ b/server/sonar-web/src/main/js/apps/groups/components/__tests__/Form-test.tsx
@@ -44,6 +44,6 @@ it('should render form', async () => {
expect(onClose).toBeCalled();
onClose.mockClear();
- click(wrapper.find('button[type="reset"]'));
+ click(wrapper.find('ResetButtonLink'));
expect(onClose).toBeCalled();
});
diff --git a/server/sonar-web/src/main/js/apps/groups/components/__tests__/Header-test.tsx b/server/sonar-web/src/main/js/apps/groups/components/__tests__/Header-test.tsx
index a237e8bafec..416b1585e11 100644
--- a/server/sonar-web/src/main/js/apps/groups/components/__tests__/Header-test.tsx
+++ b/server/sonar-web/src/main/js/apps/groups/components/__tests__/Header-test.tsx
@@ -27,7 +27,7 @@ it('should create new group', () => {
const wrapper = shallow(<Header loading={false} onCreate={onCreate} />);
expect(wrapper).toMatchSnapshot();
- click(wrapper.find('#groups-create'));
+ click(wrapper.find('[id="groups-create"]'));
expect(wrapper).toMatchSnapshot();
wrapper.find('Form').prop<Function>('onSubmit')({ name: 'foo', description: 'bar' });
diff --git a/server/sonar-web/src/main/js/apps/groups/components/__tests__/__snapshots__/EditGroup-test.tsx.snap b/server/sonar-web/src/main/js/apps/groups/components/__tests__/__snapshots__/EditGroup-test.tsx.snap
index 8b54df832b3..43bc8b832cb 100644
--- a/server/sonar-web/src/main/js/apps/groups/components/__tests__/__snapshots__/EditGroup-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/groups/components/__tests__/__snapshots__/EditGroup-test.tsx.snap
@@ -2,13 +2,13 @@
exports[`should edit group 1`] = `
<React.Fragment>
- <button />
+ <div />
</React.Fragment>
`;
exports[`should edit group 2`] = `
<React.Fragment>
- <button />
+ <div />
<Form
confirmButtonText="update_verb"
group={
@@ -27,6 +27,6 @@ exports[`should edit group 2`] = `
exports[`should edit group 3`] = `
<React.Fragment>
- <button />
+ <div />
</React.Fragment>
`;
diff --git a/server/sonar-web/src/main/js/apps/groups/components/__tests__/__snapshots__/EditMembers-test.tsx.snap b/server/sonar-web/src/main/js/apps/groups/components/__tests__/__snapshots__/EditMembers-test.tsx.snap
index 8c846140be8..230836640f5 100644
--- a/server/sonar-web/src/main/js/apps/groups/components/__tests__/__snapshots__/EditMembers-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/groups/components/__tests__/__snapshots__/EditMembers-test.tsx.snap
@@ -40,13 +40,11 @@ exports[`should edit members 2`] = `
<footer
className="modal-foot"
>
- <button
- className="button-link"
+ <ResetButtonLink
onClick={[Function]}
- type="reset"
>
Done
- </button>
+ </ResetButtonLink>
</footer>
</Modal>
</React.Fragment>
diff --git a/server/sonar-web/src/main/js/apps/groups/components/__tests__/__snapshots__/Form-test.tsx.snap b/server/sonar-web/src/main/js/apps/groups/components/__tests__/__snapshots__/Form-test.tsx.snap
index e43777b754e..2b0954e09fb 100644
--- a/server/sonar-web/src/main/js/apps/groups/components/__tests__/__snapshots__/Form-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/groups/components/__tests__/__snapshots__/Form-test.tsx.snap
@@ -67,19 +67,16 @@ exports[`should render form 1`] = `
loading={false}
timeout={100}
/>
- <button
+ <SubmitButton
disabled={false}
- type="submit"
>
confirmButtonText
- </button>
- <button
- className="button-link"
+ </SubmitButton>
+ <ResetButtonLink
onClick={[Function]}
- type="reset"
>
cancel
- </button>
+ </ResetButtonLink>
</footer>
</form>
</Modal>
diff --git a/server/sonar-web/src/main/js/apps/groups/components/__tests__/__snapshots__/Header-test.tsx.snap b/server/sonar-web/src/main/js/apps/groups/components/__tests__/__snapshots__/Header-test.tsx.snap
index 6578cf61fe8..546722468c8 100644
--- a/server/sonar-web/src/main/js/apps/groups/components/__tests__/__snapshots__/Header-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/groups/components/__tests__/__snapshots__/Header-test.tsx.snap
@@ -18,12 +18,12 @@ exports[`should create new group 1`] = `
<div
className="page-actions"
>
- <button
+ <Button
id="groups-create"
onClick={[Function]}
>
groups.create_group
- </button>
+ </Button>
</div>
<p
className="page-description"
@@ -52,12 +52,12 @@ exports[`should create new group 2`] = `
<div
className="page-actions"
>
- <button
+ <Button
id="groups-create"
onClick={[Function]}
>
groups.create_group
- </button>
+ </Button>
</div>
<p
className="page-description"
diff --git a/server/sonar-web/src/main/js/apps/maintenance/components/App.tsx b/server/sonar-web/src/main/js/apps/maintenance/components/App.tsx
index 3bc5e06b616..8f19a13856e 100644
--- a/server/sonar-web/src/main/js/apps/maintenance/components/App.tsx
+++ b/server/sonar-web/src/main/js/apps/maintenance/components/App.tsx
@@ -22,6 +22,7 @@ import * as classNames from 'classnames';
import { getMigrationStatus, getSystemStatus, migrateDatabase } from '../../../api/system';
import DateFromNow from '../../../components/intl/DateFromNow';
import TimeFormatter from '../../../components/intl/TimeFormatter';
+import { Button } from '../../../components/ui/buttons';
import { translate } from '../../../helpers/l10n';
import { getBaseUrl } from '../../../helpers/urls';
import '../styles.css';
@@ -113,9 +114,7 @@ export default class App extends React.PureComponent<Props, State> {
}, 2500);
};
- handleMigrateClick = (event: React.SyntheticEvent<HTMLButtonElement>) => {
- event.preventDefault();
- event.currentTarget.blur();
+ handleMigrateClick = () => {
migrateDatabase().then(
({ message, startedAt, state }) => {
if (this.mounted) {
@@ -221,9 +220,9 @@ export default class App extends React.PureComponent<Props, State> {
<p className="maintenance-text">{translate('maintenance.upgrade_database.2')}</p>
<p className="maintenance-text">{translate('maintenance.upgrade_database.3')}</p>
<div className="maintenance-spinner">
- <button id="start-migration" onClick={this.handleMigrateClick} type="button">
+ <Button id="start-migration" onClick={this.handleMigrateClick}>
{translate('maintenance.upgrade')}
- </button>
+ </Button>
</div>
</>
)}
diff --git a/server/sonar-web/src/main/js/apps/maintenance/components/__tests__/App-test.tsx b/server/sonar-web/src/main/js/apps/maintenance/components/__tests__/App-test.tsx
index 8d4511d09e7..93a6d4ab930 100644
--- a/server/sonar-web/src/main/js/apps/maintenance/components/__tests__/App-test.tsx
+++ b/server/sonar-web/src/main/js/apps/maintenance/components/__tests__/App-test.tsx
@@ -120,7 +120,7 @@ describe('Setup Page', () => {
await waitAndUpdate(wrapper);
expect(wrapper).toMatchSnapshot();
- click(wrapper.find('button'));
+ click(wrapper.find('Button'));
expect(migrateDatabase).toBeCalled();
await waitAndUpdate(wrapper);
expect(wrapper).toMatchSnapshot();
diff --git a/server/sonar-web/src/main/js/apps/maintenance/components/__tests__/__snapshots__/App-test.tsx.snap b/server/sonar-web/src/main/js/apps/maintenance/components/__tests__/__snapshots__/App-test.tsx.snap
index 784a8eb1969..d054e906e8c 100644
--- a/server/sonar-web/src/main/js/apps/maintenance/components/__tests__/__snapshots__/App-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/maintenance/components/__tests__/__snapshots__/App-test.tsx.snap
@@ -340,13 +340,12 @@ exports[`Setup Page should start migration 1`] = `
<div
className="maintenance-spinner"
>
- <button
+ <Button
id="start-migration"
onClick={[Function]}
- type="button"
>
maintenance.upgrade
- </button>
+ </Button>
</div>
</React.Fragment>
</div>
diff --git a/server/sonar-web/src/main/js/apps/marketplace/PendingActions.tsx b/server/sonar-web/src/main/js/apps/marketplace/PendingActions.tsx
index bbe8e3c48c3..d392d5efcc3 100644
--- a/server/sonar-web/src/main/js/apps/marketplace/PendingActions.tsx
+++ b/server/sonar-web/src/main/js/apps/marketplace/PendingActions.tsx
@@ -21,6 +21,7 @@ import * as React from 'react';
import { FormattedMessage } from 'react-intl';
import RestartForm from '../../components/common/RestartForm';
import { cancelPendingPlugins, PluginPending } from '../../api/plugins';
+import { Button } from '../../components/ui/buttons';
import { translate } from '../../helpers/l10n';
interface Props {
@@ -39,8 +40,13 @@ interface State {
export default class PendingActions extends React.PureComponent<Props, State> {
state: State = { openRestart: false };
- handleOpenRestart = () => this.setState({ openRestart: true });
- hanleCloseRestart = () => this.setState({ openRestart: false });
+ handleOpenRestart = () => {
+ this.setState({ openRestart: true });
+ };
+
+ hanleCloseRestart = () => {
+ this.setState({ openRestart: false });
+ };
handleRevert = () => {
cancelPendingPlugins().then(this.props.refreshPending, () => {});
@@ -88,12 +94,12 @@ export default class PendingActions extends React.PureComponent<Props, State> {
</ul>
</div>
<div className="pull-right">
- <button className="js-restart little-spacer-right" onClick={this.handleOpenRestart}>
+ <Button className="js-restart little-spacer-right" onClick={this.handleOpenRestart}>
{translate('marketplace.restart')}
- </button>
- <button className="js-cancel-all button-red" onClick={this.handleRevert}>
+ </Button>
+ <Button className="js-cancel-all button-red" onClick={this.handleRevert}>
{translate('marketplace.revert')}
- </button>
+ </Button>
</div>
{this.state.openRestart && <RestartForm onClose={this.hanleCloseRestart} />}
</div>
diff --git a/server/sonar-web/src/main/js/apps/marketplace/__tests__/__snapshots__/PendingActions-test.tsx.snap b/server/sonar-web/src/main/js/apps/marketplace/__tests__/__snapshots__/PendingActions-test.tsx.snap
index f68b3b68416..c8688596746 100644
--- a/server/sonar-web/src/main/js/apps/marketplace/__tests__/__snapshots__/PendingActions-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/marketplace/__tests__/__snapshots__/PendingActions-test.tsx.snap
@@ -44,18 +44,18 @@ exports[`should display pending actions 1`] = `
<div
className="pull-right"
>
- <button
+ <Button
className="js-restart little-spacer-right"
onClick={[Function]}
>
marketplace.restart
- </button>
- <button
+ </Button>
+ <Button
className="js-cancel-all button-red"
onClick={[Function]}
>
marketplace.revert
- </button>
+ </Button>
</div>
</div>
`;
diff --git a/server/sonar-web/src/main/js/apps/marketplace/components/EditionBox.tsx b/server/sonar-web/src/main/js/apps/marketplace/components/EditionBox.tsx
index 10965d760ce..0ad689bc93d 100644
--- a/server/sonar-web/src/main/js/apps/marketplace/components/EditionBox.tsx
+++ b/server/sonar-web/src/main/js/apps/marketplace/components/EditionBox.tsx
@@ -20,6 +20,7 @@
import * as React from 'react';
import EditionBoxBadge from './EditionBoxBadge';
import { Edition, EditionStatus } from '../../../api/marketplace';
+import { Button } from '../../../components/ui/buttons';
import { translate } from '../../../helpers/l10n';
interface Props {
@@ -32,7 +33,9 @@ interface Props {
}
export default class EditionBox extends React.PureComponent<Props> {
- handleAction = () => this.props.onAction(this.props.edition);
+ handleAction = () => {
+ this.props.onAction(this.props.edition);
+ };
render() {
const { disableAction, displayAction, edition, editionStatus } = this.props;
@@ -48,9 +51,9 @@ export default class EditionBox extends React.PureComponent<Props> {
{translate('marketplace.learn_more')}
</a>
{displayAction && (
- <button disabled={disableAction} onClick={this.handleAction}>
+ <Button disabled={disableAction} onClick={this.handleAction}>
{this.props.actionLabel}
- </button>
+ </Button>
)}
</div>
</div>
diff --git a/server/sonar-web/src/main/js/apps/marketplace/components/LicenseEditionForm.tsx b/server/sonar-web/src/main/js/apps/marketplace/components/LicenseEditionForm.tsx
index fb609f9e30a..a4c48287869 100644
--- a/server/sonar-web/src/main/js/apps/marketplace/components/LicenseEditionForm.tsx
+++ b/server/sonar-web/src/main/js/apps/marketplace/components/LicenseEditionForm.tsx
@@ -21,6 +21,7 @@ import * as React from 'react';
import LicenseEditionSet from './LicenseEditionSet';
import { Edition, EditionStatus, applyLicense } from '../../../api/marketplace';
import Modal from '../../../components/controls/Modal';
+import { Button, ResetButtonLink } from '../../../components/ui/buttons';
import { translate, translateWithParameters } from '../../../helpers/l10n';
export interface Props {
@@ -55,13 +56,7 @@ export default class LicenseEditionForm extends React.PureComponent<Props, State
}
};
- handleCancelClick = (event: React.SyntheticEvent<HTMLAnchorElement>) => {
- event.preventDefault();
- this.props.onClose();
- };
-
- handleConfirmClick = (event: React.SyntheticEvent<HTMLButtonElement>) => {
- event.preventDefault();
+ handleConfirmClick = () => {
const { license, status } = this.state;
if (license && status) {
this.setState({ submitting: true });
@@ -102,18 +97,16 @@ export default class LicenseEditionForm extends React.PureComponent<Props, State
<footer className="modal-foot">
{submitting && <i className="spinner spacer-right" />}
{status && (
- <button
+ <Button
className="js-confirm"
- onClick={this.handleConfirmClick}
- disabled={!license || submitting}>
+ disabled={!license || submitting}
+ onClick={this.handleConfirmClick}>
{status === 'AUTOMATIC_INSTALL'
? translate('marketplace.install')
: translate('save')}
- </button>
+ </Button>
)}
- <a className="js-modal-close" href="#" onClick={this.handleCancelClick}>
- {translate('cancel')}
- </a>
+ <ResetButtonLink onClick={this.props.onClose}>{translate('cancel')}</ResetButtonLink>
</footer>
</Modal>
);
diff --git a/server/sonar-web/src/main/js/apps/marketplace/components/PluginActions.tsx b/server/sonar-web/src/main/js/apps/marketplace/components/PluginActions.tsx
index 8edda448a25..45ca8e69773 100644
--- a/server/sonar-web/src/main/js/apps/marketplace/components/PluginActions.tsx
+++ b/server/sonar-web/src/main/js/apps/marketplace/components/PluginActions.tsx
@@ -19,10 +19,11 @@
*/
import * as React from 'react';
import PluginUpdateButton from './PluginUpdateButton';
+import { isPluginAvailable, isPluginInstalled } from '../utils';
+import { Plugin, installPlugin, updatePlugin, uninstallPlugin } from '../../../api/plugins';
import Checkbox from '../../../components/controls/Checkbox';
import CheckIcon from '../../../components/icons-components/CheckIcon';
-import { Plugin, installPlugin, updatePlugin, uninstallPlugin } from '../../../api/plugins';
-import { isPluginAvailable, isPluginInstalled } from '../utils';
+import { Button } from '../../../components/ui/buttons';
import { translate } from '../../../helpers/l10n';
interface Props {
@@ -150,23 +151,21 @@ export default class PluginActions extends React.PureComponent<Props, State> {
update={update}
/>
))}
- <button
+ <Button
className="js-uninstall button-red little-spacer-left"
disabled={loading}
- onClick={this.handleUninstall}
- type="button">
+ onClick={this.handleUninstall}>
{translate('marketplace.uninstall')}
- </button>
+ </Button>
</div>
)}
{isPluginAvailable(plugin) && (
- <button
+ <Button
className="js-install"
disabled={loading || (plugin.termsAndConditionsUrl != null && !this.state.acceptTerms)}
- onClick={this.handleInstall}
- type="button">
+ onClick={this.handleInstall}>
{translate('marketplace.install')}
- </button>
+ </Button>
)}
</div>
);
diff --git a/server/sonar-web/src/main/js/apps/marketplace/components/PluginChangeLogButton.tsx b/server/sonar-web/src/main/js/apps/marketplace/components/PluginChangeLogButton.tsx
index a1f17963a7e..b542908b5c2 100644
--- a/server/sonar-web/src/main/js/apps/marketplace/components/PluginChangeLogButton.tsx
+++ b/server/sonar-web/src/main/js/apps/marketplace/components/PluginChangeLogButton.tsx
@@ -19,8 +19,9 @@
*/
import * as React from 'react';
import PluginChangeLog from './PluginChangeLog';
-import BubblePopupHelper from '../../../components/common/BubblePopupHelper';
import { Release, Update } from '../../../api/plugins';
+import BubblePopupHelper from '../../../components/common/BubblePopupHelper';
+import { Button } from '../../../components/ui/buttons';
interface Props {
release: Release;
@@ -34,12 +35,6 @@ interface State {
export default class PluginChangeLogButton extends React.PureComponent<Props, State> {
state: State = { changelogOpen: false };
- handleChangelogClick = (event: React.SyntheticEvent<HTMLButtonElement>) => {
- event.preventDefault();
- event.stopPropagation();
- this.toggleChangelog();
- };
-
toggleChangelog = (show?: boolean) => {
if (show !== undefined) {
this.setState({ changelogOpen: show });
@@ -48,17 +43,21 @@ export default class PluginChangeLogButton extends React.PureComponent<Props, St
}
};
+ handleClick = () => {
+ this.toggleChangelog();
+ };
+
render() {
return (
<div className="display-inline-block little-spacer-left">
- <button
+ <Button
className="button-link js-changelog issue-rule icon-ellipsis-h"
- onClick={this.handleChangelogClick}
+ onClick={this.handleClick}
/>
<BubblePopupHelper
isOpen={this.state.changelogOpen}
- position="bottomright"
popup={<PluginChangeLog release={this.props.release} update={this.props.update} />}
+ position="bottomright"
togglePopup={this.toggleChangelog}
/>
</div>
diff --git a/server/sonar-web/src/main/js/apps/marketplace/components/PluginUpdateButton.tsx b/server/sonar-web/src/main/js/apps/marketplace/components/PluginUpdateButton.tsx
index b426f048247..8899613e0b9 100644
--- a/server/sonar-web/src/main/js/apps/marketplace/components/PluginUpdateButton.tsx
+++ b/server/sonar-web/src/main/js/apps/marketplace/components/PluginUpdateButton.tsx
@@ -19,6 +19,7 @@
*/
import * as React from 'react';
import { Update } from '../../../api/plugins';
+import { Button } from '../../../components/ui/buttons';
import { translateWithParameters } from '../../../helpers/l10n';
interface Props {
@@ -28,7 +29,9 @@ interface Props {
}
export default class PluginUpdateButton extends React.PureComponent<Props> {
- handleClick = () => this.props.onClick(this.props.update);
+ handleClick = () => {
+ this.props.onClick(this.props.update);
+ };
render() {
const { disabled, update } = this.props;
@@ -36,13 +39,12 @@ export default class PluginUpdateButton extends React.PureComponent<Props> {
return null;
}
return (
- <button
+ <Button
className="js-update little-spacer-bottom"
disabled={disabled}
- onClick={this.handleClick}
- type="button">
+ onClick={this.handleClick}>
{translateWithParameters('marketplace.update_to_x', update.release.version)}
- </button>
+ </Button>
);
}
}
diff --git a/server/sonar-web/src/main/js/apps/marketplace/components/UninstallEditionForm.tsx b/server/sonar-web/src/main/js/apps/marketplace/components/UninstallEditionForm.tsx
index ad79e2a31d2..1b9be29c7df 100644
--- a/server/sonar-web/src/main/js/apps/marketplace/components/UninstallEditionForm.tsx
+++ b/server/sonar-web/src/main/js/apps/marketplace/components/UninstallEditionForm.tsx
@@ -20,6 +20,7 @@
import * as React from 'react';
import { Edition, EditionStatus, uninstallEdition } from '../../../api/marketplace';
import Modal from '../../../components/controls/Modal';
+import { Button, ResetButtonLink } from '../../../components/ui/buttons';
import { translate, translateWithParameters } from '../../../helpers/l10n';
export interface Props {
@@ -45,13 +46,7 @@ export default class UninstallEditionForm extends React.PureComponent<Props, Sta
this.mounted = false;
}
- handleCancelClick = (event: React.SyntheticEvent<HTMLAnchorElement>) => {
- event.preventDefault();
- this.props.onClose();
- };
-
- handleConfirmClick = (event: React.SyntheticEvent<HTMLButtonElement>) => {
- event.preventDefault();
+ handleConfirmClick = () => {
this.setState({ loading: true });
uninstallEdition()
.then(() => {
@@ -86,12 +81,12 @@ export default class UninstallEditionForm extends React.PureComponent<Props, Sta
<footer className="modal-foot">
{loading && <i className="spinner spacer-right" />}
- <button disabled={loading} onClick={this.handleConfirmClick}>
+ <Button disabled={loading} onClick={this.handleConfirmClick}>
{translate('marketplace.downgrade')}
- </button>
- <a className="js-modal-close" href="#" onClick={this.handleCancelClick}>
+ </Button>
+ <ResetButtonLink className="js-modal-close" onClick={this.props.onClose}>
{translate('cancel')}
- </a>
+ </ResetButtonLink>
</footer>
</Modal>
);
diff --git a/server/sonar-web/src/main/js/apps/marketplace/components/__tests__/LicenseEditionForm-test.tsx b/server/sonar-web/src/main/js/apps/marketplace/components/__tests__/LicenseEditionForm-test.tsx
index 42db6f8c02b..9814570cbf8 100644
--- a/server/sonar-web/src/main/js/apps/marketplace/components/__tests__/LicenseEditionForm-test.tsx
+++ b/server/sonar-web/src/main/js/apps/marketplace/components/__tests__/LicenseEditionForm-test.tsx
@@ -54,22 +54,19 @@ it('should correctly change the button based on the status and license', () => {
(wrapper.instance() as LicenseEditionForm).mounted = true;
wrapper.setState({ license: 'mylicense', status: 'NO_INSTALL' });
- button = wrapper.find('button');
- expect(button.text()).toBe('save');
- expect(button.prop('disabled')).toBeFalsy();
+ button = wrapper.find('Button');
+ expect(button).toMatchSnapshot();
wrapper.setState({ license: undefined, status: 'MANUAL_INSTALL' });
- button = wrapper.find('button');
- expect(button.text()).toBe('save');
- expect(button.prop('disabled')).toBeTruthy();
+ button = wrapper.find('Button');
+ expect(button).toMatchSnapshot();
wrapper.setState({ status: 'AUTOMATIC_INSTALL' });
- button = wrapper.find('button');
- expect(button.text()).toContain('install');
- expect(button.prop('disabled')).toBeTruthy();
+ button = wrapper.find('Button');
+ expect(button).toMatchSnapshot();
wrapper.setState({ license: 'mylicense' });
- expect(wrapper.find('button').prop('disabled')).toBeFalsy();
+ expect(wrapper.find('Button').prop('disabled')).toBeFalsy();
});
it('should update the edition status after install', async () => {
@@ -78,7 +75,7 @@ it('should update the edition status after install', async () => {
const form = wrapper.instance() as LicenseEditionForm;
form.handleLicenseChange('mylicense', 'AUTOMATIC_INSTALL');
wrapper.update();
- click(wrapper.find('button'));
+ click(wrapper.find('Button'));
expect(applyLicense).toHaveBeenCalledWith({ license: 'mylicense' });
await new Promise(setImmediate);
expect(updateEditionStatus).toHaveBeenCalledWith({
diff --git a/server/sonar-web/src/main/js/apps/marketplace/components/__tests__/UninstallEditionForm-test.tsx b/server/sonar-web/src/main/js/apps/marketplace/components/__tests__/UninstallEditionForm-test.tsx
index 11256063574..f8dbede4cb2 100644
--- a/server/sonar-web/src/main/js/apps/marketplace/components/__tests__/UninstallEditionForm-test.tsx
+++ b/server/sonar-web/src/main/js/apps/marketplace/components/__tests__/UninstallEditionForm-test.tsx
@@ -50,7 +50,7 @@ it('should update the edition status after uninstall', async () => {
const updateEditionStatus = jest.fn();
const wrapper = getWrapper({ updateEditionStatus });
(wrapper.instance() as UninstallEditionForm).mounted = true;
- click(wrapper.find('button'));
+ click(wrapper.find('Button'));
expect(uninstallEdition).toHaveBeenCalled();
await new Promise(setImmediate);
expect(updateEditionStatus).toHaveBeenCalledWith({
diff --git a/server/sonar-web/src/main/js/apps/marketplace/components/__tests__/__snapshots__/EditionBox-test.tsx.snap b/server/sonar-web/src/main/js/apps/marketplace/components/__tests__/__snapshots__/EditionBox-test.tsx.snap
index 9fa9b253102..b9925cec2c1 100644
--- a/server/sonar-web/src/main/js/apps/marketplace/components/__tests__/__snapshots__/EditionBox-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/marketplace/components/__tests__/__snapshots__/EditionBox-test.tsx.snap
@@ -70,12 +70,12 @@ exports[`should disable action button 1`] = `
>
marketplace.learn_more
</a>
- <button
+ <Button
disabled={true}
onClick={[Function]}
>
action
- </button>
+ </Button>
</div>
</div>
`;
@@ -113,12 +113,12 @@ exports[`should display the edition 1`] = `
>
marketplace.learn_more
</a>
- <button
+ <Button
disabled={false}
onClick={[Function]}
>
action
- </button>
+ </Button>
</div>
</div>
`;
diff --git a/server/sonar-web/src/main/js/apps/marketplace/components/__tests__/__snapshots__/LicenseEditionForm-test.tsx.snap b/server/sonar-web/src/main/js/apps/marketplace/components/__tests__/__snapshots__/LicenseEditionForm-test.tsx.snap
index 9c3d5970d11..c0dcce3c40a 100644
--- a/server/sonar-web/src/main/js/apps/marketplace/components/__tests__/__snapshots__/LicenseEditionForm-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/marketplace/components/__tests__/__snapshots__/LicenseEditionForm-test.tsx.snap
@@ -1,5 +1,35 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
+exports[`should correctly change the button based on the status and license 1`] = `
+<Button
+ className="js-confirm"
+ disabled={false}
+ onClick={[Function]}
+>
+ save
+</Button>
+`;
+
+exports[`should correctly change the button based on the status and license 2`] = `
+<Button
+ className="js-confirm"
+ disabled={true}
+ onClick={[Function]}
+>
+ save
+</Button>
+`;
+
+exports[`should correctly change the button based on the status and license 3`] = `
+<Button
+ className="js-confirm"
+ disabled={true}
+ onClick={[Function]}
+>
+ marketplace.install
+</Button>
+`;
+
exports[`should display correctly 1`] = `
<Modal
contentLabel="marketplace.upgrade_to_x.Foo"
@@ -41,13 +71,11 @@ exports[`should display correctly 1`] = `
<footer
className="modal-foot"
>
- <a
- className="js-modal-close"
- href="#"
- onClick={[Function]}
+ <ResetButtonLink
+ onClick={[MockFunction]}
>
cancel
- </a>
+ </ResetButtonLink>
</footer>
</Modal>
`;
diff --git a/server/sonar-web/src/main/js/apps/marketplace/components/__tests__/__snapshots__/UninstallEditionForm-test.tsx.snap b/server/sonar-web/src/main/js/apps/marketplace/components/__tests__/__snapshots__/UninstallEditionForm-test.tsx.snap
index 06d57cb8f6f..491d59eb8f5 100644
--- a/server/sonar-web/src/main/js/apps/marketplace/components/__tests__/__snapshots__/UninstallEditionForm-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/marketplace/components/__tests__/__snapshots__/UninstallEditionForm-test.tsx.snap
@@ -22,19 +22,18 @@ exports[`should display correctly 1`] = `
<footer
className="modal-foot"
>
- <button
+ <Button
disabled={false}
onClick={[Function]}
>
marketplace.downgrade
- </button>
- <a
+ </Button>
+ <ResetButtonLink
className="js-modal-close"
- href="#"
- onClick={[Function]}
+ onClick={[MockFunction]}
>
cancel
- </a>
+ </ResetButtonLink>
</footer>
</Modal>
`;
diff --git a/server/sonar-web/src/main/js/apps/overview/badges/BadgeButton.tsx b/server/sonar-web/src/main/js/apps/overview/badges/BadgeButton.tsx
index a43aa00e075..832e0e43bc1 100644
--- a/server/sonar-web/src/main/js/apps/overview/badges/BadgeButton.tsx
+++ b/server/sonar-web/src/main/js/apps/overview/badges/BadgeButton.tsx
@@ -20,6 +20,7 @@
import * as React from 'react';
import * as classNames from 'classnames';
import { BadgeType } from './utils';
+import { Button } from '../../../components/ui/buttons';
import { translate } from '../../../helpers/l10n';
interface Props {
@@ -30,15 +31,17 @@ interface Props {
}
export default class BadgeButton extends React.PureComponent<Props> {
- handleClick = () => this.props.onClick(this.props.type);
+ handleClick = () => {
+ this.props.onClick(this.props.type);
+ };
render() {
const { selected, type, url } = this.props;
const width = type !== BadgeType.measure ? '128px' : undefined;
return (
- <button className={classNames('badge-button', { selected })} onClick={this.handleClick}>
- <img src={url} alt={translate('overview.badges', type, 'alt')} width={width} />
- </button>
+ <Button className={classNames('badge-button', { selected })} onClick={this.handleClick}>
+ <img alt={translate('overview.badges', type, 'alt')} src={url} width={width} />
+ </Button>
);
}
}
diff --git a/server/sonar-web/src/main/js/apps/overview/badges/BadgesModal.tsx b/server/sonar-web/src/main/js/apps/overview/badges/BadgesModal.tsx
index 4a4e572f7c3..fc98e4eb71a 100644
--- a/server/sonar-web/src/main/js/apps/overview/badges/BadgesModal.tsx
+++ b/server/sonar-web/src/main/js/apps/overview/badges/BadgesModal.tsx
@@ -26,6 +26,7 @@ import { Metric } from '../../../app/types';
import Modal from '../../../components/controls/Modal';
import { translate } from '../../../helpers/l10n';
import './styles.css';
+import { Button, ResetButtonLink } from '../../../components/ui/buttons';
interface Props {
branch?: string;
@@ -46,18 +47,21 @@ export default class BadgesModal extends React.PureComponent<Props, State> {
badgeOptions: { color: 'white', metric: 'alert_status' }
};
- handleClose = () => this.setState({ open: false });
-
- handleOpen = () => this.setState({ open: true });
+ handleClose = () => {
+ this.setState({ open: false });
+ };
- handleSelectBadge = (selectedType: BadgeType) => this.setState({ selectedType });
+ handleOpen = () => {
+ this.setState({ open: true });
+ };
- handleUpdateOptions = (options: Partial<BadgeOptions>) =>
- this.setState(state => ({
- badgeOptions: { ...state.badgeOptions, ...options }
- }));
+ handleSelectBadge = (selectedType: BadgeType) => {
+ this.setState({ selectedType });
+ };
- handleCancelClick = () => this.handleClose();
+ handleUpdateOptions = (options: Partial<BadgeOptions>) => {
+ this.setState(state => ({ badgeOptions: { ...state.badgeOptions, ...options } }));
+ };
render() {
const { branch, project } = this.props;
@@ -66,9 +70,9 @@ export default class BadgesModal extends React.PureComponent<Props, State> {
const fullBadgeOptions = { branch, project, ...badgeOptions };
return (
<div className="overview-meta-card">
- <button className="js-project-badges" onClick={this.handleOpen}>
+ <Button className="js-project-badges" onClick={this.handleOpen}>
{translate('overview.badges.get_badge')}
- </button>
+ </Button>
{this.state.open && (
<Modal contentLabel={header} onRequestClose={this.handleClose}>
<header className="modal-head">
@@ -100,9 +104,9 @@ export default class BadgesModal extends React.PureComponent<Props, State> {
<BadgeSnippet snippet={getBadgeUrl(selectedType, fullBadgeOptions)} />
</div>
<footer className="modal-foot">
- <button className="button-link js-modal-close" onClick={this.handleCancelClick}>
+ <ResetButtonLink className="js-modal-close" onClick={this.handleClose}>
{translate('close')}
- </button>
+ </ResetButtonLink>
</footer>
</Modal>
)}
diff --git a/server/sonar-web/src/main/js/apps/overview/badges/__tests__/BadgeButton-test.tsx b/server/sonar-web/src/main/js/apps/overview/badges/__tests__/BadgeButton-test.tsx
index 3f958698649..4e45f44e94a 100644
--- a/server/sonar-web/src/main/js/apps/overview/badges/__tests__/BadgeButton-test.tsx
+++ b/server/sonar-web/src/main/js/apps/overview/badges/__tests__/BadgeButton-test.tsx
@@ -32,7 +32,7 @@ it('should display correctly', () => {
it('should return the badge type on click', () => {
const onClick = jest.fn();
const wrapper = getWrapper({ onClick });
- click(wrapper.find('button'));
+ click(wrapper.find('Button'));
expect(onClick).toHaveBeenCalledWith(BadgeType.marketing);
});
diff --git a/server/sonar-web/src/main/js/apps/overview/badges/__tests__/BadgesModal-test.tsx b/server/sonar-web/src/main/js/apps/overview/badges/__tests__/BadgesModal-test.tsx
index fc403fc3f17..cea857f2e90 100644
--- a/server/sonar-web/src/main/js/apps/overview/badges/__tests__/BadgesModal-test.tsx
+++ b/server/sonar-web/src/main/js/apps/overview/badges/__tests__/BadgesModal-test.tsx
@@ -29,6 +29,6 @@ jest.mock('../../../../helpers/urls', () => ({
it('should display the modal after click', () => {
const wrapper = shallow(<BadgesModal branch="branch-6.6" metrics={{}} project="foo" />);
expect(wrapper).toMatchSnapshot();
- click(wrapper.find('button'));
+ click(wrapper.find('Button'));
expect(wrapper.find('Modal')).toMatchSnapshot();
});
diff --git a/server/sonar-web/src/main/js/apps/overview/badges/__tests__/__snapshots__/BadgeButton-test.tsx.snap b/server/sonar-web/src/main/js/apps/overview/badges/__tests__/__snapshots__/BadgeButton-test.tsx.snap
index 90b4d8e5e37..c1ea1a7eb50 100644
--- a/server/sonar-web/src/main/js/apps/overview/badges/__tests__/__snapshots__/BadgeButton-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/overview/badges/__tests__/__snapshots__/BadgeButton-test.tsx.snap
@@ -1,7 +1,7 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`should display correctly 1`] = `
-<button
+<Button
className="badge-button"
onClick={[Function]}
>
@@ -10,11 +10,11 @@ exports[`should display correctly 1`] = `
src="http://foo.bar"
width="128px"
/>
-</button>
+</Button>
`;
exports[`should display correctly 2`] = `
-<button
+<Button
className="badge-button selected"
onClick={[Function]}
>
@@ -23,11 +23,11 @@ exports[`should display correctly 2`] = `
src="http://foo.bar"
width="128px"
/>
-</button>
+</Button>
`;
exports[`should display correctly 3`] = `
-<button
+<Button
className="badge-button"
onClick={[Function]}
>
@@ -35,5 +35,5 @@ exports[`should display correctly 3`] = `
alt="overview.badges.measure.alt"
src="http://foo.bar"
/>
-</button>
+</Button>
`;
diff --git a/server/sonar-web/src/main/js/apps/overview/badges/__tests__/__snapshots__/BadgesModal-test.tsx.snap b/server/sonar-web/src/main/js/apps/overview/badges/__tests__/__snapshots__/BadgesModal-test.tsx.snap
index e813fd772bd..8366543e432 100644
--- a/server/sonar-web/src/main/js/apps/overview/badges/__tests__/__snapshots__/BadgesModal-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/overview/badges/__tests__/__snapshots__/BadgesModal-test.tsx.snap
@@ -4,12 +4,12 @@ exports[`should display the modal after click 1`] = `
<div
className="overview-meta-card"
>
- <button
+ <Button
className="js-project-badges"
onClick={[Function]}
>
overview.badges.get_badge
- </button>
+ </Button>
</div>
`;
@@ -82,12 +82,12 @@ exports[`should display the modal after click 2`] = `
<footer
className="modal-foot"
>
- <button
- className="button-link js-modal-close"
+ <ResetButtonLink
+ className="js-modal-close"
onClick={[Function]}
>
close
- </button>
+ </ResetButtonLink>
</footer>
</Modal>
`;
diff --git a/server/sonar-web/src/main/js/apps/overview/meta/MetaTags.tsx b/server/sonar-web/src/main/js/apps/overview/meta/MetaTags.tsx
index 07365b26330..4dde591feb7 100644
--- a/server/sonar-web/src/main/js/apps/overview/meta/MetaTags.tsx
+++ b/server/sonar-web/src/main/js/apps/overview/meta/MetaTags.tsx
@@ -24,6 +24,7 @@ import { translate } from '../../../helpers/l10n';
import TagsList from '../../../components/tags/TagsList';
import { BubblePopupPosition } from '../../../components/common/BubblePopup';
import { Component } from '../../../app/types';
+import { Button } from '../../../components/ui/buttons';
interface Props {
component: Component;
@@ -37,7 +38,7 @@ interface State {
export default class MetaTags extends React.PureComponent<Props, State> {
card?: HTMLDivElement | null;
- tagsList?: HTMLButtonElement | null;
+ tagsList?: HTMLElement | null;
tagsSelector?: HTMLDivElement | null;
state: State = { popupOpen: false, popupPosition: { top: 0, right: 0 } };
@@ -70,8 +71,7 @@ export default class MetaTags extends React.PureComponent<Props, State> {
}
};
- handleClick = (evt: React.SyntheticEvent<HTMLButtonElement>) => {
- evt.stopPropagation();
+ handleClick = () => {
this.setState(state => ({ popupOpen: !state.popupOpen }));
};
@@ -100,12 +100,13 @@ export default class MetaTags extends React.PureComponent<Props, State> {
if (this.canUpdateTags()) {
return (
<div className="big-spacer-top overview-meta-tags" ref={card => (this.card = card)}>
- <button
+ <Button
className="button-link"
+ innerRef={tagsList => (this.tagsList = tagsList)}
onClick={this.handleClick}
- ref={tagsList => (this.tagsList = tagsList)}>
+ stopPropagation={true}>
<TagsList allowUpdate={true} tags={tags.length ? tags : [translate('no_tags')]} />
- </button>
+ </Button>
{popupOpen && (
<div ref={tagsSelector => (this.tagsSelector = tagsSelector)}>
<MetaTagsSelector
diff --git a/server/sonar-web/src/main/js/apps/overview/meta/__tests__/MetaTags-test.tsx b/server/sonar-web/src/main/js/apps/overview/meta/__tests__/MetaTags-test.tsx
index 1479225a022..7fa2003a331 100644
--- a/server/sonar-web/src/main/js/apps/overview/meta/__tests__/MetaTags-test.tsx
+++ b/server/sonar-web/src/main/js/apps/overview/meta/__tests__/MetaTags-test.tsx
@@ -72,10 +72,10 @@ it('should open the tag selector on click', () => {
expect(wrapper).toMatchSnapshot();
// open
- click(wrapper.find('button'));
+ click(wrapper.find('Button'));
expect(wrapper).toMatchSnapshot();
// close
- click(wrapper.find('button'));
+ click(wrapper.find('Button'));
expect(wrapper).toMatchSnapshot();
});
diff --git a/server/sonar-web/src/main/js/apps/overview/meta/__tests__/__snapshots__/MetaTags-test.tsx.snap b/server/sonar-web/src/main/js/apps/overview/meta/__tests__/__snapshots__/MetaTags-test.tsx.snap
index 1eea19831ab..d0b063accf7 100644
--- a/server/sonar-web/src/main/js/apps/overview/meta/__tests__/__snapshots__/MetaTags-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/overview/meta/__tests__/__snapshots__/MetaTags-test.tsx.snap
@@ -4,9 +4,11 @@ exports[`should open the tag selector on click 1`] = `
<div
className="big-spacer-top overview-meta-tags"
>
- <button
+ <Button
className="button-link"
+ innerRef={[Function]}
onClick={[Function]}
+ stopPropagation={true}
>
<TagsList
allowUpdate={true}
@@ -17,7 +19,7 @@ exports[`should open the tag selector on click 1`] = `
]
}
/>
- </button>
+ </Button>
</div>
`;
@@ -25,9 +27,11 @@ exports[`should open the tag selector on click 2`] = `
<div
className="big-spacer-top overview-meta-tags"
>
- <button
+ <Button
className="button-link"
+ innerRef={[Function]}
onClick={[Function]}
+ stopPropagation={true}
>
<TagsList
allowUpdate={true}
@@ -38,7 +42,7 @@ exports[`should open the tag selector on click 2`] = `
]
}
/>
- </button>
+ </Button>
<div>
<MetaTagsSelector
position={
@@ -64,9 +68,11 @@ exports[`should open the tag selector on click 3`] = `
<div
className="big-spacer-top overview-meta-tags"
>
- <button
+ <Button
className="button-link"
+ innerRef={[Function]}
onClick={[Function]}
+ stopPropagation={true}
>
<TagsList
allowUpdate={true}
@@ -77,7 +83,7 @@ exports[`should open the tag selector on click 3`] = `
]
}
/>
- </button>
+ </Button>
</div>
`;
@@ -85,9 +91,11 @@ exports[`should render with tags and admin rights 1`] = `
<div
className="big-spacer-top overview-meta-tags"
>
- <button
+ <Button
className="button-link"
+ innerRef={[Function]}
onClick={[Function]}
+ stopPropagation={true}
>
<TagsList
allowUpdate={true}
@@ -98,7 +106,7 @@ exports[`should render with tags and admin rights 1`] = `
]
}
/>
- </button>
+ </Button>
</div>
`;
diff --git a/server/sonar-web/src/main/js/apps/permission-templates/components/Form.tsx b/server/sonar-web/src/main/js/apps/permission-templates/components/Form.tsx
index 3bf36d12b1d..828fc380d78 100644
--- a/server/sonar-web/src/main/js/apps/permission-templates/components/Form.tsx
+++ b/server/sonar-web/src/main/js/apps/permission-templates/components/Form.tsx
@@ -21,6 +21,7 @@ import * as React from 'react';
import DeferredSpinner from '../../../components/common/DeferredSpinner';
import SimpleModal from '../../../components/controls/SimpleModal';
import { translate } from '../../../helpers/l10n';
+import { SubmitButton, ResetButtonLink } from '../../../components/ui/buttons';
interface Props {
confirmButtonText: string;
@@ -134,17 +135,15 @@ export default class Form extends React.PureComponent<Props, State> {
<footer className="modal-foot">
<DeferredSpinner className="spacer-right" loading={submitting} />
- <button disabled={submitting} id="permission-template-submit" type="submit">
+ <SubmitButton disabled={submitting} id="permission-template-submit">
{this.props.confirmButtonText}
- </button>
- <button
- className="button-link"
+ </SubmitButton>
+ <ResetButtonLink
disabled={submitting}
id="permission-template-cancel"
- onClick={onCloseClick}
- type="reset">
+ onClick={onCloseClick}>
{translate('cancel')}
- </button>
+ </ResetButtonLink>
</footer>
</form>
)}
diff --git a/server/sonar-web/src/main/js/apps/permission-templates/components/Header.tsx b/server/sonar-web/src/main/js/apps/permission-templates/components/Header.tsx
index 1db801795fe..e6d9b84dc88 100644
--- a/server/sonar-web/src/main/js/apps/permission-templates/components/Header.tsx
+++ b/server/sonar-web/src/main/js/apps/permission-templates/components/Header.tsx
@@ -21,6 +21,7 @@ import * as React from 'react';
import * as PropTypes from 'prop-types';
import Form from './Form';
import { createPermissionTemplate } from '../../../api/permissions';
+import { Button } from '../../../components/ui/buttons';
import { translate } from '../../../helpers/l10n';
interface Props {
@@ -50,9 +51,7 @@ export default class Header extends React.PureComponent<Props, State> {
this.mounted = false;
}
- handleCreateClick = (event: React.SyntheticEvent<HTMLButtonElement>) => {
- event.preventDefault();
- event.currentTarget.blur();
+ handleCreateClick = () => {
this.setState({ createModal: true });
};
@@ -86,9 +85,7 @@ export default class Header extends React.PureComponent<Props, State> {
{!this.props.ready && <i className="spinner" />}
<div className="page-actions">
- <button onClick={this.handleCreateClick} type="button">
- {translate('create')}
- </button>
+ <Button onClick={this.handleCreateClick}>{translate('create')}</Button>
{this.state.createModal && (
<Form
diff --git a/server/sonar-web/src/main/js/apps/permissions/project/components/ApplyTemplate.tsx b/server/sonar-web/src/main/js/apps/permissions/project/components/ApplyTemplate.tsx
index e8550cef79a..94fe7d09868 100644
--- a/server/sonar-web/src/main/js/apps/permissions/project/components/ApplyTemplate.tsx
+++ b/server/sonar-web/src/main/js/apps/permissions/project/components/ApplyTemplate.tsx
@@ -23,6 +23,7 @@ import { PermissionTemplate } from '../../../../app/types';
import DeferredSpinner from '../../../../components/common/DeferredSpinner';
import SimpleModal from '../../../../components/controls/SimpleModal';
import Select from '../../../../components/controls/Select';
+import { SubmitButton, ResetButtonLink } from '../../../../components/ui/buttons';
import { translateWithParameters, translate } from '../../../../helpers/l10n';
interface Props {
@@ -139,13 +140,13 @@ export default class ApplyTemplate extends React.PureComponent<Props, State> {
<footer className="modal-foot">
<DeferredSpinner className="spacer-right" loading={submitting} />
{!this.state.done && (
- <button disabled={submitting || !this.state.permissionTemplate} type="submit">
+ <SubmitButton disabled={submitting || !this.state.permissionTemplate}>
{translate('apply')}
- </button>
+ </SubmitButton>
)}
- <button className="button-link" onClick={onCloseClick} type="reset">
+ <ResetButtonLink onClick={onCloseClick}>
{translate(this.state.done ? 'close' : 'cancel')}
- </button>
+ </ResetButtonLink>
</footer>
</form>
)}
diff --git a/server/sonar-web/src/main/js/apps/permissions/project/components/PageHeader.tsx b/server/sonar-web/src/main/js/apps/permissions/project/components/PageHeader.tsx
index bab1ba6490d..f9017efdefa 100644
--- a/server/sonar-web/src/main/js/apps/permissions/project/components/PageHeader.tsx
+++ b/server/sonar-web/src/main/js/apps/permissions/project/components/PageHeader.tsx
@@ -20,6 +20,7 @@
import * as React from 'react';
import ApplyTemplate from './ApplyTemplate';
import { Component } from '../../../../app/types';
+import { Button } from '../../../../components/ui/buttons';
import { translate } from '../../../../helpers/l10n';
interface Props {
@@ -44,9 +45,7 @@ export default class PageHeader extends React.PureComponent<Props, State> {
this.mounted = false;
}
- handleApplyTemplate = (event: React.SyntheticEvent<HTMLButtonElement>) => {
- event.preventDefault();
- event.currentTarget.blur();
+ handleApplyTemplate = () => {
this.setState({ applyTemplateModal: true });
};
@@ -79,9 +78,9 @@ export default class PageHeader extends React.PureComponent<Props, State> {
{canApplyPermissionTemplate && (
<div className="page-actions">
- <button className="js-apply-template" onClick={this.handleApplyTemplate} type="button">
+ <Button className="js-apply-template" onClick={this.handleApplyTemplate}>
{translate('projects_role.apply_template')}
- </button>
+ </Button>
{this.state.applyTemplateModal && (
<ApplyTemplate
diff --git a/server/sonar-web/src/main/js/apps/portfolio/components/Subscription.tsx b/server/sonar-web/src/main/js/apps/portfolio/components/Subscription.tsx
index 98282a76287..efd920612cd 100644
--- a/server/sonar-web/src/main/js/apps/portfolio/components/Subscription.tsx
+++ b/server/sonar-web/src/main/js/apps/portfolio/components/Subscription.tsx
@@ -20,6 +20,7 @@
import * as React from 'react';
import { ReportStatus, subscribe, unsubscribe } from '../../../api/report';
import { translate, translateWithParameters } from '../../../helpers/l10n';
+import { Button } from '../../../components/ui/buttons';
interface Props {
component: string;
@@ -66,18 +67,14 @@ export default class Subscription extends React.PureComponent<Props, State> {
}
};
- handleSubscribe = (e: React.SyntheticEvent<HTMLButtonElement>) => {
- e.preventDefault();
- e.currentTarget.blur();
+ handleSubscribe = () => {
this.setState({ loading: true });
subscribe(this.props.component)
.then(() => this.handleSubscription(true))
.catch(this.stopLoading);
};
- handleUnsubscribe = (e: React.SyntheticEvent<HTMLButtonElement>) => {
- e.preventDefault();
- e.currentTarget.blur();
+ handleUnsubscribe = () => {
this.setState({ loading: true });
unsubscribe(this.props.component)
.then(() => this.handleSubscription(false))
@@ -100,7 +97,7 @@ export default class Subscription extends React.PureComponent<Props, State> {
{translateWithParameters('report.subscribed', this.getEffectiveFrequencyText())}
</div>
</div>
- <button onClick={this.handleUnsubscribe}>{translate('report.unsubscribe')}</button>
+ <Button onClick={this.handleUnsubscribe}>{translate('report.unsubscribe')}</Button>
{this.renderLoading()}
</div>
);
@@ -110,9 +107,9 @@ export default class Subscription extends React.PureComponent<Props, State> {
<p className="spacer-bottom">
{translateWithParameters('report.unsubscribed', this.getEffectiveFrequencyText())}
</p>
- <button className="js-report-subscribe" onClick={this.handleSubscribe}>
+ <Button className="js-report-subscribe" onClick={this.handleSubscribe}>
{translate('report.subscribe')}
- </button>
+ </Button>
{this.renderLoading()}
</div>
);
diff --git a/server/sonar-web/src/main/js/apps/portfolio/components/__tests__/__snapshots__/Subscription-test.tsx.snap b/server/sonar-web/src/main/js/apps/portfolio/components/__tests__/__snapshots__/Subscription-test.tsx.snap
index 03ba0e5f118..488d122219e 100644
--- a/server/sonar-web/src/main/js/apps/portfolio/components/__tests__/__snapshots__/Subscription-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/portfolio/components/__tests__/__snapshots__/Subscription-test.tsx.snap
@@ -24,12 +24,12 @@ exports[`renders when not subscribed 1`] = `
>
report.unsubscribed.report.frequency.montly.effective
</p>
- <button
+ <Button
className="js-report-subscribe"
onClick={[Function]}
>
report.subscribe
- </button>
+ </Button>
</div>
</div>
`;
@@ -53,11 +53,11 @@ exports[`renders when subscribed 1`] = `
report.subscribed.report.frequency.montly.effective
</div>
</div>
- <button
+ <Button
onClick={[Function]}
>
report.unsubscribe
- </button>
+ </Button>
</div>
</div>
`;
diff --git a/server/sonar-web/src/main/js/apps/projectBranches/components/DeleteBranchModal.tsx b/server/sonar-web/src/main/js/apps/projectBranches/components/DeleteBranchModal.tsx
index 4760621d29c..127b3781189 100644
--- a/server/sonar-web/src/main/js/apps/projectBranches/components/DeleteBranchModal.tsx
+++ b/server/sonar-web/src/main/js/apps/projectBranches/components/DeleteBranchModal.tsx
@@ -21,6 +21,7 @@ import * as React from 'react';
import { deleteBranch } from '../../../api/branches';
import { Branch } from '../../../app/types';
import Modal from '../../../components/controls/Modal';
+import { SubmitButton, ResetButtonLink } from '../../../components/ui/buttons';
import { translate, translateWithParameters } from '../../../helpers/l10n';
interface Props {
@@ -64,11 +65,6 @@ export default class DeleteBranchModal extends React.PureComponent<Props, State>
);
};
- handleCancelClick = (event: React.SyntheticEvent<HTMLAnchorElement>) => {
- event.preventDefault();
- this.props.onClose();
- };
-
render() {
const { branch } = this.props;
const header = translate('branches.delete');
@@ -84,12 +80,10 @@ export default class DeleteBranchModal extends React.PureComponent<Props, State>
</div>
<footer className="modal-foot">
{this.state.loading && <i className="spinner spacer-right" />}
- <button className="button-red" disabled={this.state.loading} type="submit">
+ <SubmitButton className="button-red" disabled={this.state.loading}>
{translate('delete')}
- </button>
- <a href="#" onClick={this.handleCancelClick}>
- {translate('cancel')}
- </a>
+ </SubmitButton>
+ <ResetButtonLink onClick={this.props.onClose}>{translate('cancel')}</ResetButtonLink>
</footer>
</form>
</Modal>
diff --git a/server/sonar-web/src/main/js/apps/projectBranches/components/RenameBranchModal.tsx b/server/sonar-web/src/main/js/apps/projectBranches/components/RenameBranchModal.tsx
index 67a7656fe0a..bc78f0395cb 100644
--- a/server/sonar-web/src/main/js/apps/projectBranches/components/RenameBranchModal.tsx
+++ b/server/sonar-web/src/main/js/apps/projectBranches/components/RenameBranchModal.tsx
@@ -20,8 +20,9 @@
import * as React from 'react';
import { renameBranch } from '../../../api/branches';
import { Branch } from '../../../app/types';
-import { translate } from '../../../helpers/l10n';
import Modal from '../../../components/controls/Modal';
+import { SubmitButton, ResetButtonLink } from '../../../components/ui/buttons';
+import { translate } from '../../../helpers/l10n';
interface Props {
branch: Branch;
@@ -68,11 +69,6 @@ export default class RenameBranchModal extends React.PureComponent<Props, State>
);
};
- handleCancelClick = (event: React.SyntheticEvent<HTMLAnchorElement>) => {
- event.preventDefault();
- this.props.onClose();
- };
-
handleNameChange = (event: React.SyntheticEvent<HTMLInputElement>) => {
this.setState({ name: event.currentTarget.value });
};
@@ -110,12 +106,8 @@ export default class RenameBranchModal extends React.PureComponent<Props, State>
</div>
<footer className="modal-foot">
{this.state.loading && <i className="spinner spacer-right" />}
- <button disabled={submitDisabled} type="submit">
- {translate('rename')}
- </button>
- <a href="#" onClick={this.handleCancelClick}>
- {translate('cancel')}
- </a>
+ <SubmitButton disabled={submitDisabled}>{translate('rename')}</SubmitButton>
+ <ResetButtonLink onClick={this.props.onClose}>{translate('cancel')}</ResetButtonLink>
</footer>
</form>
</Modal>
diff --git a/server/sonar-web/src/main/js/apps/projectBranches/components/SettingForm.tsx b/server/sonar-web/src/main/js/apps/projectBranches/components/SettingForm.tsx
index e862b2b7f8c..6c3b737dd4c 100644
--- a/server/sonar-web/src/main/js/apps/projectBranches/components/SettingForm.tsx
+++ b/server/sonar-web/src/main/js/apps/projectBranches/components/SettingForm.tsx
@@ -19,6 +19,7 @@
*/
import * as React from 'react';
import { SettingValue, setSimpleSettingValue, resetSettingValue } from '../../../api/settings';
+import { Button, SubmitButton, ResetButtonLink } from '../../../components/ui/buttons';
import { translate, translateWithParameters } from '../../../helpers/l10n';
interface Props {
@@ -75,9 +76,7 @@ export default class SettingForm extends React.PureComponent<Props, State> {
this.setState({ value: event.currentTarget.value });
};
- handleResetClick = (event: React.SyntheticEvent<HTMLButtonElement>) => {
- event.preventDefault();
- event.currentTarget.blur();
+ handleResetClick = () => {
this.setState({ submitting: true });
resetSettingValue(this.props.setting.key, this.props.project, this.props.branch).then(
this.props.onChange,
@@ -89,11 +88,6 @@ export default class SettingForm extends React.PureComponent<Props, State> {
);
};
- handleCancelClick = (event: React.SyntheticEvent<HTMLAnchorElement>) => {
- event.preventDefault();
- this.props.onClose();
- };
-
render() {
const { setting } = this.props;
const submitDisabled = this.state.submitting || this.state.value === setting.value;
@@ -128,21 +122,17 @@ export default class SettingForm extends React.PureComponent<Props, State> {
<footer className="modal-foot">
{!setting.inherited &&
setting.parentValue && (
- <button
+ <Button
className="pull-left"
disabled={this.state.submitting}
onClick={this.handleResetClick}
type="reset">
{translate('reset_to_default')}
- </button>
+ </Button>
)}
{this.state.submitting && <i className="spinner spacer-right" />}
- <button disabled={submitDisabled} type="submit">
- {translate('save')}
- </button>
- <a href="#" onClick={this.handleCancelClick}>
- {translate('cancel')}
- </a>
+ <SubmitButton disabled={submitDisabled}>{translate('save')}</SubmitButton>
+ <ResetButtonLink onClick={this.props.onClose}>{translate('cancel')}</ResetButtonLink>
</footer>
</form>
);
diff --git a/server/sonar-web/src/main/js/apps/projectBranches/components/__tests__/DeleteBranchModal-test.tsx b/server/sonar-web/src/main/js/apps/projectBranches/components/__tests__/DeleteBranchModal-test.tsx
index d23beef1c6e..88fd8dffca7 100644
--- a/server/sonar-web/src/main/js/apps/projectBranches/components/__tests__/DeleteBranchModal-test.tsx
+++ b/server/sonar-web/src/main/js/apps/projectBranches/components/__tests__/DeleteBranchModal-test.tsx
@@ -55,7 +55,7 @@ it('cancels', () => {
const onClose = jest.fn();
const wrapper = shallowRender(jest.fn(), onClose);
- click(wrapper.find('a'));
+ click(wrapper.find('ResetButtonLink'));
return doAsync().then(() => {
expect(onClose).toBeCalled();
diff --git a/server/sonar-web/src/main/js/apps/projectBranches/components/__tests__/LongBranchesPattern-test.tsx b/server/sonar-web/src/main/js/apps/projectBranches/components/__tests__/LongBranchesPattern-test.tsx
index 4a9221d80e9..0e2a0bf65a7 100644
--- a/server/sonar-web/src/main/js/apps/projectBranches/components/__tests__/LongBranchesPattern-test.tsx
+++ b/server/sonar-web/src/main/js/apps/projectBranches/components/__tests__/LongBranchesPattern-test.tsx
@@ -21,6 +21,7 @@
import * as React from 'react';
import { shallow } from 'enzyme';
import LongBranchesPattern from '../LongBranchesPattern';
+import { click } from '../../../../helpers/testUtils';
jest.mock('../../../../api/settings', () => ({
getValues: jest.fn(() => Promise.resolve([]))
@@ -42,8 +43,7 @@ it('opens form', () => {
const wrapper = shallow(<LongBranchesPattern project="project" />);
wrapper.setState({ loading: false, setting: { value: 'release-.*' } });
- wrapper.find('EditButton').prop<Function>('onClick')();
- wrapper.update();
+ click(wrapper.find('EditButton'));
expect(wrapper.find('LongBranchesPatternForm').exists()).toBeTruthy();
wrapper.find('LongBranchesPatternForm').prop<Function>('onClose')();
diff --git a/server/sonar-web/src/main/js/apps/projectBranches/components/__tests__/RenameBranchModal-test.tsx b/server/sonar-web/src/main/js/apps/projectBranches/components/__tests__/RenameBranchModal-test.tsx
index 3d897c3a953..65bb3ca6f29 100644
--- a/server/sonar-web/src/main/js/apps/projectBranches/components/__tests__/RenameBranchModal-test.tsx
+++ b/server/sonar-web/src/main/js/apps/projectBranches/components/__tests__/RenameBranchModal-test.tsx
@@ -57,7 +57,7 @@ it('cancels', () => {
const onClose = jest.fn();
const wrapper = shallowRender(jest.fn(), onClose);
- click(wrapper.find('a'));
+ click(wrapper.find('ResetButtonLink'));
return doAsync().then(() => {
expect(onClose).toBeCalled();
diff --git a/server/sonar-web/src/main/js/apps/projectBranches/components/__tests__/SettingForm-test.tsx b/server/sonar-web/src/main/js/apps/projectBranches/components/__tests__/SettingForm-test.tsx
index ed442a4bdd8..6a107645fc0 100644
--- a/server/sonar-web/src/main/js/apps/projectBranches/components/__tests__/SettingForm-test.tsx
+++ b/server/sonar-web/src/main/js/apps/projectBranches/components/__tests__/SettingForm-test.tsx
@@ -75,7 +75,7 @@ it('resets value', async () => {
);
expect(wrapper).toMatchSnapshot();
- click(wrapper.find('button[type="reset"]'));
+ click(wrapper.find('Button'));
expect(resetSettingValue).toBeCalledWith('foo', 'project', undefined);
await new Promise(setImmediate);
diff --git a/server/sonar-web/src/main/js/apps/projectBranches/components/__tests__/__snapshots__/DeleteBranchModal-test.tsx.snap b/server/sonar-web/src/main/js/apps/projectBranches/components/__tests__/__snapshots__/DeleteBranchModal-test.tsx.snap
index 8571673e611..3864d0c38fd 100644
--- a/server/sonar-web/src/main/js/apps/projectBranches/components/__tests__/__snapshots__/DeleteBranchModal-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/projectBranches/components/__tests__/__snapshots__/DeleteBranchModal-test.tsx.snap
@@ -23,19 +23,17 @@ exports[`renders 1`] = `
<footer
className="modal-foot"
>
- <button
+ <SubmitButton
className="button-red"
disabled={false}
- type="submit"
>
delete
- </button>
- <a
- href="#"
- onClick={[Function]}
+ </SubmitButton>
+ <ResetButtonLink
+ onClick={[MockFunction]}
>
cancel
- </a>
+ </ResetButtonLink>
</footer>
</form>
</Modal>
@@ -67,19 +65,17 @@ exports[`renders 2`] = `
<i
className="spinner spacer-right"
/>
- <button
+ <SubmitButton
className="button-red"
disabled={true}
- type="submit"
>
delete
- </button>
- <a
- href="#"
- onClick={[Function]}
+ </SubmitButton>
+ <ResetButtonLink
+ onClick={[MockFunction]}
>
cancel
- </a>
+ </ResetButtonLink>
</footer>
</form>
</Modal>
diff --git a/server/sonar-web/src/main/js/apps/projectBranches/components/__tests__/__snapshots__/RenameBranchModal-test.tsx.snap b/server/sonar-web/src/main/js/apps/projectBranches/components/__tests__/__snapshots__/RenameBranchModal-test.tsx.snap
index 2960f04d2d9..77c4b64b7f1 100644
--- a/server/sonar-web/src/main/js/apps/projectBranches/components/__tests__/__snapshots__/RenameBranchModal-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/projectBranches/components/__tests__/__snapshots__/RenameBranchModal-test.tsx.snap
@@ -47,18 +47,16 @@ exports[`renders 1`] = `
<footer
className="modal-foot"
>
- <button
+ <SubmitButton
disabled={true}
- type="submit"
>
rename
- </button>
- <a
- href="#"
- onClick={[Function]}
+ </SubmitButton>
+ <ResetButtonLink
+ onClick={[MockFunction]}
>
cancel
- </a>
+ </ResetButtonLink>
</footer>
</form>
</Modal>
@@ -111,18 +109,16 @@ exports[`renders 2`] = `
<footer
className="modal-foot"
>
- <button
+ <SubmitButton
disabled={false}
- type="submit"
>
rename
- </button>
- <a
- href="#"
- onClick={[Function]}
+ </SubmitButton>
+ <ResetButtonLink
+ onClick={[MockFunction]}
>
cancel
- </a>
+ </ResetButtonLink>
</footer>
</form>
</Modal>
@@ -178,18 +174,16 @@ exports[`renders 3`] = `
<i
className="spinner spacer-right"
/>
- <button
+ <SubmitButton
disabled={true}
- type="submit"
>
rename
- </button>
- <a
- href="#"
- onClick={[Function]}
+ </SubmitButton>
+ <ResetButtonLink
+ onClick={[MockFunction]}
>
cancel
- </a>
+ </ResetButtonLink>
</footer>
</form>
</Modal>
diff --git a/server/sonar-web/src/main/js/apps/projectBranches/components/__tests__/__snapshots__/SettingForm-test.tsx.snap b/server/sonar-web/src/main/js/apps/projectBranches/components/__tests__/__snapshots__/SettingForm-test.tsx.snap
index bec3f234357..1c038c720ff 100644
--- a/server/sonar-web/src/main/js/apps/projectBranches/components/__tests__/__snapshots__/SettingForm-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/projectBranches/components/__tests__/__snapshots__/SettingForm-test.tsx.snap
@@ -36,18 +36,16 @@ exports[`changes value 1`] = `
<footer
className="modal-foot"
>
- <button
+ <SubmitButton
disabled={true}
- type="submit"
>
save
- </button>
- <a
- href="#"
- onClick={[Function]}
+ </SubmitButton>
+ <ResetButtonLink
+ onClick={[MockFunction]}
>
cancel
- </a>
+ </ResetButtonLink>
</footer>
</form>
`;
@@ -88,26 +86,24 @@ exports[`resets value 1`] = `
<footer
className="modal-foot"
>
- <button
+ <Button
className="pull-left"
disabled={false}
onClick={[Function]}
type="reset"
>
reset_to_default
- </button>
- <button
+ </Button>
+ <SubmitButton
disabled={true}
- type="submit"
>
save
- </button>
- <a
- href="#"
- onClick={[Function]}
+ </SubmitButton>
+ <ResetButtonLink
+ onClick={[MockFunction]}
>
cancel
- </a>
+ </ResetButtonLink>
</footer>
</form>
`;
diff --git a/server/sonar-web/src/main/js/apps/projects/components/ClearAll.tsx b/server/sonar-web/src/main/js/apps/projects/components/ClearAll.tsx
index 0e2772309d4..ddf2825d011 100644
--- a/server/sonar-web/src/main/js/apps/projects/components/ClearAll.tsx
+++ b/server/sonar-web/src/main/js/apps/projects/components/ClearAll.tsx
@@ -18,26 +18,19 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import * as React from 'react';
+import { Button } from '../../../components/ui/buttons';
import { translate } from '../../../helpers/l10n';
interface Props {
onClearAll: () => void;
}
-export default class ClearAll extends React.PureComponent<Props> {
- handleClick = (event: React.SyntheticEvent<HTMLButtonElement>) => {
- event.preventDefault();
- event.currentTarget.blur();
- this.props.onClearAll();
- };
-
- render() {
- return (
- <div className="projects-facets-reset">
- <button className="button-red" onClick={this.handleClick}>
- {translate('clear_all_filters')}
- </button>
- </div>
- );
- }
+export default function ClearAll({ onClearAll }: Props) {
+ return (
+ <div className="projects-facets-reset">
+ <Button className="button-red" onClick={onClearAll}>
+ {translate('clear_all_filters')}
+ </Button>
+ </div>
+ );
}
diff --git a/server/sonar-web/src/main/js/apps/projects/components/__tests__/ClearAll-test.tsx b/server/sonar-web/src/main/js/apps/projects/components/__tests__/ClearAll-test.tsx
index 6978b60dcda..8ff409b905a 100644
--- a/server/sonar-web/src/main/js/apps/projects/components/__tests__/ClearAll-test.tsx
+++ b/server/sonar-web/src/main/js/apps/projects/components/__tests__/ClearAll-test.tsx
@@ -29,6 +29,6 @@ it('renders', () => {
it('clears all', () => {
const onClearAll = jest.fn();
const wrapper = shallow(<ClearAll onClearAll={onClearAll} />);
- click(wrapper.find('button'));
+ click(wrapper.find('Button'));
expect(onClearAll).toBeCalled();
});
diff --git a/server/sonar-web/src/main/js/apps/projects/components/__tests__/ProjectsSortingSelect-test.tsx b/server/sonar-web/src/main/js/apps/projects/components/__tests__/ProjectsSortingSelect-test.tsx
index f38303cf520..19ca26cc2a6 100644
--- a/server/sonar-web/src/main/js/apps/projects/components/__tests__/ProjectsSortingSelect-test.tsx
+++ b/server/sonar-web/src/main/js/apps/projects/components/__tests__/ProjectsSortingSelect-test.tsx
@@ -20,6 +20,7 @@
import * as React from 'react';
import { shallow } from 'enzyme';
import ProjectsSortingSelect from '../ProjectsSortingSelect';
+import { click } from '../../../../helpers/testUtils';
it('should render correctly for overall view', () => {
expect(
@@ -84,6 +85,6 @@ it('reverses sorting', () => {
view="overall"
/>
);
- wrapper.find('ButtonIcon').prop<Function>('onClick')();
+ click(wrapper.find('ButtonIcon'));
expect(onChange).toBeCalledWith('size', false);
});
diff --git a/server/sonar-web/src/main/js/apps/projects/components/__tests__/__snapshots__/ClearAll-test.tsx.snap b/server/sonar-web/src/main/js/apps/projects/components/__tests__/__snapshots__/ClearAll-test.tsx.snap
index 5f61d820953..2340e0bbf03 100644
--- a/server/sonar-web/src/main/js/apps/projects/components/__tests__/__snapshots__/ClearAll-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/projects/components/__tests__/__snapshots__/ClearAll-test.tsx.snap
@@ -4,11 +4,11 @@ exports[`renders 1`] = `
<div
className="projects-facets-reset"
>
- <button
+ <Button
className="button-red"
- onClick={[Function]}
+ onClick={[MockFunction]}
>
clear_all_filters
- </button>
+ </Button>
</div>
`;
diff --git a/server/sonar-web/src/main/js/apps/projectsManagement/BulkApplyTemplateModal.tsx b/server/sonar-web/src/main/js/apps/projectsManagement/BulkApplyTemplateModal.tsx
index 69bb55161c7..663c5105577 100644
--- a/server/sonar-web/src/main/js/apps/projectsManagement/BulkApplyTemplateModal.tsx
+++ b/server/sonar-web/src/main/js/apps/projectsManagement/BulkApplyTemplateModal.tsx
@@ -24,6 +24,7 @@ import { translate, translateWithParameters } from '../../helpers/l10n';
import AlertWarnIcon from '../../components/icons-components/AlertWarnIcon';
import Modal from '../../components/controls/Modal';
import Select from '../../components/controls/Select';
+import { Button, ResetButtonLink } from '../../components/ui/buttons';
export interface Props {
analyzedBefore?: string;
@@ -78,11 +79,6 @@ export default class BulkApplyTemplateModal extends React.PureComponent<Props, S
);
}
- handleCancelClick = (event: React.SyntheticEvent<HTMLAnchorElement>) => {
- event.preventDefault();
- this.props.onClose();
- };
-
handleConfirmClick = () => {
const { permissionTemplate } = this.state;
if (permissionTemplate) {
@@ -180,13 +176,13 @@ export default class BulkApplyTemplateModal extends React.PureComponent<Props, S
{!loading &&
!done &&
permissionTemplates && (
- <button disabled={submitting} onClick={this.handleConfirmClick}>
+ <Button disabled={submitting} onClick={this.handleConfirmClick}>
{translate('apply')}
- </button>
+ </Button>
)}
- <a className="js-modal-close" href="#" onClick={this.handleCancelClick}>
+ <ResetButtonLink className="js-modal-close" onClick={this.props.onClose}>
{done ? translate('close') : translate('cancel')}
- </a>
+ </ResetButtonLink>
</footer>
</Modal>
);
diff --git a/server/sonar-web/src/main/js/apps/projectsManagement/ChangeVisibilityForm.tsx b/server/sonar-web/src/main/js/apps/projectsManagement/ChangeVisibilityForm.tsx
index 359fc4198c1..d603ab0a5d4 100644
--- a/server/sonar-web/src/main/js/apps/projectsManagement/ChangeVisibilityForm.tsx
+++ b/server/sonar-web/src/main/js/apps/projectsManagement/ChangeVisibilityForm.tsx
@@ -21,8 +21,9 @@ import * as React from 'react';
import * as classNames from 'classnames';
import { Organization, Visibility } from '../../app/types';
import UpgradeOrganizationBox from '../../components/common/UpgradeOrganizationBox';
-import { translate } from '../../helpers/l10n';
import Modal from '../../components/controls/Modal';
+import { Button, ResetButtonLink } from '../../components/ui/buttons';
+import { translate } from '../../helpers/l10n';
export interface Props {
onClose: () => void;
@@ -40,13 +41,7 @@ export default class ChangeVisibilityForm extends React.PureComponent<Props, Sta
this.state = { visibility: props.organization.projectVisibility as Visibility };
}
- handleCancelClick = (event: React.SyntheticEvent<HTMLAnchorElement>) => {
- event.preventDefault();
- this.props.onClose();
- };
-
- handleConfirmClick = (event: React.SyntheticEvent<HTMLButtonElement>) => {
- event.preventDefault();
+ handleConfirmClick = () => {
this.props.onConfirm(this.state.visibility);
this.props.onClose();
};
@@ -111,12 +106,12 @@ export default class ChangeVisibilityForm extends React.PureComponent<Props, Sta
</div>
<footer className="modal-foot">
- <button className="js-confirm" onClick={this.handleConfirmClick}>
+ <Button className="js-confirm" onClick={this.handleConfirmClick}>
{translate('organization.change_visibility_form.submit')}
- </button>
- <a className="js-modal-close" href="#" onClick={this.handleCancelClick}>
+ </Button>
+ <ResetButtonLink className="js-modal-close" onClick={this.props.onClose}>
{translate('cancel')}
- </a>
+ </ResetButtonLink>
</footer>
</Modal>
);
diff --git a/server/sonar-web/src/main/js/apps/projectsManagement/CreateProjectForm.tsx b/server/sonar-web/src/main/js/apps/projectsManagement/CreateProjectForm.tsx
index b43aadab9c7..5a39b28c5f8 100644
--- a/server/sonar-web/src/main/js/apps/projectsManagement/CreateProjectForm.tsx
+++ b/server/sonar-web/src/main/js/apps/projectsManagement/CreateProjectForm.tsx
@@ -20,13 +20,14 @@
import * as React from 'react';
import { Link } from 'react-router';
import { FormattedMessage } from 'react-intl';
+import { createProject } from '../../api/components';
import { Organization } from '../../app/types';
import UpgradeOrganizationBox from '../../components/common/UpgradeOrganizationBox';
import VisibilitySelector from '../../components/common/VisibilitySelector';
-import { createProject } from '../../api/components';
+import Modal from '../../components/controls/Modal';
+import { SubmitButton, ResetButtonLink } from '../../components/ui/buttons';
import { translate } from '../../helpers/l10n';
import { getProjectUrl } from '../../helpers/urls';
-import Modal from '../../components/controls/Modal';
interface Props {
onClose: () => void;
@@ -79,11 +80,6 @@ export default class CreateProjectForm extends React.PureComponent<Props, State>
this.mounted = false;
}
- handleCancelClick = (event: React.SyntheticEvent<HTMLAnchorElement>) => {
- event.preventDefault();
- this.props.onClose();
- };
-
handleAdvancedClick = (event: React.SyntheticEvent<HTMLAnchorElement>) => {
event.preventDefault();
event.currentTarget.blur();
@@ -155,13 +151,12 @@ export default class CreateProjectForm extends React.PureComponent<Props, State>
</div>
<footer className="modal-foot">
- <a
- href="#"
+ <ResetButtonLink
id="create-project-close"
- onClick={this.handleCancelClick}
- ref={node => (this.closeButton = node)}>
+ innerRef={node => (this.closeButton = node)}
+ onClick={this.props.onClose}>
{translate('close')}
- </a>
+ </ResetButtonLink>
</footer>
</div>
) : (
@@ -243,12 +238,12 @@ export default class CreateProjectForm extends React.PureComponent<Props, State>
<footer className="modal-foot">
{this.state.loading && <i className="spinner spacer-right" />}
- <button disabled={this.state.loading} id="create-project-submit" type="submit">
+ <SubmitButton disabled={this.state.loading} id="create-project-submit">
{translate('create')}
- </button>
- <a href="#" id="create-project-cancel" onClick={this.handleCancelClick}>
+ </SubmitButton>
+ <ResetButtonLink id="create-project-cancel" onClick={this.props.onClose}>
{translate('cancel')}
- </a>
+ </ResetButtonLink>
</footer>
</form>
)}
diff --git a/server/sonar-web/src/main/js/apps/projectsManagement/DeleteModal.tsx b/server/sonar-web/src/main/js/apps/projectsManagement/DeleteModal.tsx
index a9b45bb2a52..9300d2bc96b 100644
--- a/server/sonar-web/src/main/js/apps/projectsManagement/DeleteModal.tsx
+++ b/server/sonar-web/src/main/js/apps/projectsManagement/DeleteModal.tsx
@@ -19,9 +19,10 @@
*/
import * as React from 'react';
import { bulkDeleteProjects } from '../../api/components';
-import { translate, translateWithParameters } from '../../helpers/l10n';
-import AlertWarnIcon from '../../components/icons-components/AlertWarnIcon';
import Modal from '../../components/controls/Modal';
+import AlertWarnIcon from '../../components/icons-components/AlertWarnIcon';
+import { Button, ResetButtonLink } from '../../components/ui/buttons';
+import { translate, translateWithParameters } from '../../helpers/l10n';
export interface Props {
analyzedBefore?: string;
@@ -51,11 +52,6 @@ export default class DeleteModal extends React.PureComponent<Props, State> {
this.mounted = false;
}
- handleCancelClick = (event: React.SyntheticEvent<HTMLAnchorElement>) => {
- event.preventDefault();
- this.props.onClose();
- };
-
handleConfirmClick = () => {
this.setState({ loading: true });
const parameters = this.props.selection.length
@@ -112,15 +108,15 @@ export default class DeleteModal extends React.PureComponent<Props, State> {
<footer className="modal-foot">
{this.state.loading && <i className="spinner spacer-right" />}
- <button
+ <Button
className="button-red"
disabled={this.state.loading}
onClick={this.handleConfirmClick}>
{translate('delete')}
- </button>
- <a className="js-modal-close" href="#" onClick={this.handleCancelClick}>
+ </Button>
+ <ResetButtonLink className="js-modal-close" onClick={this.props.onClose}>
{translate('cancel')}
- </a>
+ </ResetButtonLink>
</footer>
</Modal>
);
diff --git a/server/sonar-web/src/main/js/apps/projectsManagement/Header.tsx b/server/sonar-web/src/main/js/apps/projectsManagement/Header.tsx
index 3b2b14d39b1..90015c3cf5d 100644
--- a/server/sonar-web/src/main/js/apps/projectsManagement/Header.tsx
+++ b/server/sonar-web/src/main/js/apps/projectsManagement/Header.tsx
@@ -20,8 +20,8 @@
import * as React from 'react';
import ChangeVisibilityForm from './ChangeVisibilityForm';
import { Organization, Visibility } from '../../app/types';
+import { EditButton, Button } from '../../components/ui/buttons';
import { translate } from '../../helpers/l10n';
-import { EditButton } from '../../components/ui/buttons';
export interface Props {
hasProvisionPermission?: boolean;
@@ -37,11 +37,6 @@ interface State {
export default class Header extends React.PureComponent<Props, State> {
state: State = { visibilityForm: false };
- handleCreateProjectClick = (event: React.SyntheticEvent<HTMLButtonElement>) => {
- event.preventDefault();
- this.props.onProjectCreate();
- };
-
handleChangeVisibilityClick = () => {
this.setState({ visibilityForm: true });
};
@@ -69,9 +64,9 @@ export default class Header extends React.PureComponent<Props, State> {
/>
</span>
{this.props.hasProvisionPermission && (
- <button id="create-project" onClick={this.handleCreateProjectClick}>
+ <Button id="create-project" onClick={this.props.onProjectCreate}>
{translate('qualifiers.create.TRK')}
- </button>
+ </Button>
)}
</div>
diff --git a/server/sonar-web/src/main/js/apps/projectsManagement/RestoreAccessModal.tsx b/server/sonar-web/src/main/js/apps/projectsManagement/RestoreAccessModal.tsx
index d936fafa1e9..57183554451 100644
--- a/server/sonar-web/src/main/js/apps/projectsManagement/RestoreAccessModal.tsx
+++ b/server/sonar-web/src/main/js/apps/projectsManagement/RestoreAccessModal.tsx
@@ -22,6 +22,7 @@ import { FormattedMessage } from 'react-intl';
import { Project } from './utils';
import { grantPermissionToUser } from '../../api/permissions';
import Modal from '../../components/controls/Modal';
+import { SubmitButton, ResetButtonLink } from '../../components/ui/buttons';
import { translate } from '../../helpers/l10n';
interface Props {
@@ -47,11 +48,6 @@ export default class RestoreAccessModal extends React.PureComponent<Props, State
this.mounted = false;
}
- handleCancelClick = (event: React.SyntheticEvent<HTMLAnchorElement>) => {
- event.preventDefault();
- this.props.onClose();
- };
-
handleFormSubmit = (event: React.SyntheticEvent<HTMLFormElement>) => {
event.preventDefault();
this.setState({ loading: true });
@@ -96,12 +92,8 @@ export default class RestoreAccessModal extends React.PureComponent<Props, State
<footer className="modal-foot">
{this.state.loading && <i className="spinner spacer-right" />}
- <button disabled={this.state.loading} type="submit">
- {translate('restore')}
- </button>
- <a className="js-modal-close" href="#" onClick={this.handleCancelClick}>
- {translate('cancel')}
- </a>
+ <SubmitButton disabled={this.state.loading}>{translate('restore')}</SubmitButton>
+ <ResetButtonLink onClick={this.props.onClose}>{translate('cancel')}</ResetButtonLink>
</footer>
</form>
</Modal>
diff --git a/server/sonar-web/src/main/js/apps/projectsManagement/Search.tsx b/server/sonar-web/src/main/js/apps/projectsManagement/Search.tsx
index 6e3fa3d02ac..c2df72d6bef 100644
--- a/server/sonar-web/src/main/js/apps/projectsManagement/Search.tsx
+++ b/server/sonar-web/src/main/js/apps/projectsManagement/Search.tsx
@@ -30,6 +30,7 @@ import Tooltip from '../../components/controls/Tooltip';
import DateInput from '../../components/controls/DateInput';
import Select from '../../components/controls/Select';
import SearchBox from '../../components/controls/SearchBox';
+import { Button } from '../../components/ui/buttons';
export interface Props {
analyzedBefore?: string;
@@ -76,9 +77,7 @@ export default class Search extends React.PureComponent<Props, State> {
}
};
- handleDeleteClick = (event: React.SyntheticEvent<HTMLButtonElement>) => {
- event.preventDefault();
- event.currentTarget.blur();
+ handleDeleteClick = () => {
this.setState({ deleteModal: true });
};
@@ -91,9 +90,7 @@ export default class Search extends React.PureComponent<Props, State> {
this.props.onDeleteProjects();
};
- handleBulkApplyTemplateClick = (event: React.SyntheticEvent<HTMLButtonElement>) => {
- event.preventDefault();
- event.currentTarget.blur();
+ handleBulkApplyTemplateClick = () => {
this.setState({ bulkApplyTemplateModal: true });
};
@@ -115,8 +112,8 @@ export default class Search extends React.PureComponent<Props, State> {
<Checkbox
checked={checked}
id="projects-selection"
- thirdState={thirdState}
onCheck={this.onCheck}
+ thirdState={thirdState}
/>
);
};
@@ -139,13 +136,13 @@ export default class Search extends React.PureComponent<Props, State> {
className="input-medium"
clearable={false}
disabled={!this.props.ready}
+ name="projects-qualifier"
+ onChange={this.handleQualifierChange}
optionRenderer={this.renderQualifierOption}
options={this.getQualifierOptions()}
+ searchable={false}
value={this.props.qualifiers}
valueRenderer={this.renderQualifierOption}
- name="projects-qualifier"
- onChange={this.handleQualifierChange}
- searchable={false}
/>
</td>
);
@@ -155,8 +152,8 @@ export default class Search extends React.PureComponent<Props, State> {
this.props.qualifiers === 'TRK' ? (
<td className="thin nowrap text-middle">
<Checkbox
- className="link-checkbox-control"
checked={this.props.provisioned}
+ className="link-checkbox-control"
id="projects-provisioned"
onCheck={this.props.onProvisionedChanged}>
<span className="little-spacer-left">
@@ -204,19 +201,19 @@ export default class Search extends React.PureComponent<Props, State> {
/>
</td>
<td className="thin nowrap text-middle">
- <button
+ <Button
className="js-bulk-apply-permission-template"
disabled={this.props.total === 0}
onClick={this.handleBulkApplyTemplateClick}>
{translate('permission_templates.bulk_apply_permission_template')}
- </button>
+ </Button>
{this.props.qualifiers === 'TRK' && (
- <button
+ <Button
className="js-delete spacer-left button-red"
disabled={this.props.total === 0}
onClick={this.handleDeleteClick}>
{translate('delete')}
- </button>
+ </Button>
)}
</td>
</tr>
diff --git a/server/sonar-web/src/main/js/apps/projectsManagement/__tests__/BulkApplyTemplateModal-test.tsx b/server/sonar-web/src/main/js/apps/projectsManagement/__tests__/BulkApplyTemplateModal-test.tsx
index 09c56289581..2ce76067896 100644
--- a/server/sonar-web/src/main/js/apps/projectsManagement/__tests__/BulkApplyTemplateModal-test.tsx
+++ b/server/sonar-web/src/main/js/apps/projectsManagement/__tests__/BulkApplyTemplateModal-test.tsx
@@ -56,7 +56,7 @@ it('bulk applies template to all results', async () => {
});
expect(wrapper).toMatchSnapshot();
- click(wrapper.find('button'));
+ click(wrapper.find('Button'));
expect(bulkApplyTemplate).toBeCalledWith({
analyzedBefore: '2017-04-08T00:00:00.000Z',
onProvisionedOnly: true,
@@ -83,7 +83,7 @@ it('bulk applies template to selected results', async () => {
});
expect(wrapper).toMatchSnapshot();
- click(wrapper.find('button'));
+ click(wrapper.find('Button'));
expect(wrapper).toMatchSnapshot();
await new Promise(setImmediate);
expect(bulkApplyTemplate).toBeCalledWith({
diff --git a/server/sonar-web/src/main/js/apps/projectsManagement/__tests__/DeleteModal-test.tsx b/server/sonar-web/src/main/js/apps/projectsManagement/__tests__/DeleteModal-test.tsx
index 2aaa50a288f..853593d2058 100644
--- a/server/sonar-web/src/main/js/apps/projectsManagement/__tests__/DeleteModal-test.tsx
+++ b/server/sonar-web/src/main/js/apps/projectsManagement/__tests__/DeleteModal-test.tsx
@@ -39,7 +39,7 @@ it('deletes all projects', async () => {
(wrapper.instance() as DeleteModal).mounted = true;
expect(wrapper).toMatchSnapshot();
- click(wrapper.find('button'));
+ click(wrapper.find('Button'));
expect(wrapper).toMatchSnapshot();
expect(bulkDeleteProjects).toBeCalledWith({
analyzedBefore: '2017-04-08T00:00:00.000Z',
@@ -59,7 +59,7 @@ it('deletes selected projects', async () => {
(wrapper.instance() as DeleteModal).mounted = true;
expect(wrapper).toMatchSnapshot();
- click(wrapper.find('button'));
+ click(wrapper.find('Button'));
expect(wrapper).toMatchSnapshot();
expect(bulkDeleteProjects).toBeCalledWith({ organization: 'org', projects: 'proj1,proj2' });
diff --git a/server/sonar-web/src/main/js/apps/projectsManagement/__tests__/__snapshots__/BulkApplyTemplateModal-test.tsx.snap b/server/sonar-web/src/main/js/apps/projectsManagement/__tests__/__snapshots__/BulkApplyTemplateModal-test.tsx.snap
index fc6070810f9..2b7b17690f2 100644
--- a/server/sonar-web/src/main/js/apps/projectsManagement/__tests__/__snapshots__/BulkApplyTemplateModal-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/projectsManagement/__tests__/__snapshots__/BulkApplyTemplateModal-test.tsx.snap
@@ -22,13 +22,12 @@ exports[`bulk applies template to all results 1`] = `
<footer
className="modal-foot"
>
- <a
+ <ResetButtonLink
className="js-modal-close"
- href="#"
- onClick={[Function]}
+ onClick={[MockFunction]}
>
cancel
- </a>
+ </ResetButtonLink>
</footer>
</Modal>
`;
@@ -91,19 +90,18 @@ exports[`bulk applies template to all results 2`] = `
<footer
className="modal-foot"
>
- <button
+ <Button
disabled={false}
onClick={[Function]}
>
apply
- </button>
- <a
+ </Button>
+ <ResetButtonLink
className="js-modal-close"
- href="#"
- onClick={[Function]}
+ onClick={[MockFunction]}
>
cancel
- </a>
+ </ResetButtonLink>
</footer>
</Modal>
`;
@@ -169,19 +167,18 @@ exports[`bulk applies template to all results 3`] = `
<i
className="spinner spacer-right"
/>
- <button
+ <Button
disabled={true}
onClick={[Function]}
>
apply
- </button>
- <a
+ </Button>
+ <ResetButtonLink
className="js-modal-close"
- href="#"
- onClick={[Function]}
+ onClick={[MockFunction]}
>
cancel
- </a>
+ </ResetButtonLink>
</footer>
</Modal>
`;
@@ -210,13 +207,12 @@ exports[`bulk applies template to all results 4`] = `
<footer
className="modal-foot"
>
- <a
+ <ResetButtonLink
className="js-modal-close"
- href="#"
- onClick={[Function]}
+ onClick={[MockFunction]}
>
close
- </a>
+ </ResetButtonLink>
</footer>
</Modal>
`;
@@ -243,13 +239,12 @@ exports[`bulk applies template to selected results 1`] = `
<footer
className="modal-foot"
>
- <a
+ <ResetButtonLink
className="js-modal-close"
- href="#"
- onClick={[Function]}
+ onClick={[MockFunction]}
>
cancel
- </a>
+ </ResetButtonLink>
</footer>
</Modal>
`;
@@ -312,19 +307,18 @@ exports[`bulk applies template to selected results 2`] = `
<footer
className="modal-foot"
>
- <button
+ <Button
disabled={false}
onClick={[Function]}
>
apply
- </button>
- <a
+ </Button>
+ <ResetButtonLink
className="js-modal-close"
- href="#"
- onClick={[Function]}
+ onClick={[MockFunction]}
>
cancel
- </a>
+ </ResetButtonLink>
</footer>
</Modal>
`;
@@ -390,19 +384,18 @@ exports[`bulk applies template to selected results 3`] = `
<i
className="spinner spacer-right"
/>
- <button
+ <Button
disabled={true}
onClick={[Function]}
>
apply
- </button>
- <a
+ </Button>
+ <ResetButtonLink
className="js-modal-close"
- href="#"
- onClick={[Function]}
+ onClick={[MockFunction]}
>
cancel
- </a>
+ </ResetButtonLink>
</footer>
</Modal>
`;
@@ -431,13 +424,12 @@ exports[`bulk applies template to selected results 4`] = `
<footer
className="modal-foot"
>
- <a
+ <ResetButtonLink
className="js-modal-close"
- href="#"
- onClick={[Function]}
+ onClick={[MockFunction]}
>
close
- </a>
+ </ResetButtonLink>
</footer>
</Modal>
`;
diff --git a/server/sonar-web/src/main/js/apps/projectsManagement/__tests__/__snapshots__/ChangeVisibilityForm-test.tsx.snap b/server/sonar-web/src/main/js/apps/projectsManagement/__tests__/__snapshots__/ChangeVisibilityForm-test.tsx.snap
index c2471bfc944..0375c6c07e8 100644
--- a/server/sonar-web/src/main/js/apps/projectsManagement/__tests__/__snapshots__/ChangeVisibilityForm-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/projectsManagement/__tests__/__snapshots__/ChangeVisibilityForm-test.tsx.snap
@@ -80,19 +80,18 @@ exports[`changes visibility 1`] = `
<footer
className="modal-foot"
>
- <button
+ <Button
className="js-confirm"
onClick={[Function]}
>
organization.change_visibility_form.submit
- </button>
- <a
+ </Button>
+ <ResetButtonLink
className="js-modal-close"
- href="#"
- onClick={[Function]}
+ onClick={[MockFunction]}
>
cancel
- </a>
+ </ResetButtonLink>
</footer>
</Modal>
`;
@@ -177,19 +176,18 @@ exports[`changes visibility 2`] = `
<footer
className="modal-foot"
>
- <button
+ <Button
className="js-confirm"
onClick={[Function]}
>
organization.change_visibility_form.submit
- </button>
- <a
+ </Button>
+ <ResetButtonLink
className="js-modal-close"
- href="#"
- onClick={[Function]}
+ onClick={[MockFunction]}
>
cancel
- </a>
+ </ResetButtonLink>
</footer>
</Modal>
`;
@@ -269,19 +267,18 @@ exports[`renders disabled 1`] = `
<footer
className="modal-foot"
>
- <button
+ <Button
className="js-confirm"
onClick={[Function]}
>
organization.change_visibility_form.submit
- </button>
- <a
+ </Button>
+ <ResetButtonLink
className="js-modal-close"
- href="#"
- onClick={[Function]}
+ onClick={[MockFunction]}
>
cancel
- </a>
+ </ResetButtonLink>
</footer>
</Modal>
`;
diff --git a/server/sonar-web/src/main/js/apps/projectsManagement/__tests__/__snapshots__/CreateProjectForm-test.tsx.snap b/server/sonar-web/src/main/js/apps/projectsManagement/__tests__/__snapshots__/CreateProjectForm-test.tsx.snap
index 71af5dfa82d..deec1e2e7fd 100644
--- a/server/sonar-web/src/main/js/apps/projectsManagement/__tests__/__snapshots__/CreateProjectForm-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/projectsManagement/__tests__/__snapshots__/CreateProjectForm-test.tsx.snap
@@ -100,20 +100,18 @@ exports[`creates project 1`] = `
<footer
className="modal-foot"
>
- <button
+ <SubmitButton
disabled={false}
id="create-project-submit"
- type="submit"
>
create
- </button>
- <a
- href="#"
+ </SubmitButton>
+ <ResetButtonLink
id="create-project-cancel"
- onClick={[Function]}
+ onClick={[MockFunction]}
>
cancel
- </a>
+ </ResetButtonLink>
</footer>
</form>
</Modal>
@@ -219,20 +217,18 @@ exports[`creates project 2`] = `
<footer
className="modal-foot"
>
- <button
+ <SubmitButton
disabled={false}
id="create-project-submit"
- type="submit"
>
create
- </button>
- <a
- href="#"
+ </SubmitButton>
+ <ResetButtonLink
id="create-project-cancel"
- onClick={[Function]}
+ onClick={[MockFunction]}
>
cancel
- </a>
+ </ResetButtonLink>
</footer>
</form>
</Modal>
@@ -341,20 +337,18 @@ exports[`creates project 3`] = `
<i
className="spinner spacer-right"
/>
- <button
+ <SubmitButton
disabled={true}
id="create-project-submit"
- type="submit"
>
create
- </button>
- <a
- href="#"
+ </SubmitButton>
+ <ResetButtonLink
id="create-project-cancel"
- onClick={[Function]}
+ onClick={[MockFunction]}
>
cancel
- </a>
+ </ResetButtonLink>
</footer>
</form>
</Modal>
@@ -407,13 +401,13 @@ exports[`creates project 4`] = `
<footer
className="modal-foot"
>
- <a
- href="#"
+ <ResetButtonLink
id="create-project-close"
- onClick={[Function]}
+ innerRef={[Function]}
+ onClick={[MockFunction]}
>
close
- </a>
+ </ResetButtonLink>
</footer>
</div>
</Modal>
@@ -519,20 +513,18 @@ exports[`shows more 1`] = `
<footer
className="modal-foot"
>
- <button
+ <SubmitButton
disabled={false}
id="create-project-submit"
- type="submit"
>
create
- </button>
- <a
- href="#"
+ </SubmitButton>
+ <ResetButtonLink
id="create-project-cancel"
- onClick={[Function]}
+ onClick={[MockFunction]}
>
cancel
- </a>
+ </ResetButtonLink>
</footer>
</form>
</Modal>
@@ -645,20 +637,18 @@ exports[`shows more 2`] = `
<footer
className="modal-foot"
>
- <button
+ <SubmitButton
disabled={false}
id="create-project-submit"
- type="submit"
>
create
- </button>
- <a
- href="#"
+ </SubmitButton>
+ <ResetButtonLink
id="create-project-cancel"
- onClick={[Function]}
+ onClick={[MockFunction]}
>
cancel
- </a>
+ </ResetButtonLink>
</footer>
</form>
</Modal>
diff --git a/server/sonar-web/src/main/js/apps/projectsManagement/__tests__/__snapshots__/DeleteModal-test.tsx.snap b/server/sonar-web/src/main/js/apps/projectsManagement/__tests__/__snapshots__/DeleteModal-test.tsx.snap
index 77ea7ac64fc..3fed0f28acd 100644
--- a/server/sonar-web/src/main/js/apps/projectsManagement/__tests__/__snapshots__/DeleteModal-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/projectsManagement/__tests__/__snapshots__/DeleteModal-test.tsx.snap
@@ -28,20 +28,19 @@ exports[`deletes all projects 1`] = `
<footer
className="modal-foot"
>
- <button
+ <Button
className="button-red"
disabled={false}
onClick={[Function]}
>
delete
- </button>
- <a
+ </Button>
+ <ResetButtonLink
className="js-modal-close"
- href="#"
- onClick={[Function]}
+ onClick={[MockFunction]}
>
cancel
- </a>
+ </ResetButtonLink>
</footer>
</Modal>
`;
@@ -77,20 +76,19 @@ exports[`deletes all projects 2`] = `
<i
className="spinner spacer-right"
/>
- <button
+ <Button
className="button-red"
disabled={true}
onClick={[Function]}
>
delete
- </button>
- <a
+ </Button>
+ <ResetButtonLink
className="js-modal-close"
- href="#"
- onClick={[Function]}
+ onClick={[MockFunction]}
>
cancel
- </a>
+ </ResetButtonLink>
</footer>
</Modal>
`;
@@ -123,20 +121,19 @@ exports[`deletes selected projects 1`] = `
<footer
className="modal-foot"
>
- <button
+ <Button
className="button-red"
disabled={false}
onClick={[Function]}
>
delete
- </button>
- <a
+ </Button>
+ <ResetButtonLink
className="js-modal-close"
- href="#"
- onClick={[Function]}
+ onClick={[MockFunction]}
>
cancel
- </a>
+ </ResetButtonLink>
</footer>
</Modal>
`;
@@ -172,20 +169,19 @@ exports[`deletes selected projects 2`] = `
<i
className="spinner spacer-right"
/>
- <button
+ <Button
className="button-red"
disabled={true}
onClick={[Function]}
>
delete
- </button>
- <a
+ </Button>
+ <ResetButtonLink
className="js-modal-close"
- href="#"
- onClick={[Function]}
+ onClick={[MockFunction]}
>
cancel
- </a>
+ </ResetButtonLink>
</footer>
</Modal>
`;
diff --git a/server/sonar-web/src/main/js/apps/projectsManagement/__tests__/__snapshots__/Header-test.tsx.snap b/server/sonar-web/src/main/js/apps/projectsManagement/__tests__/__snapshots__/Header-test.tsx.snap
index aefc34315dd..456011bf7c6 100644
--- a/server/sonar-web/src/main/js/apps/projectsManagement/__tests__/__snapshots__/Header-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/projectsManagement/__tests__/__snapshots__/Header-test.tsx.snap
@@ -43,12 +43,12 @@ exports[`renders 1`] = `
onClick={[Function]}
/>
</span>
- <button
+ <Button
id="create-project"
- onClick={[Function]}
+ onClick={[MockFunction]}
>
qualifiers.create.TRK
- </button>
+ </Button>
</div>
<p
className="page-description"
diff --git a/server/sonar-web/src/main/js/apps/projectsManagement/__tests__/__snapshots__/Search-test.tsx.snap b/server/sonar-web/src/main/js/apps/projectsManagement/__tests__/__snapshots__/Search-test.tsx.snap
index 15ccbea3e9b..31530ef6a9d 100644
--- a/server/sonar-web/src/main/js/apps/projectsManagement/__tests__/__snapshots__/Search-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/projectsManagement/__tests__/__snapshots__/Search-test.tsx.snap
@@ -130,20 +130,20 @@ exports[`render qualifiers filter 1`] = `
<td
className="thin nowrap text-middle"
>
- <button
+ <Button
className="js-bulk-apply-permission-template"
disabled={false}
onClick={[Function]}
>
permission_templates.bulk_apply_permission_template
- </button>
- <button
+ </Button>
+ <Button
className="js-delete spacer-left button-red"
disabled={false}
onClick={[Function]}
>
delete
- </button>
+ </Button>
</td>
</tr>
</tbody>
@@ -220,20 +220,20 @@ exports[`renders 1`] = `
<td
className="thin nowrap text-middle"
>
- <button
+ <Button
className="js-bulk-apply-permission-template"
disabled={false}
onClick={[Function]}
>
permission_templates.bulk_apply_permission_template
- </button>
- <button
+ </Button>
+ <Button
className="js-delete spacer-left button-red"
disabled={false}
onClick={[Function]}
>
delete
- </button>
+ </Button>
</td>
</tr>
</tbody>
diff --git a/server/sonar-web/src/main/js/apps/quality-gates/components/Condition.tsx b/server/sonar-web/src/main/js/apps/quality-gates/components/Condition.tsx
index c5e3c2be471..2fd57fb40b8 100644
--- a/server/sonar-web/src/main/js/apps/quality-gates/components/Condition.tsx
+++ b/server/sonar-web/src/main/js/apps/quality-gates/components/Condition.tsx
@@ -20,8 +20,6 @@
import * as React from 'react';
import DeleteConditionForm from './DeleteConditionForm';
import ThresholdInput from './ThresholdInput';
-import Checkbox from '../../../components/controls/Checkbox';
-import Select from '../../../components/controls/Select';
import {
Condition as ICondition,
ConditionBase,
@@ -30,6 +28,9 @@ import {
updateCondition
} from '../../../api/quality-gates';
import { Metric } from '../../../app/types';
+import Checkbox from '../../../components/controls/Checkbox';
+import Select from '../../../components/controls/Select';
+import { Button, ResetButtonLink } from '../../../components/ui/buttons';
import { translate, getLocalizedMetricName } from '../../../helpers/l10n';
import { formatMeasure } from '../../../helpers/measures';
@@ -133,14 +134,17 @@ export default class Condition extends React.PureComponent<Props, State> {
this.props.onResetError();
};
- handleCancelClick = (e: React.SyntheticEvent<HTMLAnchorElement>) => {
- e.preventDefault();
- e.stopPropagation();
+ handleCancelClick = () => {
this.props.onDeleteCondition(this.props.condition);
};
- openDeleteConditionForm = () => this.setState({ openDeleteCondition: true });
- closeDeleteConditionForm = () => this.setState({ openDeleteCondition: false });
+ openDeleteConditionForm = () => {
+ this.setState({ openDeleteCondition: true });
+ };
+
+ closeDeleteConditionForm = () => {
+ this.setState({ openDeleteCondition: false });
+ };
renderPeriodValue() {
const { condition, metric } = this.props;
@@ -228,10 +232,10 @@ export default class Condition extends React.PureComponent<Props, State> {
<td className="thin text-middle nowrap">
{edit ? (
<ThresholdInput
- name="warning"
- value={this.state.warning}
metric={metric}
+ name="warning"
onChange={this.handleWarningChange}
+ value={this.state.warning}
/>
) : (
formatMeasure(condition.warning, metric.type)
@@ -241,10 +245,10 @@ export default class Condition extends React.PureComponent<Props, State> {
<td className="thin text-middle nowrap">
{edit ? (
<ThresholdInput
- name="error"
- value={this.state.error}
metric={metric}
+ name="error"
onChange={this.handleErrorChange}
+ value={this.state.error}
/>
) : (
formatMeasure(condition.error, metric.type)
@@ -255,17 +259,17 @@ export default class Condition extends React.PureComponent<Props, State> {
<td className="thin text-middle nowrap">
{condition.id ? (
<div>
- <button
+ <Button
className="update-condition"
disabled={!this.state.changed}
onClick={this.handleUpdateClick}>
{translate('update_verb')}
- </button>
- <button
+ </Button>
+ <Button
className="button-red delete-condition little-spacer-left"
onClick={this.openDeleteConditionForm}>
{translate('delete')}
- </button>
+ </Button>
{this.state.openDeleteCondition && (
<DeleteConditionForm
condition={condition}
@@ -278,15 +282,14 @@ export default class Condition extends React.PureComponent<Props, State> {
</div>
) : (
<div>
- <button className="add-condition" onClick={this.handleSaveClick}>
+ <Button className="add-condition" onClick={this.handleSaveClick}>
{translate('add_verb')}
- </button>
- <a
+ </Button>
+ <ResetButtonLink
className="cancel-add-condition spacer-left"
- href="#"
onClick={this.handleCancelClick}>
{translate('cancel')}
- </a>
+ </ResetButtonLink>
</div>
)}
</td>
diff --git a/server/sonar-web/src/main/js/apps/quality-gates/components/CopyQualityGateForm.tsx b/server/sonar-web/src/main/js/apps/quality-gates/components/CopyQualityGateForm.tsx
index 4c16c04184c..2c0609e5f66 100644
--- a/server/sonar-web/src/main/js/apps/quality-gates/components/CopyQualityGateForm.tsx
+++ b/server/sonar-web/src/main/js/apps/quality-gates/components/CopyQualityGateForm.tsx
@@ -19,10 +19,11 @@
*/
import * as React from 'react';
import * as PropTypes from 'prop-types';
-import Modal from '../../../components/controls/Modal';
import { copyQualityGate, QualityGate } from '../../../api/quality-gates';
-import { getQualityGateUrl } from '../../../helpers/urls';
+import Modal from '../../../components/controls/Modal';
+import { Button, ResetButtonLink } from '../../../components/ui/buttons';
import { translate } from '../../../helpers/l10n';
+import { getQualityGateUrl } from '../../../helpers/urls';
interface Props {
qualityGate: QualityGate;
@@ -56,11 +57,6 @@ export default class CopyQualityGateForm extends React.PureComponent<Props, Stat
this.mounted = false;
}
- handleCancelClick = (event: React.SyntheticEvent<HTMLElement>) => {
- event.preventDefault();
- this.props.onClose();
- };
-
handleNameChange = (event: React.SyntheticEvent<HTMLInputElement>) => {
this.setState({ name: event.currentTarget.value });
};
@@ -120,12 +116,12 @@ export default class CopyQualityGateForm extends React.PureComponent<Props, Stat
</div>
<div className="modal-foot">
{loading && <i className="spinner spacer-right" />}
- <button disabled={submitDisabled} className="js-confirm">
+ <Button className="js-confirm" disabled={submitDisabled}>
{translate('copy')}
- </button>
- <a href="#" className="js-modal-close" onClick={this.handleCancelClick}>
+ </Button>
+ <ResetButtonLink className="js-modal-close" onClick={this.props.onClose}>
{translate('cancel')}
- </a>
+ </ResetButtonLink>
</div>
</form>
</Modal>
diff --git a/server/sonar-web/src/main/js/apps/quality-gates/components/CreateQualityGateForm.tsx b/server/sonar-web/src/main/js/apps/quality-gates/components/CreateQualityGateForm.tsx
index cb228fd06ad..f34aad8bfb9 100644
--- a/server/sonar-web/src/main/js/apps/quality-gates/components/CreateQualityGateForm.tsx
+++ b/server/sonar-web/src/main/js/apps/quality-gates/components/CreateQualityGateForm.tsx
@@ -19,8 +19,9 @@
*/
import * as React from 'react';
import * as PropTypes from 'prop-types';
-import Modal from '../../../components/controls/Modal';
import { createQualityGate, QualityGate } from '../../../api/quality-gates';
+import Modal from '../../../components/controls/Modal';
+import { Button, ResetButtonLink } from '../../../components/ui/buttons';
import { translate } from '../../../helpers/l10n';
import { getQualityGateUrl } from '../../../helpers/urls';
@@ -52,11 +53,6 @@ export default class CreateQualityGateForm extends React.PureComponent<Props, St
this.mounted = false;
}
- handleCancelClick = (event: React.SyntheticEvent<HTMLElement>) => {
- event.preventDefault();
- this.props.onClose();
- };
-
handleNameChange = (event: React.SyntheticEvent<HTMLInputElement>) => {
this.setState({ name: event.currentTarget.value });
};
@@ -113,12 +109,12 @@ export default class CreateQualityGateForm extends React.PureComponent<Props, St
</div>
<div className="modal-foot">
{loading && <i className="spinner spacer-right" />}
- <button disabled={submitDisabled} className="js-confirm">
+ <Button className="js-confirm" disabled={submitDisabled}>
{translate('save')}
- </button>
- <a href="#" className="js-modal-close" onClick={this.handleCancelClick}>
+ </Button>
+ <ResetButtonLink className="js-modal-close" onClick={this.props.onClose}>
{translate('cancel')}
- </a>
+ </ResetButtonLink>
</div>
</form>
</Modal>
diff --git a/server/sonar-web/src/main/js/apps/quality-gates/components/DeleteConditionForm.tsx b/server/sonar-web/src/main/js/apps/quality-gates/components/DeleteConditionForm.tsx
index c8f041fef39..ce41277c1ad 100644
--- a/server/sonar-web/src/main/js/apps/quality-gates/components/DeleteConditionForm.tsx
+++ b/server/sonar-web/src/main/js/apps/quality-gates/components/DeleteConditionForm.tsx
@@ -18,9 +18,10 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import * as React from 'react';
-import Modal from '../../../components/controls/Modal';
-import { Metric } from '../../../app/types';
import { Condition, deleteCondition } from '../../../api/quality-gates';
+import { Metric } from '../../../app/types';
+import Modal from '../../../components/controls/Modal';
+import { SubmitButton, ResetButtonLink } from '../../../components/ui/buttons';
import { getLocalizedMetricName, translate, translateWithParameters } from '../../../helpers/l10n';
interface Props {
@@ -47,11 +48,6 @@ export default class DeleteConditionForm extends React.PureComponent<Props, Stat
this.mounted = false;
}
- handleCancelClick = (event: React.SyntheticEvent<HTMLElement>) => {
- event.preventDefault();
- this.props.onClose();
- };
-
handleFormSubmit = (event: React.SyntheticEvent<HTMLFormElement>) => {
event.preventDefault();
const { organization, condition } = this.props;
@@ -86,12 +82,12 @@ export default class DeleteConditionForm extends React.PureComponent<Props, Stat
</div>
<div className="modal-foot">
{this.state.loading && <i className="spinner spacer-right" />}
- <button className="js-delete button-red" disabled={this.state.loading}>
+ <SubmitButton className="js-delete button-red" disabled={this.state.loading}>
{translate('delete')}
- </button>
- <a href="#" className="js-modal-close" onClick={this.handleCancelClick}>
+ </SubmitButton>
+ <ResetButtonLink className="js-modal-close" onClick={this.props.onClose}>
{translate('cancel')}
- </a>
+ </ResetButtonLink>
</div>
</form>
</Modal>
diff --git a/server/sonar-web/src/main/js/apps/quality-gates/components/DeleteQualityGateForm.tsx b/server/sonar-web/src/main/js/apps/quality-gates/components/DeleteQualityGateForm.tsx
index b37e21d0b5d..1d0edec416a 100644
--- a/server/sonar-web/src/main/js/apps/quality-gates/components/DeleteQualityGateForm.tsx
+++ b/server/sonar-web/src/main/js/apps/quality-gates/components/DeleteQualityGateForm.tsx
@@ -19,10 +19,11 @@
*/
import * as React from 'react';
import * as PropTypes from 'prop-types';
-import Modal from '../../../components/controls/Modal';
-import { getQualityGatesUrl } from '../../../helpers/urls';
import { deleteQualityGate, QualityGate } from '../../../api/quality-gates';
+import Modal from '../../../components/controls/Modal';
+import { SubmitButton, ResetButtonLink } from '../../../components/ui/buttons';
import { translate, translateWithParameters } from '../../../helpers/l10n';
+import { getQualityGatesUrl } from '../../../helpers/urls';
interface Props {
onClose: () => void;
@@ -52,11 +53,6 @@ export default class DeleteQualityGateForm extends React.PureComponent<Props, St
this.mounted = false;
}
- handleCancelClick = (event: React.SyntheticEvent<HTMLElement>) => {
- event.preventDefault();
- this.props.onClose();
- };
-
handleFormSubmit = (event: React.SyntheticEvent<HTMLFormElement>) => {
event.preventDefault();
const { organization, qualityGate } = this.props;
@@ -91,12 +87,12 @@ export default class DeleteQualityGateForm extends React.PureComponent<Props, St
</div>
<div className="modal-foot">
{this.state.loading && <i className="spinner spacer-right" />}
- <button className="js-delete button-red" disabled={this.state.loading}>
+ <SubmitButton className="js-delete button-red" disabled={this.state.loading}>
{translate('delete')}
- </button>
- <a href="#" className="js-modal-close" onClick={this.handleCancelClick}>
+ </SubmitButton>
+ <ResetButtonLink className="js-modal-close" onClick={this.props.onClose}>
{translate('cancel')}
- </a>
+ </ResetButtonLink>
</div>
</form>
</Modal>
diff --git a/server/sonar-web/src/main/js/apps/quality-gates/components/DetailsHeader.tsx b/server/sonar-web/src/main/js/apps/quality-gates/components/DetailsHeader.tsx
index 244b2a7090b..a661becfdef 100644
--- a/server/sonar-web/src/main/js/apps/quality-gates/components/DetailsHeader.tsx
+++ b/server/sonar-web/src/main/js/apps/quality-gates/components/DetailsHeader.tsx
@@ -23,6 +23,7 @@ import RenameQualityGateForm from './RenameQualityGateForm';
import CopyQualityGateForm from './CopyQualityGateForm';
import DeleteQualityGateForm from './DeleteQualityGateForm';
import { fetchQualityGate, QualityGate, setQualityGateAsDefault } from '../../../api/quality-gates';
+import { Button } from '../../../components/ui/buttons';
import { translate } from '../../../helpers/l10n';
interface Props {
@@ -41,18 +42,15 @@ interface State {
export default class DetailsHeader extends React.PureComponent<Props, State> {
state = { openPopup: undefined };
- handleRenameClick = (e: React.SyntheticEvent<HTMLButtonElement>) => {
- e.preventDefault();
+ handleRenameClick = () => {
this.setState({ openPopup: 'rename' });
};
- handleCopyClick = (e: React.SyntheticEvent<HTMLButtonElement>) => {
- e.preventDefault();
+ handleCopyClick = () => {
this.setState({ openPopup: 'copy' });
};
- handleSetAsDefaultClick = (e: React.SyntheticEvent<HTMLButtonElement>) => {
- e.preventDefault();
+ handleSetAsDefaultClick = () => {
const { qualityGate, onSetAsDefault, organization } = this.props;
if (!qualityGate.isDefault) {
setQualityGateAsDefault({ id: qualityGate.id, organization })
@@ -61,8 +59,7 @@ export default class DetailsHeader extends React.PureComponent<Props, State> {
}
};
- handleDeleteClick = (e: React.SyntheticEvent<HTMLButtonElement>) => {
- e.preventDefault();
+ handleDeleteClick = () => {
this.setState({ openPopup: 'delete' });
};
@@ -83,57 +80,57 @@ export default class DetailsHeader extends React.PureComponent<Props, State> {
<div className="pull-right">
{actions.rename && (
- <button id="quality-gate-rename" onClick={this.handleRenameClick}>
+ <Button id="quality-gate-rename" onClick={this.handleRenameClick}>
{translate('rename')}
- </button>
+ </Button>
)}
{actions.copy && (
- <button
+ <Button
className="little-spacer-left"
id="quality-gate-copy"
onClick={this.handleCopyClick}>
{translate('copy')}
- </button>
+ </Button>
)}
{actions.setAsDefault && (
- <button
+ <Button
className="little-spacer-left"
id="quality-gate-toggle-default"
onClick={this.handleSetAsDefaultClick}>
{translate('set_as_default')}
- </button>
+ </Button>
)}
{actions.delete && (
- <button
- id="quality-gate-delete"
+ <Button
className="little-spacer-left button-red"
+ id="quality-gate-delete"
onClick={this.handleDeleteClick}>
{translate('delete')}
- </button>
+ </Button>
)}
{openPopup === 'rename' && (
<RenameQualityGateForm
+ onClose={this.handleClosePopup}
onRename={this.props.onRename}
organization={organization}
- onClose={this.handleClosePopup}
qualityGate={qualityGate}
/>
)}
{openPopup === 'copy' && (
<CopyQualityGateForm
+ onClose={this.handleClosePopup}
onCopy={this.props.onCopy}
organization={organization}
- onClose={this.handleClosePopup}
qualityGate={qualityGate}
/>
)}
{openPopup === 'delete' && (
<DeleteQualityGateForm
+ onClose={this.handleClosePopup}
onDelete={this.props.onDelete}
organization={organization}
- onClose={this.handleClosePopup}
qualityGate={qualityGate}
/>
)}
diff --git a/server/sonar-web/src/main/js/apps/quality-gates/components/ListHeader.tsx b/server/sonar-web/src/main/js/apps/quality-gates/components/ListHeader.tsx
index efef33d5335..4a267e581fb 100644
--- a/server/sonar-web/src/main/js/apps/quality-gates/components/ListHeader.tsx
+++ b/server/sonar-web/src/main/js/apps/quality-gates/components/ListHeader.tsx
@@ -20,8 +20,9 @@
import * as React from 'react';
import CreateQualityGateForm from '../components/CreateQualityGateForm';
import { QualityGate } from '../../../api/quality-gates';
-import { translate } from '../../../helpers/l10n';
import { Organization } from '../../../app/types';
+import { Button } from '../../../components/ui/buttons';
+import { translate } from '../../../helpers/l10n';
interface Props {
canCreate: boolean;
@@ -36,8 +37,13 @@ interface State {
export default class ListHeader extends React.PureComponent<Props, State> {
state = { createQualityGateOpen: false };
- openCreateQualityGateForm = () => this.setState({ createQualityGateOpen: true });
- closeCreateQualityGateForm = () => this.setState({ createQualityGateOpen: false });
+ openCreateQualityGateForm = () => {
+ this.setState({ createQualityGateOpen: true });
+ };
+
+ closeCreateQualityGateForm = () => {
+ this.setState({ createQualityGateOpen: false });
+ };
render() {
const { organization } = this.props;
@@ -47,9 +53,9 @@ export default class ListHeader extends React.PureComponent<Props, State> {
<h1 className="page-title">{translate('quality_gates.page')}</h1>
{this.props.canCreate && (
<div className="page-actions">
- <button id="quality-gate-add" onClick={this.openCreateQualityGateForm}>
+ <Button id="quality-gate-add" onClick={this.openCreateQualityGateForm}>
{translate('create')}
- </button>
+ </Button>
</div>
)}
{this.state.createQualityGateOpen && (
diff --git a/server/sonar-web/src/main/js/apps/quality-gates/components/RenameQualityGateForm.tsx b/server/sonar-web/src/main/js/apps/quality-gates/components/RenameQualityGateForm.tsx
index 964f160ad40..aebd61dda73 100644
--- a/server/sonar-web/src/main/js/apps/quality-gates/components/RenameQualityGateForm.tsx
+++ b/server/sonar-web/src/main/js/apps/quality-gates/components/RenameQualityGateForm.tsx
@@ -18,8 +18,9 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import * as React from 'react';
-import Modal from '../../../components/controls/Modal';
import { QualityGate, renameQualityGate } from '../../../api/quality-gates';
+import Modal from '../../../components/controls/Modal';
+import { SubmitButton, ResetButtonLink } from '../../../components/ui/buttons';
import { translate } from '../../../helpers/l10n';
interface Props {
@@ -50,11 +51,6 @@ export default class RenameQualityGateForm extends React.PureComponent<Props, St
this.mounted = false;
}
- handleCancelClick = (event: React.SyntheticEvent<HTMLElement>) => {
- event.preventDefault();
- this.props.onClose();
- };
-
handleNameChange = (event: React.SyntheticEvent<HTMLInputElement>) => {
this.setState({ name: event.currentTarget.value });
};
@@ -111,12 +107,12 @@ export default class RenameQualityGateForm extends React.PureComponent<Props, St
</div>
<div className="modal-foot">
{loading && <i className="spinner spacer-right" />}
- <button disabled={submitDisabled} className="js-confirm">
+ <SubmitButton className="js-confirm" disabled={submitDisabled}>
{translate('rename')}
- </button>
- <a href="#" className="js-modal-close" onClick={this.handleCancelClick}>
+ </SubmitButton>
+ <ResetButtonLink className="js-modal-close" onClick={this.props.onClose}>
{translate('cancel')}
- </a>
+ </ResetButtonLink>
</div>
</form>
</Modal>
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/changelog/ChangelogSearch.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/changelog/ChangelogSearch.tsx
index e4e9220ba8d..f298e8f4056 100644
--- a/server/sonar-web/src/main/js/apps/quality-profiles/changelog/ChangelogSearch.tsx
+++ b/server/sonar-web/src/main/js/apps/quality-profiles/changelog/ChangelogSearch.tsx
@@ -19,6 +19,7 @@
*/
import * as React from 'react';
import DateInput from '../../../components/controls/DateInput';
+import { Button } from '../../../components/ui/buttons';
import { toShortNotSoISOString } from '../../../helpers/dates';
import { translate } from '../../../helpers/l10n';
@@ -31,12 +32,6 @@ interface Props {
}
export default class ChangelogSearch extends React.PureComponent<Props> {
- handleResetClick = (event: React.SyntheticEvent<HTMLElement>) => {
- event.preventDefault();
- event.currentTarget.blur();
- this.props.onReset();
- };
-
formatDate = (date?: string) => (date ? toShortNotSoISOString(date) : undefined);
render() {
@@ -57,9 +52,9 @@ export default class ChangelogSearch extends React.PureComponent<Props> {
placeholder={translate('to')}
value={this.formatDate(this.props.toDate)}
/>
- <button className="spacer-left" onClick={this.handleResetClick}>
+ <Button className="spacer-left" onClick={this.props.onReset}>
{translate('reset_verb')}
- </button>
+ </Button>
</div>
);
}
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/changelog/__tests__/ChangelogSearch-test.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/changelog/__tests__/ChangelogSearch-test.tsx
index 454bc713ba6..e0812fa388d 100644
--- a/server/sonar-web/src/main/js/apps/quality-profiles/changelog/__tests__/ChangelogSearch-test.tsx
+++ b/server/sonar-web/src/main/js/apps/quality-profiles/changelog/__tests__/ChangelogSearch-test.tsx
@@ -29,10 +29,10 @@ it('should render DateInput', () => {
const output = shallow(
<ChangelogSearch
fromDate="2016-01-01"
- toDate="2016-05-05"
onFromDateChange={onFromDateChange}
- onToDateChange={onToDateChange}
onReset={jest.fn()}
+ onToDateChange={onToDateChange}
+ toDate="2016-05-05"
/>
);
const dateInputs = output.find(DateInput);
@@ -48,13 +48,13 @@ it('should reset', () => {
const output = shallow(
<ChangelogSearch
fromDate="2016-01-01"
- toDate="2016-05-05"
onFromDateChange={jest.fn()}
- onToDateChange={jest.fn()}
onReset={onReset}
+ onToDateChange={jest.fn()}
+ toDate="2016-05-05"
/>
);
expect(onReset).not.toBeCalled();
- click(output.find('button'));
+ click(output.find('Button'));
expect(onReset).toBeCalled();
});
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/components/CopyProfileForm.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/components/CopyProfileForm.tsx
index 7d04a1f3809..39cd96b4c88 100644
--- a/server/sonar-web/src/main/js/apps/quality-profiles/components/CopyProfileForm.tsx
+++ b/server/sonar-web/src/main/js/apps/quality-profiles/components/CopyProfileForm.tsx
@@ -18,10 +18,11 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import * as React from 'react';
+import { Profile } from '../types';
import { copyProfile } from '../../../api/quality-profiles';
import Modal from '../../../components/controls/Modal';
+import { SubmitButton, ResetButtonLink } from '../../../components/ui/buttons';
import { translate, translateWithParameters } from '../../../helpers/l10n';
-import { Profile } from '../types';
interface Props {
onClose: () => void;
@@ -47,11 +48,6 @@ export default class CopyProfileForm extends React.PureComponent<Props, State> {
this.mounted = false;
}
- handleCancelClick = (event: React.SyntheticEvent<HTMLElement>) => {
- event.preventDefault();
- this.props.onClose();
- };
-
handleNameChange = (event: React.SyntheticEvent<HTMLInputElement>) => {
this.setState({ name: event.currentTarget.value });
};
@@ -112,12 +108,12 @@ export default class CopyProfileForm extends React.PureComponent<Props, State> {
</div>
<div className="modal-foot">
{this.state.loading && <i className="spinner spacer-right" />}
- <button disabled={submitDisabled} id="copy-profile-submit">
+ <SubmitButton disabled={submitDisabled} id="copy-profile-submit">
{translate('copy')}
- </button>
- <a href="#" id="copy-profile-cancel" onClick={this.handleCancelClick}>
+ </SubmitButton>
+ <ResetButtonLink id="copy-profile-cancel" onClick={this.props.onClose}>
{translate('cancel')}
- </a>
+ </ResetButtonLink>
</div>
</form>
</Modal>
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/components/DeleteProfileForm.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/components/DeleteProfileForm.tsx
index 1b564ec9be0..39260d39eb7 100644
--- a/server/sonar-web/src/main/js/apps/quality-profiles/components/DeleteProfileForm.tsx
+++ b/server/sonar-web/src/main/js/apps/quality-profiles/components/DeleteProfileForm.tsx
@@ -18,10 +18,11 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import * as React from 'react';
+import { Profile } from '../types';
import { deleteProfile } from '../../../api/quality-profiles';
import Modal from '../../../components/controls/Modal';
+import { SubmitButton, ResetButtonLink } from '../../../components/ui/buttons';
import { translate, translateWithParameters } from '../../../helpers/l10n';
-import { Profile } from '../types';
interface Props {
onClose: () => void;
@@ -47,11 +48,6 @@ export default class DeleteProfileForm extends React.PureComponent<Props, State>
this.mounted = false;
}
- handleCancelClick = (event: React.SyntheticEvent<HTMLElement>) => {
- event.preventDefault();
- this.props.onClose();
- };
-
handleFormSubmit = (event: React.SyntheticEvent<HTMLFormElement>) => {
event.preventDefault();
this.setState({ loading: true });
@@ -100,12 +96,15 @@ export default class DeleteProfileForm extends React.PureComponent<Props, State>
</div>
<div className="modal-foot">
{this.state.loading && <i className="spinner spacer-right" />}
- <button className="button-red" disabled={this.state.loading} id="delete-profile-submit">
+ <SubmitButton
+ className="button-red"
+ disabled={this.state.loading}
+ id="delete-profile-submit">
{translate('delete')}
- </button>
- <a href="#" id="delete-profile-cancel" onClick={this.handleCancelClick}>
+ </SubmitButton>
+ <ResetButtonLink id="delete-profile-cancel" onClick={this.props.onClose}>
{translate('cancel')}
- </a>
+ </ResetButtonLink>
</div>
</form>
</Modal>
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/components/RenameProfileForm.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/components/RenameProfileForm.tsx
index 34b610bc7d8..fd04227ede9 100644
--- a/server/sonar-web/src/main/js/apps/quality-profiles/components/RenameProfileForm.tsx
+++ b/server/sonar-web/src/main/js/apps/quality-profiles/components/RenameProfileForm.tsx
@@ -18,10 +18,11 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import * as React from 'react';
+import { Profile } from '../types';
import { renameProfile } from '../../../api/quality-profiles';
import Modal from '../../../components/controls/Modal';
+import { SubmitButton, ResetButtonLink } from '../../../components/ui/buttons';
import { translate, translateWithParameters } from '../../../helpers/l10n';
-import { Profile } from '../types';
interface Props {
onClose: () => void;
@@ -47,11 +48,6 @@ export default class RenameProfileForm extends React.PureComponent<Props, State>
this.mounted = false;
}
- handleCancelClick = (event: React.SyntheticEvent<HTMLElement>) => {
- event.preventDefault();
- this.props.onClose();
- };
-
handleNameChange = (event: React.SyntheticEvent<HTMLInputElement>) => {
this.setState({ name: event.currentTarget.value });
};
@@ -112,12 +108,12 @@ export default class RenameProfileForm extends React.PureComponent<Props, State>
</div>
<div className="modal-foot">
{this.state.loading && <i className="spinner spacer-right" />}
- <button disabled={submitDisabled} id="rename-profile-submit">
+ <SubmitButton disabled={submitDisabled} id="rename-profile-submit">
{translate('rename')}
- </button>
- <a href="#" id="rename-profile-cancel" onClick={this.handleCancelClick}>
+ </SubmitButton>
+ <ResetButtonLink id="rename-profile-cancel" onClick={this.props.onClose}>
{translate('cancel')}
- </a>
+ </ResetButtonLink>
</div>
</form>
</Modal>
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/details/ChangeParentForm.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/details/ChangeParentForm.tsx
index b1978c6d310..b783eb7e411 100644
--- a/server/sonar-web/src/main/js/apps/quality-profiles/details/ChangeParentForm.tsx
+++ b/server/sonar-web/src/main/js/apps/quality-profiles/details/ChangeParentForm.tsx
@@ -19,11 +19,12 @@
*/
import * as React from 'react';
import { sortBy } from 'lodash';
+import { Profile } from '../types';
import { changeProfileParent } from '../../../api/quality-profiles';
import Modal from '../../../components/controls/Modal';
import Select from '../../../components/controls/Select';
+import { SubmitButton, ResetButtonLink } from '../../../components/ui/buttons';
import { translate } from '../../../helpers/l10n';
-import { Profile } from '../types';
interface Props {
onChange: () => void;
@@ -53,11 +54,6 @@ export default class ChangeParentForm extends React.PureComponent<Props, State>
this.mounted = false;
}
- handleCancelClick = (event: React.SyntheticEvent<HTMLElement>) => {
- event.preventDefault();
- this.props.onClose();
- };
-
handleSelectChange = (option: { value: string }) => {
this.setState({ selected: option.value });
};
@@ -126,12 +122,12 @@ export default class ChangeParentForm extends React.PureComponent<Props, State>
</div>
<div className="modal-foot">
{this.state.loading && <i className="spinner spacer-right" />}
- <button disabled={submitDisabled} id="change-profile-parent-submit">
+ <SubmitButton disabled={submitDisabled} id="change-profile-parent-submit">
{translate('change_verb')}
- </button>
- <a href="#" id="change-profile-parent-cancel" onClick={this.handleCancelClick}>
+ </SubmitButton>
+ <ResetButtonLink id="change-profile-parent-cancel" onClick={this.props.onClose}>
{translate('cancel')}
- </a>
+ </ResetButtonLink>
</div>
</form>
</Modal>
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileInheritance.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileInheritance.tsx
index 2786757c0f3..85deb056f70 100644
--- a/server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileInheritance.tsx
+++ b/server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileInheritance.tsx
@@ -21,9 +21,10 @@ import * as React from 'react';
import * as classNames from 'classnames';
import ProfileInheritanceBox from './ProfileInheritanceBox';
import ChangeParentForm from './ChangeParentForm';
-import { translate } from '../../../helpers/l10n';
-import { getProfileInheritance } from '../../../api/quality-profiles';
import { Profile } from '../types';
+import { getProfileInheritance } from '../../../api/quality-profiles';
+import { Button } from '../../../components/ui/buttons';
+import { translate } from '../../../helpers/l10n';
interface Props {
onRequestFail: (reason: any) => void;
@@ -74,21 +75,27 @@ export default class ProfileInheritance extends React.PureComponent<Props, State
}
loadData() {
- getProfileInheritance(this.props.profile.key).then((r: any) => {
- if (this.mounted) {
- const { ancestors, children } = r;
- this.setState({
- children,
- ancestors: ancestors.reverse(),
- profile: r.profile,
- loading: false
- });
+ getProfileInheritance(this.props.profile.key).then(
+ r => {
+ if (this.mounted) {
+ const { ancestors, children } = r;
+ this.setState({
+ children,
+ ancestors: ancestors.reverse(),
+ profile: r.profile,
+ loading: false
+ });
+ }
+ },
+ () => {
+ if (this.mounted) {
+ this.setState({ loading: false });
+ }
}
- });
+ );
}
- handleChangeParentClick = (event: React.SyntheticEvent<HTMLElement>) => {
- event.preventDefault();
+ handleChangeParentClick = () => {
this.setState({ formOpen: true });
};
@@ -123,11 +130,11 @@ export default class ProfileInheritance extends React.PureComponent<Props, State
profile.actions.edit &&
!profile.isBuiltIn && (
<div className="boxed-group-actions">
- <button
+ <Button
className="pull-right js-change-parent"
onClick={this.handleChangeParentClick}>
{translate('quality_profiles.change_parent')}
- </button>
+ </Button>
</div>
)}
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/details/ProfilePermissions.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/details/ProfilePermissions.tsx
index e77208909df..ad88c22f0a1 100644
--- a/server/sonar-web/src/main/js/apps/quality-profiles/details/ProfilePermissions.tsx
+++ b/server/sonar-web/src/main/js/apps/quality-profiles/details/ProfilePermissions.tsx
@@ -27,6 +27,7 @@ import {
searchGroups,
SearchUsersGroupsParameters
} from '../../../api/quality-profiles';
+import { Button } from '../../../components/ui/buttons';
import { translate } from '../../../helpers/l10n';
export interface User {
@@ -100,9 +101,7 @@ export default class ProfilePermissions extends React.PureComponent<Props, State
);
}
- handleAddUserButtonClick = (event: React.SyntheticEvent<HTMLButtonElement>) => {
- event.preventDefault();
- event.currentTarget.blur();
+ handleAddUserButtonClick = () => {
this.setState({ addUserForm: true });
};
@@ -180,9 +179,9 @@ export default class ProfilePermissions extends React.PureComponent<Props, State
/>
))}
<div className="text-right">
- <button onClick={this.handleAddUserButtonClick}>
+ <Button onClick={this.handleAddUserButtonClick}>
{translate('quality_profiles.grant_permissions_to_more_users')}
- </button>
+ </Button>
</div>
</div>
)}
@@ -193,8 +192,8 @@ export default class ProfilePermissions extends React.PureComponent<Props, State
onClose={this.handleAddUserFormClose}
onGroupAdd={this.handleGroupAdd}
onUserAdd={this.handleUserAdd}
- profile={this.props.profile}
organization={this.props.organization}
+ profile={this.props.profile}
/>
)}
</div>
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/details/ProfilePermissionsForm.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/details/ProfilePermissionsForm.tsx
index 06fc7c571da..cb5a652065a 100644
--- a/server/sonar-web/src/main/js/apps/quality-profiles/details/ProfilePermissionsForm.tsx
+++ b/server/sonar-web/src/main/js/apps/quality-profiles/details/ProfilePermissionsForm.tsx
@@ -28,6 +28,7 @@ import {
SearchUsersGroupsParameters
} from '../../../api/quality-profiles';
import Modal from '../../../components/controls/Modal';
+import { SubmitButton, ResetButtonLink } from '../../../components/ui/buttons';
import { translate } from '../../../helpers/l10n';
interface Props {
@@ -121,20 +122,16 @@ export default class ProfilePermissionsForm extends React.PureComponent<Props, S
<div className="modal-large-field">
<label>{translate('quality_profiles.search_description')}</label>
<ProfilePermissionsFormSelect
- selected={this.state.selected}
onChange={this.handleValueChange}
onSearch={this.handleSearch}
+ selected={this.state.selected}
/>
</div>
</div>
<footer className="modal-foot">
{this.state.submitting && <i className="spinner spacer-right" />}
- <button disabled={submitDisabled} type="submit">
- {translate('add_verb')}
- </button>
- <button className="button-link" onClick={this.props.onClose} type="reset">
- {translate('cancel')}
- </button>
+ <SubmitButton disabled={submitDisabled}>{translate('add_verb')}</SubmitButton>
+ <ResetButtonLink onClick={this.props.onClose}>{translate('cancel')}</ResetButtonLink>
</footer>
</form>
</Modal>
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/details/ProfilePermissionsGroup.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/details/ProfilePermissionsGroup.tsx
index 2dbb0885ee2..7e859a8fe38 100644
--- a/server/sonar-web/src/main/js/apps/quality-profiles/details/ProfilePermissionsGroup.tsx
+++ b/server/sonar-web/src/main/js/apps/quality-profiles/details/ProfilePermissionsGroup.tsx
@@ -23,7 +23,7 @@ import { Group } from './ProfilePermissions';
import { removeGroup } from '../../../api/quality-profiles';
import SimpleModal, { ChildrenProps } from '../../../components/controls/SimpleModal';
import GroupIcon from '../../../components/icons-components/GroupIcon';
-import { DeleteButton } from '../../../components/ui/buttons';
+import { DeleteButton, Button, ResetButtonLink } from '../../../components/ui/buttons';
import { translate } from '../../../helpers/l10n';
interface Props {
@@ -91,12 +91,10 @@ export default class ProfilePermissionsGroup extends React.PureComponent<Props,
<footer className="modal-foot">
{props.submitting && <i className="spinner spacer-right" />}
- <button className="button-red" disabled={props.submitting} onClick={props.onSubmitClick}>
+ <Button className="button-red" disabled={props.submitting} onClick={props.onSubmitClick}>
{translate('remove')}
- </button>
- <a href="#" onClick={props.onCloseClick}>
- {translate('cancel')}
- </a>
+ </Button>
+ <ResetButtonLink onClick={props.onCloseClick}>{translate('cancel')}</ResetButtonLink>
</footer>
</div>
);
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/details/ProfilePermissionsUser.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/details/ProfilePermissionsUser.tsx
index d2c2094cd62..f35c21287e4 100644
--- a/server/sonar-web/src/main/js/apps/quality-profiles/details/ProfilePermissionsUser.tsx
+++ b/server/sonar-web/src/main/js/apps/quality-profiles/details/ProfilePermissionsUser.tsx
@@ -22,7 +22,7 @@ import { FormattedMessage } from 'react-intl';
import { User } from './ProfilePermissions';
import { removeUser } from '../../../api/quality-profiles';
import SimpleModal, { ChildrenProps } from '../../../components/controls/SimpleModal';
-import { DeleteButton } from '../../../components/ui/buttons';
+import { DeleteButton, SubmitButton, ResetButtonLink } from '../../../components/ui/buttons';
import Avatar from '../../../components/ui/Avatar';
import { translate } from '../../../helpers/l10n';
@@ -91,12 +91,13 @@ export default class ProfilePermissionsUser extends React.PureComponent<Props, S
<footer className="modal-foot">
{props.submitting && <i className="spinner spacer-right" />}
- <button className="button-red" disabled={props.submitting} onClick={props.onSubmitClick}>
+ <SubmitButton
+ className="button-red"
+ disabled={props.submitting}
+ onClick={props.onSubmitClick}>
{translate('remove')}
- </button>
- <a href="#" onClick={props.onCloseClick}>
- {translate('cancel')}
- </a>
+ </SubmitButton>
+ <ResetButtonLink onClick={props.onCloseClick}>{translate('cancel')}</ResetButtonLink>
</footer>
</div>
);
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileProjects.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileProjects.tsx
index 84fd60c40fa..7ac978ea69e 100644
--- a/server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileProjects.tsx
+++ b/server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileProjects.tsx
@@ -20,10 +20,11 @@
import * as React from 'react';
import { Link } from 'react-router';
import ChangeProjectsForm from './ChangeProjectsForm';
-import QualifierIcon from '../../../components/shared/QualifierIcon';
+import { Profile } from '../types';
import { getProfileProjects } from '../../../api/quality-profiles';
+import QualifierIcon from '../../../components/shared/QualifierIcon';
+import { Button } from '../../../components/ui/buttons';
import { translate } from '../../../helpers/l10n';
-import { Profile } from '../types';
interface Props {
organization: string | null;
@@ -83,8 +84,7 @@ export default class ProfileProjects extends React.PureComponent<Props, State> {
);
}
- handleChangeClick = (event: React.SyntheticEvent<HTMLElement>) => {
- event.preventDefault();
+ handleChangeClick = () => {
this.setState({ formOpen: true });
};
@@ -124,10 +124,10 @@ export default class ProfileProjects extends React.PureComponent<Props, State> {
return (
<ul>
{projects.map(project => (
- <li key={project.uuid} className="spacer-top js-profile-project" data-key={project.key}>
+ <li className="spacer-top js-profile-project" data-key={project.key} key={project.uuid}>
<Link
- to={{ pathname: '/dashboard', query: { id: project.key } }}
- className="link-with-icon">
+ className="link-with-icon"
+ to={{ pathname: '/dashboard', query: { id: project.key } }}>
<QualifierIcon qualifier="TRK" /> <span>{project.name}</span>
</Link>
</li>
@@ -143,9 +143,9 @@ export default class ProfileProjects extends React.PureComponent<Props, State> {
{profile.actions &&
profile.actions.associateProjects && (
<div className="boxed-group-actions">
- <button className="js-change-projects" onClick={this.handleChangeClick}>
+ <Button className="js-change-projects" onClick={this.handleChangeClick}>
{translate('quality_profiles.change_projects')}
- </button>
+ </Button>
</div>
)}
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/ProfilePermissions-test.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/ProfilePermissions-test.tsx
index 08452e22416..ff5d9b2def5 100644
--- a/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/ProfilePermissions-test.tsx
+++ b/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/ProfilePermissions-test.tsx
@@ -59,7 +59,7 @@ it('opens add users form', async () => {
await waitAndUpdate(wrapper);
expect(wrapper.find('ProfilePermissionsForm').exists()).toBeFalsy();
- click(wrapper.find('button'));
+ click(wrapper.find('Button'));
expect(wrapper.find('ProfilePermissionsForm').exists()).toBeTruthy();
wrapper.find('ProfilePermissionsForm').prop<Function>('onClose')();
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/ProfilePermissionsGroup-test.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/ProfilePermissionsGroup-test.tsx
index e106e5a231c..fa4d4662aa7 100644
--- a/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/ProfilePermissionsGroup-test.tsx
+++ b/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/ProfilePermissionsGroup-test.tsx
@@ -25,6 +25,7 @@ jest.mock('../../../../api/quality-profiles', () => ({
import * as React from 'react';
import { shallow } from 'enzyme';
import ProfilePermissionsGroup from '../ProfilePermissionsGroup';
+import { click } from '../../../../helpers/testUtils';
const removeGroup = require('../../../../api/quality-profiles').removeGroup as jest.Mock<any>;
@@ -54,8 +55,7 @@ it('removes user', async () => {
(wrapper.instance() as ProfilePermissionsGroup).mounted = true;
expect(wrapper.find('SimpleModal').exists()).toBeFalsy();
- wrapper.find('DeleteButton').prop<Function>('onClick')();
- wrapper.update();
+ click(wrapper.find('DeleteButton'));
expect(wrapper.find('SimpleModal').exists()).toBeTruthy();
wrapper.find('SimpleModal').prop<Function>('onSubmit')();
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/ProfilePermissionsUser-test.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/ProfilePermissionsUser-test.tsx
index e26d1cf7322..7a9b63d9c4f 100644
--- a/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/ProfilePermissionsUser-test.tsx
+++ b/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/ProfilePermissionsUser-test.tsx
@@ -25,6 +25,7 @@ jest.mock('../../../../api/quality-profiles', () => ({
import * as React from 'react';
import { shallow } from 'enzyme';
import ProfilePermissionsUser from '../ProfilePermissionsUser';
+import { click } from '../../../../helpers/testUtils';
const removeUser = require('../../../../api/quality-profiles').removeUser as jest.Mock<any>;
@@ -49,8 +50,7 @@ it('removes user', async () => {
(wrapper.instance() as ProfilePermissionsUser).mounted = true;
expect(wrapper.find('SimpleModal').exists()).toBeFalsy();
- wrapper.find('DeleteButton').prop<Function>('onClick')();
- wrapper.update();
+ click(wrapper.find('DeleteButton'));
expect(wrapper.find('SimpleModal').exists()).toBeTruthy();
wrapper.find('SimpleModal').prop<Function>('onSubmit')();
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfilePermissions-test.tsx.snap b/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfilePermissions-test.tsx.snap
index 9dd2c1d6c47..29599454c98 100644
--- a/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfilePermissions-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfilePermissions-test.tsx.snap
@@ -78,11 +78,11 @@ exports[`renders 2`] = `
<div
className="text-right"
>
- <button
+ <Button
onClick={[Function]}
>
quality_profiles.grant_permissions_to_more_users
- </button>
+ </Button>
</div>
</div>
</div>
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfilePermissionsForm-test.tsx.snap b/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfilePermissionsForm-test.tsx.snap
index a4e51e5f160..4caa41a48c1 100644
--- a/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfilePermissionsForm-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfilePermissionsForm-test.tsx.snap
@@ -33,19 +33,16 @@ exports[`adds group 1`] = `
<footer
className="modal-foot"
>
- <button
+ <SubmitButton
disabled={true}
- type="submit"
>
add_verb
- </button>
- <button
- className="button-link"
+ </SubmitButton>
+ <ResetButtonLink
onClick={[MockFunction]}
- type="reset"
>
cancel
- </button>
+ </ResetButtonLink>
</footer>
</form>
</Modal>
@@ -89,19 +86,16 @@ exports[`adds group 2`] = `
<footer
className="modal-foot"
>
- <button
+ <SubmitButton
disabled={false}
- type="submit"
>
add_verb
- </button>
- <button
- className="button-link"
+ </SubmitButton>
+ <ResetButtonLink
onClick={[MockFunction]}
- type="reset"
>
cancel
- </button>
+ </ResetButtonLink>
</footer>
</form>
</Modal>
@@ -148,19 +142,16 @@ exports[`adds group 3`] = `
<i
className="spinner spacer-right"
/>
- <button
+ <SubmitButton
disabled={true}
- type="submit"
>
add_verb
- </button>
- <button
- className="button-link"
+ </SubmitButton>
+ <ResetButtonLink
onClick={[MockFunction]}
- type="reset"
>
cancel
- </button>
+ </ResetButtonLink>
</footer>
</form>
</Modal>
@@ -199,19 +190,16 @@ exports[`adds user 1`] = `
<footer
className="modal-foot"
>
- <button
+ <SubmitButton
disabled={true}
- type="submit"
>
add_verb
- </button>
- <button
- className="button-link"
+ </SubmitButton>
+ <ResetButtonLink
onClick={[MockFunction]}
- type="reset"
>
cancel
- </button>
+ </ResetButtonLink>
</footer>
</form>
</Modal>
@@ -255,19 +243,16 @@ exports[`adds user 2`] = `
<footer
className="modal-foot"
>
- <button
+ <SubmitButton
disabled={false}
- type="submit"
>
add_verb
- </button>
- <button
- className="button-link"
+ </SubmitButton>
+ <ResetButtonLink
onClick={[MockFunction]}
- type="reset"
>
cancel
- </button>
+ </ResetButtonLink>
</footer>
</form>
</Modal>
@@ -314,19 +299,16 @@ exports[`adds user 3`] = `
<i
className="spinner spacer-right"
/>
- <button
+ <SubmitButton
disabled={true}
- type="submit"
>
add_verb
- </button>
- <button
- className="button-link"
+ </SubmitButton>
+ <ResetButtonLink
onClick={[MockFunction]}
- type="reset"
>
cancel
- </button>
+ </ResetButtonLink>
</footer>
</form>
</Modal>
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/home/CreateProfileForm.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/home/CreateProfileForm.tsx
index d60ab75b1d2..e9fcc95b3ad 100644
--- a/server/sonar-web/src/main/js/apps/quality-profiles/home/CreateProfileForm.tsx
+++ b/server/sonar-web/src/main/js/apps/quality-profiles/home/CreateProfileForm.tsx
@@ -22,6 +22,7 @@ import { sortBy } from 'lodash';
import { getImporters, createQualityProfile } from '../../../api/quality-profiles';
import Modal from '../../../components/controls/Modal';
import Select from '../../../components/controls/Select';
+import { SubmitButton, ResetButtonLink } from '../../../components/ui/buttons';
import { translate } from '../../../helpers/l10n';
interface Props {
@@ -55,19 +56,19 @@ export default class CreateProfileForm extends React.PureComponent<Props, State>
fetchImporters() {
getImporters().then(
- (importers: Array<{ key: string; languages: Array<string>; name: string }>) => {
+ importers => {
if (this.mounted) {
this.setState({ importers, preloading: false });
}
+ },
+ () => {
+ if (this.mounted) {
+ this.setState({ preloading: false });
+ }
}
);
}
- handleCancelClick = (event: React.SyntheticEvent<HTMLElement>) => {
- event.preventDefault();
- this.props.onClose();
- };
-
handleNameChange = (event: React.SyntheticEvent<HTMLInputElement>) => {
this.setState({ name: event.currentTarget.value });
};
@@ -171,20 +172,20 @@ export default class CreateProfileForm extends React.PureComponent<Props, State>
</div>
))}
{/* drop me when we stop supporting ie11 */}
- <input type="hidden" name="hello-ie11" value="" />
+ <input name="hello-ie11" type="hidden" value="" />
</div>
)}
<div className="modal-foot">
{this.state.loading && <i className="spinner spacer-right" />}
{!this.state.preloading && (
- <button disabled={this.state.loading} id="create-profile-submit">
+ <SubmitButton disabled={this.state.loading} id="create-profile-submit">
{translate('create')}
- </button>
+ </SubmitButton>
)}
- <a href="#" id="create-profile-cancel" onClick={this.handleCancelClick}>
+ <ResetButtonLink id="create-profile-cancel" onClick={this.props.onClose}>
{translate('cancel')}
- </a>
+ </ResetButtonLink>
</div>
</form>
</Modal>
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/home/PageHeader.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/home/PageHeader.tsx
index 796daea5b23..1373fa0f309 100644
--- a/server/sonar-web/src/main/js/apps/quality-profiles/home/PageHeader.tsx
+++ b/server/sonar-web/src/main/js/apps/quality-profiles/home/PageHeader.tsx
@@ -21,10 +21,11 @@ import * as React from 'react';
import * as PropTypes from 'prop-types';
import CreateProfileForm from './CreateProfileForm';
import RestoreProfileForm from './RestoreProfileForm';
-import { getProfilePath } from '../utils';
-import { translate } from '../../../helpers/l10n';
import { Profile } from '../types';
+import { getProfilePath } from '../utils';
import { Actions } from '../../../api/quality-profiles';
+import { Button } from '../../../components/ui/buttons';
+import { translate } from '../../../helpers/l10n';
interface Props {
actions: Actions;
@@ -49,26 +50,26 @@ export default class PageHeader extends React.PureComponent<Props, State> {
restoreFormOpen: false
};
- handleCreateClick = (event: React.SyntheticEvent<HTMLElement>) => {
- event.preventDefault();
- event.currentTarget.blur();
+ handleCreateClick = () => {
this.setState({ createFormOpen: true });
};
handleCreate = (profile: Profile) => {
- this.props.updateProfiles().then(() => {
- this.context.router.push(
- getProfilePath(profile.name, profile.language, this.props.organization)
- );
- });
+ this.props.updateProfiles().then(
+ () => {
+ this.context.router.push(
+ getProfilePath(profile.name, profile.language, this.props.organization)
+ );
+ },
+ () => {}
+ );
};
closeCreateForm = () => {
this.setState({ createFormOpen: false });
};
- handleRestoreClick = (event: React.SyntheticEvent<HTMLElement>) => {
- event.preventDefault();
+ handleRestoreClick = () => {
this.setState({ restoreFormOpen: true });
};
@@ -83,15 +84,15 @@ export default class PageHeader extends React.PureComponent<Props, State> {
{this.props.actions.create && (
<div className="page-actions">
- <button id="quality-profiles-create" onClick={this.handleCreateClick}>
+ <Button id="quality-profiles-create" onClick={this.handleCreateClick}>
{translate('create')}
- </button>
- <button
+ </Button>
+ <Button
className="little-spacer-left"
id="quality-profiles-restore"
onClick={this.handleRestoreClick}>
{translate('restore')}
- </button>
+ </Button>
</div>
)}
@@ -114,8 +115,8 @@ export default class PageHeader extends React.PureComponent<Props, State> {
<CreateProfileForm
languages={this.props.languages}
onClose={this.closeCreateForm}
- onRequestFail={this.props.onRequestFail}
onCreate={this.handleCreate}
+ onRequestFail={this.props.onRequestFail}
organization={this.props.organization}
/>
)}
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/home/RestoreProfileForm.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/home/RestoreProfileForm.tsx
index d964ff019ee..a93f0e0a44e 100644
--- a/server/sonar-web/src/main/js/apps/quality-profiles/home/RestoreProfileForm.tsx
+++ b/server/sonar-web/src/main/js/apps/quality-profiles/home/RestoreProfileForm.tsx
@@ -21,6 +21,7 @@ import * as React from 'react';
import { restoreQualityProfile } from '../../../api/quality-profiles';
import Modal from '../../../components/controls/Modal';
import { translate, translateWithParameters } from '../../../helpers/l10n';
+import { SubmitButton, ResetButtonLink } from '../../../components/ui/buttons';
interface Props {
onClose: () => void;
@@ -48,11 +49,6 @@ export default class RestoreProfileForm extends React.PureComponent<Props, State
this.mounted = false;
}
- handleCancelClick = (event: React.SyntheticEvent<HTMLElement>) => {
- event.preventDefault();
- this.props.onClose();
- };
-
handleFormSubmit = (event: React.SyntheticEvent<HTMLFormElement>) => {
event.preventDefault();
@@ -130,18 +126,18 @@ export default class RestoreProfileForm extends React.PureComponent<Props, State
{ruleSuccesses == null ? (
<div className="modal-foot">
{loading && <i className="spinner spacer-right" />}
- <button disabled={loading} id="restore-profile-submit">
+ <SubmitButton disabled={loading} id="restore-profile-submit">
{translate('restore')}
- </button>
- <a href="#" id="restore-profile-cancel" onClick={this.handleCancelClick}>
+ </SubmitButton>
+ <ResetButtonLink id="restore-profile-cancel" onClick={this.props.onClose}>
{translate('cancel')}
- </a>
+ </ResetButtonLink>
</div>
) : (
<div className="modal-foot">
- <a href="#" onClick={this.handleCancelClick}>
+ <ResetButtonLink id="restore-profile-cancel" onClick={this.props.onClose}>
{translate('close')}
- </a>
+ </ResetButtonLink>
</div>
)}
</form>
diff --git a/server/sonar-web/src/main/js/apps/sessions/components/LoginForm.tsx b/server/sonar-web/src/main/js/apps/sessions/components/LoginForm.tsx
index 136f0b00522..b793c09a985 100644
--- a/server/sonar-web/src/main/js/apps/sessions/components/LoginForm.tsx
+++ b/server/sonar-web/src/main/js/apps/sessions/components/LoginForm.tsx
@@ -22,6 +22,7 @@ import { Link } from 'react-router';
import OAuthProviders from './OAuthProviders';
import GlobalMessagesContainer from '../../../app/components/GlobalMessagesContainer';
import { IdentityProvider } from '../../../app/types';
+import { SubmitButton } from '../../../components/ui/buttons';
import { translate } from '../../../helpers/l10n';
import './LoginForm.css';
@@ -94,44 +95,42 @@ export default class LoginForm extends React.PureComponent<Props, State> {
<GlobalMessagesContainer />
<div className="big-spacer-bottom">
- <label htmlFor="login" className="login-label">
+ <label className="login-label" htmlFor="login">
{translate('login')}
</label>
<input
- type="text"
- id="login"
- name="login"
+ autoFocus={true}
className="login-input"
+ id="login"
maxLength={255}
- required={true}
- autoFocus={true}
+ name="login"
+ onChange={this.handleLoginChange}
placeholder={translate('login')}
+ required={true}
+ type="text"
value={this.state.login}
- onChange={this.handleLoginChange}
/>
</div>
<div className="big-spacer-bottom">
- <label htmlFor="password" className="login-label">
+ <label className="login-label" htmlFor="password">
{translate('password')}
</label>
<input
- type="password"
+ className="login-input"
id="password"
name="password"
- className="login-input"
- required={true}
+ onChange={this.handlePwdChange}
placeholder={translate('password')}
+ required={true}
+ type="password"
value={this.state.password}
- onChange={this.handlePwdChange}
/>
</div>
<div>
<div className="text-right overflow-hidden">
- <button name="commit" type="submit">
- {translate('sessions.log_in')}
- </button>
+ <SubmitButton>{translate('sessions.log_in')}</SubmitButton>
<Link className="spacer-left" to="/">
{translate('cancel')}
</Link>
diff --git a/server/sonar-web/src/main/js/apps/sessions/components/__tests__/__snapshots__/LoginForm-test.tsx.snap b/server/sonar-web/src/main/js/apps/sessions/components/__tests__/__snapshots__/LoginForm-test.tsx.snap
index fddd44f6bcd..744c0b93b09 100644
--- a/server/sonar-web/src/main/js/apps/sessions/components/__tests__/__snapshots__/LoginForm-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/sessions/components/__tests__/__snapshots__/LoginForm-test.tsx.snap
@@ -111,12 +111,9 @@ exports[`expands more options 2`] = `
<div
className="text-right overflow-hidden"
>
- <button
- name="commit"
- type="submit"
- >
+ <SubmitButton>
sessions.log_in
- </button>
+ </SubmitButton>
<Link
className="spacer-left"
onlyActiveOnIndex={false}
@@ -229,12 +226,9 @@ exports[`logs in with simple credentials 1`] = `
<div
className="text-right overflow-hidden"
>
- <button
- name="commit"
- type="submit"
- >
+ <SubmitButton>
sessions.log_in
- </button>
+ </SubmitButton>
<Link
className="spacer-left"
onlyActiveOnIndex={false}
diff --git a/server/sonar-web/src/main/js/apps/system/components/ChangeLogLevelForm.tsx b/server/sonar-web/src/main/js/apps/system/components/ChangeLogLevelForm.tsx
index f3d70706104..fd80e756d09 100644
--- a/server/sonar-web/src/main/js/apps/system/components/ChangeLogLevelForm.tsx
+++ b/server/sonar-web/src/main/js/apps/system/components/ChangeLogLevelForm.tsx
@@ -18,10 +18,11 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import * as React from 'react';
+import { LOGS_LEVELS } from '../utils';
import { setLogLevel } from '../../../api/system';
import Modal from '../../../components/controls/Modal';
+import { SubmitButton, ResetButtonLink } from '../../../components/ui/buttons';
import { translate } from '../../../helpers/l10n';
-import { LOGS_LEVELS } from '../utils';
interface Props {
infoMsg: string;
@@ -41,11 +42,6 @@ export default class ChangeLogLevelForm extends React.PureComponent<Props, State
this.state = { newLevel: props.logLevel, updating: false };
}
- handleCancelClick = (event: React.SyntheticEvent<HTMLElement>) => {
- event.preventDefault();
- this.props.onClose();
- };
-
handleFormSubmit = (event: React.SyntheticEvent<HTMLFormElement>) => {
event.preventDefault();
const { newLevel } = this.state;
@@ -72,15 +68,15 @@ export default class ChangeLogLevelForm extends React.PureComponent<Props, State
</div>
<div className="modal-body">
{LOGS_LEVELS.map(level => (
- <p key={level} className="spacer-bottom">
+ <p className="spacer-bottom" key={level}>
<input
- id={`loglevel-${level}`}
- type="radio"
+ checked={level === newLevel}
className="spacer-right text-middle"
+ id={`loglevel-${level}`}
name="system.log_levels"
- value={level}
- checked={level === newLevel}
onChange={this.handleLevelChange}
+ type="radio"
+ value={level}
/>
<label className="text-middle" htmlFor={`loglevel-${level}`}>
{level}
@@ -96,12 +92,12 @@ export default class ChangeLogLevelForm extends React.PureComponent<Props, State
</div>
<div className="modal-foot">
{updating && <i className="spinner spacer-right" />}
- <button disabled={updating} id="set-log-level-submit">
+ <SubmitButton disabled={updating} id="set-log-level-submit">
{translate('save')}
- </button>
- <a href="#" id="set-log-level-cancel" onClick={this.handleCancelClick}>
+ </SubmitButton>
+ <ResetButtonLink id="set-log-level-cancel" onClick={this.props.onClose}>
{translate('cancel')}
- </a>
+ </ResetButtonLink>
</div>
</form>
</Modal>
diff --git a/server/sonar-web/src/main/js/apps/system/components/PageActions.tsx b/server/sonar-web/src/main/js/apps/system/components/PageActions.tsx
index dfda4b9e904..7b718fc5ad2 100644
--- a/server/sonar-web/src/main/js/apps/system/components/PageActions.tsx
+++ b/server/sonar-web/src/main/js/apps/system/components/PageActions.tsx
@@ -21,7 +21,7 @@ import * as React from 'react';
import ChangeLogLevelForm from './ChangeLogLevelForm';
import RestartForm from '../../../components/common/RestartForm';
import { getFileNameSuffix } from '../utils';
-import { EditButton } from '../../../components/ui/buttons';
+import { EditButton, Button } from '../../../components/ui/buttons';
import { getBaseUrl } from '../../../helpers/urls';
import { translate } from '../../../helpers/l10n';
@@ -66,12 +66,21 @@ export default class PageActions extends React.PureComponent<Props, State> {
this.handleLogsLevelClose();
};
- handleLogsLevelClose = () => this.setState({ openLogsLevelForm: false });
+ handleLogsLevelClose = () => {
+ this.setState({ openLogsLevelForm: false });
+ };
+
+ handleServerRestartOpen = () => {
+ this.setState({ openRestartForm: true });
+ };
- handleServerRestartOpen = () => this.setState({ openRestartForm: true });
- handleServerRestartClose = () => this.setState({ openRestartForm: false });
+ handleServerRestartClose = () => {
+ this.setState({ openRestartForm: false });
+ };
- removeElementFocus = (event: React.SyntheticEvent<HTMLElement>) => event.currentTarget.blur();
+ removeElementFocus = (event: React.SyntheticEvent<HTMLElement>) => {
+ event.currentTarget.blur();
+ };
render() {
const infoUrl = getBaseUrl() + '/api/system/info';
@@ -85,50 +94,51 @@ export default class PageActions extends React.PureComponent<Props, State> {
<strong className="little-spacer-left">{this.state.logLevel}</strong>
</span>
<EditButton
- id="edit-logs-level-button"
className="spacer-left button-small"
+ id="edit-logs-level-button"
onClick={this.handleLogsLevelOpen}
/>
</span>
{this.props.canDownloadLogs && (
<div className="display-inline-block dropdown spacer-left">
- <button data-toggle="dropdown">
+ {/* TODO use Dropdown component */}
+ <Button data-toggle="dropdown">
{translate('system.download_logs')}
<i className="icon-dropdown little-spacer-left" />
- </button>
+ </Button>
<ul className="dropdown-menu">
<li>
<a
+ download="sonarqube_app.log"
href={logsUrl + '?process=app'}
id="logs-link"
- download="sonarqube_app.log"
target="_blank">
Main Process
</a>
</li>
<li>
<a
+ download="sonarqube_ce.log"
href={logsUrl + '?process=ce'}
id="ce-logs-link"
- download="sonarqube_ce.log"
target="_blank">
Compute Engine
</a>
</li>
<li>
<a
+ download="sonarqube_es.log"
href={logsUrl + '?process=es'}
id="es-logs-link"
- download="sonarqube_es.log"
target="_blank">
Search Engine
</a>
</li>
<li>
<a
+ download="sonarqube_web.log"
href={logsUrl + '?process=web'}
id="web-logs-link"
- download="sonarqube_web.log"
target="_blank">
Web Server
</a>
@@ -137,21 +147,21 @@ export default class PageActions extends React.PureComponent<Props, State> {
</div>
)}
<a
+ className="button spacer-left"
+ download={`sonarqube-support-info-${getFileNameSuffix(this.props.serverId)}.json`}
href={infoUrl}
id="download-link"
- className="button spacer-left"
onClick={this.removeElementFocus}
- download={`sonarqube-support-info-${getFileNameSuffix(this.props.serverId)}.json`}
target="_blank">
{translate('system.download_system_info')}
</a>
{this.props.canRestart && (
- <button
- id="restart-server-button"
+ <Button
className="spacer-left"
+ id="restart-server-button"
onClick={this.handleServerRestartOpen}>
{translate('system.restart_server')}
- </button>
+ </Button>
)}
{this.props.canRestart &&
this.state.openRestartForm && <RestartForm onClose={this.handleServerRestartClose} />}
diff --git a/server/sonar-web/src/main/js/apps/system/components/__tests__/__snapshots__/ChangeLogLevelForm-test.tsx.snap b/server/sonar-web/src/main/js/apps/system/components/__tests__/__snapshots__/ChangeLogLevelForm-test.tsx.snap
index 0c857453ed9..d65fc8d4872 100644
--- a/server/sonar-web/src/main/js/apps/system/components/__tests__/__snapshots__/ChangeLogLevelForm-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/system/components/__tests__/__snapshots__/ChangeLogLevelForm-test.tsx.snap
@@ -93,19 +93,18 @@ exports[`should display some warning messages for non INFO levels 1`] = `
<div
className="modal-foot"
>
- <button
+ <SubmitButton
disabled={false}
id="set-log-level-submit"
>
save
- </button>
- <a
- href="#"
+ </SubmitButton>
+ <ResetButtonLink
id="set-log-level-cancel"
onClick={[Function]}
>
cancel
- </a>
+ </ResetButtonLink>
</div>
</form>
</Modal>
@@ -199,19 +198,18 @@ exports[`should render correctly 1`] = `
<div
className="modal-foot"
>
- <button
+ <SubmitButton
disabled={false}
id="set-log-level-submit"
>
save
- </button>
- <a
- href="#"
+ </SubmitButton>
+ <ResetButtonLink
id="set-log-level-cancel"
onClick={[Function]}
>
cancel
- </a>
+ </ResetButtonLink>
</div>
</form>
</Modal>
diff --git a/server/sonar-web/src/main/js/apps/system/components/__tests__/__snapshots__/PageActions-test.tsx.snap b/server/sonar-web/src/main/js/apps/system/components/__tests__/__snapshots__/PageActions-test.tsx.snap
index dd7d6f39b36..252b7a95398 100644
--- a/server/sonar-web/src/main/js/apps/system/components/__tests__/__snapshots__/PageActions-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/system/components/__tests__/__snapshots__/PageActions-test.tsx.snap
@@ -25,14 +25,14 @@ exports[`should render correctly 1`] = `
<div
className="display-inline-block dropdown spacer-left"
>
- <button
+ <Button
data-toggle="dropdown"
>
system.download_logs
<i
className="icon-dropdown little-spacer-left"
/>
- </button>
+ </Button>
<ul
className="dropdown-menu"
>
@@ -88,13 +88,13 @@ exports[`should render correctly 1`] = `
>
system.download_system_info
</a>
- <button
+ <Button
className="spacer-left"
id="restart-server-button"
onClick={[Function]}
>
system.restart_server
- </button>
+ </Button>
</div>
`;
diff --git a/server/sonar-web/src/main/js/apps/system/components/system-upgrade/SystemUpgradeNotif.tsx b/server/sonar-web/src/main/js/apps/system/components/system-upgrade/SystemUpgradeNotif.tsx
index a39c44965b3..15f4e8a3b10 100644
--- a/server/sonar-web/src/main/js/apps/system/components/system-upgrade/SystemUpgradeNotif.tsx
+++ b/server/sonar-web/src/main/js/apps/system/components/system-upgrade/SystemUpgradeNotif.tsx
@@ -19,9 +19,10 @@
*/
import * as React from 'react';
import SystemUpgradeForm from './SystemUpgradeForm';
+import { sortUpgrades, groupUpgrades } from '../../utils';
import { getSystemUpgrades, SystemUpgrade } from '../../../../api/system';
+import { Button } from '../../../../components/ui/buttons';
import { translate } from '../../../../helpers/l10n';
-import { sortUpgrades, groupUpgrades } from '../../utils';
interface State {
systemUpgrades: SystemUpgrade[][];
@@ -51,8 +52,13 @@ export default class SystemUpgradeNotif extends React.PureComponent<{}, State> {
() => {}
);
- handleOpenSystemUpgradeForm = () => this.setState({ openSystemUpgradeForm: true });
- handleCloseSystemUpgradeForm = () => this.setState({ openSystemUpgradeForm: false });
+ handleOpenSystemUpgradeForm = () => {
+ this.setState({ openSystemUpgradeForm: true });
+ };
+
+ handleCloseSystemUpgradeForm = () => {
+ this.setState({ openSystemUpgradeForm: false });
+ };
render() {
const { systemUpgrades } = this.state;
@@ -65,14 +71,14 @@ export default class SystemUpgradeNotif extends React.PureComponent<{}, State> {
<div className="page-notifs">
<div className="alert alert-info">
{translate('system.new_version_available')}
- <button className="spacer-left" onClick={this.handleOpenSystemUpgradeForm}>
+ <Button className="spacer-left" onClick={this.handleOpenSystemUpgradeForm}>
{translate('learn_more')}
- </button>
+ </Button>
</div>
{this.state.openSystemUpgradeForm && (
<SystemUpgradeForm
- systemUpgrades={systemUpgrades}
onClose={this.handleCloseSystemUpgradeForm}
+ systemUpgrades={systemUpgrades}
/>
)}
</div>
diff --git a/server/sonar-web/src/main/js/apps/system/components/system-upgrade/__tests__/SystemUpgradeNotif-test.tsx b/server/sonar-web/src/main/js/apps/system/components/system-upgrade/__tests__/SystemUpgradeNotif-test.tsx
index 0ae8979a9d7..29d8533cd82 100644
--- a/server/sonar-web/src/main/js/apps/system/components/system-upgrade/__tests__/SystemUpgradeNotif-test.tsx
+++ b/server/sonar-web/src/main/js/apps/system/components/system-upgrade/__tests__/SystemUpgradeNotif-test.tsx
@@ -103,6 +103,6 @@ it('should fetch upgrade when mounting', () => {
it('should open the upgrade form', async () => {
const wrapper = shallow(<SystemUpgradeNotif />);
await waitAndUpdate(wrapper);
- click(wrapper.find('button'));
+ click(wrapper.find('Button'));
expect(wrapper.find('SystemUpgradeForm').exists()).toBeTruthy();
});
diff --git a/server/sonar-web/src/main/js/apps/system/components/system-upgrade/__tests__/__snapshots__/SystemUpgradeNotif-test.tsx.snap b/server/sonar-web/src/main/js/apps/system/components/system-upgrade/__tests__/__snapshots__/SystemUpgradeNotif-test.tsx.snap
index f1b0b865020..50c3d8ee70e 100644
--- a/server/sonar-web/src/main/js/apps/system/components/system-upgrade/__tests__/__snapshots__/SystemUpgradeNotif-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/system/components/system-upgrade/__tests__/__snapshots__/SystemUpgradeNotif-test.tsx.snap
@@ -8,12 +8,12 @@ exports[`should display correctly 1`] = `
className="alert alert-info"
>
system.new_version_available
- <button
+ <Button
className="spacer-left"
onClick={[Function]}
>
learn_more
- </button>
+ </Button>
</div>
</div>
`;
diff --git a/server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/__snapshots__/NewOrganizationForm-test.js.snap b/server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/__snapshots__/NewOrganizationForm-test.js.snap
index 40da82493a8..7694dfc182d 100644
--- a/server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/__snapshots__/NewOrganizationForm-test.js.snap
+++ b/server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/__snapshots__/NewOrganizationForm-test.js.snap
@@ -93,17 +93,29 @@ exports[`creates new organization 3`] = `
color="#d4333f"
onClick={[Function]}
>
- <button
+ <Button
className="button-small button-icon"
onClick={[Function]}
+ stopPropagation={true}
style={
Object {
"color": "#d4333f",
}
}
>
- <ClearIcon />
- </button>
+ <button
+ className="button button-small button-icon"
+ onClick={[Function]}
+ style={
+ Object {
+ "color": "#d4333f",
+ }
+ }
+ type="button"
+ >
+ <ClearIcon />
+ </button>
+ </Button>
</ButtonIcon>
</DeleteButton>
</div>
@@ -130,17 +142,29 @@ exports[`deletes organization 1`] = `
color="#d4333f"
onClick={[Function]}
>
- <button
+ <Button
className="button-small button-icon"
onClick={[Function]}
+ stopPropagation={true}
style={
Object {
"color": "#d4333f",
}
}
>
- <ClearIcon />
- </button>
+ <button
+ className="button button-small button-icon"
+ onClick={[Function]}
+ style={
+ Object {
+ "color": "#d4333f",
+ }
+ }
+ type="button"
+ >
+ <ClearIcon />
+ </button>
+ </Button>
</ButtonIcon>
</DeleteButton>
</div>
diff --git a/server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/__snapshots__/NewProjectForm-test.js.snap b/server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/__snapshots__/NewProjectForm-test.js.snap
index 5f389a66391..a6682fb7870 100644
--- a/server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/__snapshots__/NewProjectForm-test.js.snap
+++ b/server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/__snapshots__/NewProjectForm-test.js.snap
@@ -117,17 +117,29 @@ exports[`creates new project 3`] = `
color="#d4333f"
onClick={[Function]}
>
- <button
+ <Button
className="button-small text-middle button-icon"
onClick={[Function]}
+ stopPropagation={true}
style={
Object {
"color": "#d4333f",
}
}
>
- <ClearIcon />
- </button>
+ <button
+ className="button button-small text-middle button-icon"
+ onClick={[Function]}
+ style={
+ Object {
+ "color": "#d4333f",
+ }
+ }
+ type="button"
+ >
+ <ClearIcon />
+ </button>
+ </Button>
</ButtonIcon>
</DeleteButton>
</div>
@@ -163,17 +175,29 @@ exports[`deletes project 1`] = `
color="#d4333f"
onClick={[Function]}
>
- <button
+ <Button
className="button-small text-middle button-icon"
onClick={[Function]}
+ stopPropagation={true}
style={
Object {
"color": "#d4333f",
}
}
>
- <ClearIcon />
- </button>
+ <button
+ className="button button-small text-middle button-icon"
+ onClick={[Function]}
+ style={
+ Object {
+ "color": "#d4333f",
+ }
+ }
+ type="button"
+ >
+ <ClearIcon />
+ </button>
+ </Button>
</ButtonIcon>
</DeleteButton>
</div>
diff --git a/server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/__snapshots__/TokenStep-test.js.snap b/server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/__snapshots__/TokenStep-test.js.snap
index 332780eddec..86d6f2a627c 100644
--- a/server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/__snapshots__/TokenStep-test.js.snap
+++ b/server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/__snapshots__/TokenStep-test.js.snap
@@ -264,17 +264,29 @@ exports[`generates token 3`] = `
color="#d4333f"
onClick={[Function]}
>
- <button
+ <Button
className="button-small text-middle button-icon"
onClick={[Function]}
+ stopPropagation={true}
style={
Object {
"color": "#d4333f",
}
}
>
- <ClearIcon />
- </button>
+ <button
+ className="button button-small text-middle button-icon"
+ onClick={[Function]}
+ style={
+ Object {
+ "color": "#d4333f",
+ }
+ }
+ type="button"
+ >
+ <ClearIcon />
+ </button>
+ </Button>
</ButtonIcon>
</DeleteButton>
</form>
@@ -362,17 +374,29 @@ exports[`revokes token 1`] = `
color="#d4333f"
onClick={[Function]}
>
- <button
+ <Button
className="button-small text-middle button-icon"
onClick={[Function]}
+ stopPropagation={true}
style={
Object {
"color": "#d4333f",
}
}
>
- <ClearIcon />
- </button>
+ <button
+ className="button button-small text-middle button-icon"
+ onClick={[Function]}
+ style={
+ Object {
+ "color": "#d4333f",
+ }
+ }
+ type="button"
+ >
+ <ClearIcon />
+ </button>
+ </Button>
</ButtonIcon>
</DeleteButton>
</form>
diff --git a/server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/__tests__/__snapshots__/Command-test.js.snap b/server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/__tests__/__snapshots__/Command-test.js.snap
index 2bd0aafd5b8..a7a6a001caa 100644
--- a/server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/__tests__/__snapshots__/Command-test.js.snap
+++ b/server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/__tests__/__snapshots__/Command-test.js.snap
@@ -17,13 +17,22 @@ bar
bar"
tooltipPlacement="top"
>
- <button
+ <Button
className="js-copy-to-clipboard no-select"
data-clipboard-text="foo
bar"
+ innerRef={[Function]}
>
- copy
- </button>
+ <button
+ className="button js-copy-to-clipboard no-select"
+ data-clipboard-text="foo
+bar"
+ onClick={[Function]}
+ type="button"
+ >
+ copy
+ </button>
+ </Button>
</ClipboardButton>
</div>
</Command>
diff --git a/server/sonar-web/src/main/js/apps/users/Header.tsx b/server/sonar-web/src/main/js/apps/users/Header.tsx
index 7131a7eb0f0..65808704194 100644
--- a/server/sonar-web/src/main/js/apps/users/Header.tsx
+++ b/server/sonar-web/src/main/js/apps/users/Header.tsx
@@ -20,6 +20,7 @@
import * as React from 'react';
import UserForm from './components/UserForm';
import DeferredSpinner from '../../components/common/DeferredSpinner';
+import { Button } from '../../components/ui/buttons';
import { translate } from '../../helpers/l10n';
interface Props {
@@ -34,19 +35,24 @@ interface State {
export default class Header extends React.PureComponent<Props, State> {
state: State = { openUserForm: false };
- handleOpenUserForm = () => this.setState({ openUserForm: true });
- handleCloseUserForm = () => this.setState({ openUserForm: false });
+ handleOpenUserForm = () => {
+ this.setState({ openUserForm: true });
+ };
+
+ handleCloseUserForm = () => {
+ this.setState({ openUserForm: false });
+ };
render() {
return (
- <header id="users-header" className="page-header">
+ <header className="page-header" id="users-header">
<h1 className="page-title">{translate('users.page')}</h1>
<DeferredSpinner loading={this.props.loading} />
<div className="page-actions">
- <button id="users-create" onClick={this.handleOpenUserForm}>
+ <Button id="users-create" onClick={this.handleOpenUserForm}>
{translate('users.create_user')}
- </button>
+ </Button>
</div>
<p className="page-description">{translate('users.page.description')}</p>
diff --git a/server/sonar-web/src/main/js/apps/users/__tests__/__snapshots__/Header-test.tsx.snap b/server/sonar-web/src/main/js/apps/users/__tests__/__snapshots__/Header-test.tsx.snap
index 6e38124302c..7acecae4f39 100644
--- a/server/sonar-web/src/main/js/apps/users/__tests__/__snapshots__/Header-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/users/__tests__/__snapshots__/Header-test.tsx.snap
@@ -17,12 +17,12 @@ exports[`should render correctly 1`] = `
<div
className="page-actions"
>
- <button
+ <Button
id="users-create"
onClick={[Function]}
>
users.create_user
- </button>
+ </Button>
</div>
<p
className="page-description"
diff --git a/server/sonar-web/src/main/js/apps/users/components/DeactivateForm.tsx b/server/sonar-web/src/main/js/apps/users/components/DeactivateForm.tsx
index 7b34c4c3fc8..062a463d444 100644
--- a/server/sonar-web/src/main/js/apps/users/components/DeactivateForm.tsx
+++ b/server/sonar-web/src/main/js/apps/users/components/DeactivateForm.tsx
@@ -18,9 +18,10 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import * as React from 'react';
-import Modal from '../../../components/controls/Modal';
import { deactivateUser } from '../../../api/users';
import { User } from '../../../app/types';
+import Modal from '../../../components/controls/Modal';
+import { SubmitButton, ResetButtonLink } from '../../../components/ui/buttons';
import { translate, translateWithParameters } from '../../../helpers/l10n';
export interface Props {
@@ -45,11 +46,6 @@ export default class DeactivateForm extends React.PureComponent<Props, State> {
this.mounted = false;
}
- handleCancelClick = (event: React.SyntheticEvent<HTMLAnchorElement>) => {
- event.preventDefault();
- this.props.onClose();
- };
-
handleDeactivate = (event: React.SyntheticEvent<HTMLFormElement>) => {
event.preventDefault();
this.setState({ submitting: true });
@@ -73,7 +69,7 @@ export default class DeactivateForm extends React.PureComponent<Props, State> {
const header = translate('users.deactivate_user');
return (
<Modal contentLabel={header} onRequestClose={this.props.onClose}>
- <form id="deactivate-user-form" onSubmit={this.handleDeactivate} autoComplete="off">
+ <form autoComplete="off" id="deactivate-user-form" onSubmit={this.handleDeactivate}>
<header className="modal-head">
<h2>{header}</h2>
</header>
@@ -82,12 +78,12 @@ export default class DeactivateForm extends React.PureComponent<Props, State> {
</div>
<footer className="modal-foot">
{submitting && <i className="spinner spacer-right" />}
- <button className="js-confirm button-red" disabled={submitting} type="submit">
+ <SubmitButton className="js-confirm button-red" disabled={submitting}>
{translate('users.deactivate')}
- </button>
- <a className="js-modal-close" href="#" onClick={this.handleCancelClick}>
+ </SubmitButton>
+ <ResetButtonLink className="js-modal-close" onClick={this.props.onClose}>
{translate('cancel')}
- </a>
+ </ResetButtonLink>
</footer>
</form>
</Modal>
diff --git a/server/sonar-web/src/main/js/apps/users/components/PasswordForm.tsx b/server/sonar-web/src/main/js/apps/users/components/PasswordForm.tsx
index 675b42761ce..00872246c35 100644
--- a/server/sonar-web/src/main/js/apps/users/components/PasswordForm.tsx
+++ b/server/sonar-web/src/main/js/apps/users/components/PasswordForm.tsx
@@ -18,13 +18,14 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import * as React from 'react';
-import Modal from '../../../components/controls/Modal';
+import { changePassword } from '../../../api/users';
+import { User } from '../../../app/types';
import addGlobalSuccessMessage from '../../../app/utils/addGlobalSuccessMessage';
import throwGlobalError from '../../../app/utils/throwGlobalError';
-import { User } from '../../../app/types';
-import { parseError } from '../../../helpers/request';
-import { changePassword } from '../../../api/users';
+import Modal from '../../../components/controls/Modal';
+import { SubmitButton, ResetButtonLink } from '../../../components/ui/buttons';
import { translate } from '../../../helpers/l10n';
+import { parseError } from '../../../helpers/request';
interface Props {
isCurrentUser: boolean;
@@ -77,11 +78,6 @@ export default class PasswordForm extends React.PureComponent<Props, State> {
handleOldPasswordChange = (event: React.SyntheticEvent<HTMLInputElement>) =>
this.setState({ oldPassword: event.currentTarget.value });
- handleCancelClick = (event: React.SyntheticEvent<HTMLAnchorElement>) => {
- event.preventDefault();
- this.props.onClose();
- };
-
handleChangePassword = (event: React.SyntheticEvent<HTMLFormElement>) => {
event.preventDefault();
if (
@@ -106,7 +102,7 @@ export default class PasswordForm extends React.PureComponent<Props, State> {
const header = translate('my_profile.password.title');
return (
<Modal contentLabel={header} onRequestClose={this.props.onClose}>
- <form id="user-password-form" onSubmit={this.handleChangePassword} autoComplete="off">
+ <form autoComplete="off" id="user-password-form" onSubmit={this.handleChangePassword}>
<header className="modal-head">
<h2>{header}</h2>
</header>
@@ -119,14 +115,14 @@ export default class PasswordForm extends React.PureComponent<Props, State> {
<em className="mandatory">*</em>
</label>
{/* keep this fake field to hack browser autofill */}
- <input name="old-password-fake" type="password" className="hidden" />
+ <input className="hidden" name="old-password-fake" type="password" />
<input
id="old-user-password"
- name="old-password"
- type="password"
maxLength={50}
+ name="old-password"
onChange={this.handleOldPasswordChange}
required={true}
+ type="password"
value={this.state.oldPassword}
/>
</div>
@@ -137,14 +133,14 @@ export default class PasswordForm extends React.PureComponent<Props, State> {
<em className="mandatory">*</em>
</label>
{/* keep this fake field to hack browser autofill */}
- <input name="password-fake" type="password" className="hidden" />
+ <input className="hidden" name="password-fake" type="password" />
<input
id="user-password"
- name="password"
- type="password"
maxLength={50}
+ name="password"
onChange={this.handleNewPasswordChange}
required={true}
+ type="password"
value={this.state.newPassword}
/>
</div>
@@ -154,29 +150,28 @@ export default class PasswordForm extends React.PureComponent<Props, State> {
<em className="mandatory">*</em>
</label>
{/* keep this fake field to hack browser autofill */}
- <input name="confirm-password-fake" type="password" className="hidden" />
+ <input className="hidden" name="confirm-password-fake" type="password" />
<input
id="confirm-user-password"
- name="confirm-password"
- type="password"
maxLength={50}
+ name="confirm-password"
onChange={this.handleConfirmPasswordChange}
required={true}
+ type="password"
value={this.state.confirmPassword}
/>
</div>
</div>
<footer className="modal-foot">
{submitting && <i className="spinner spacer-right" />}
- <button
+ <SubmitButton
className="js-confirm"
- disabled={submitting || !newPassword || newPassword !== confirmPassword}
- type="submit">
+ disabled={submitting || !newPassword || newPassword !== confirmPassword}>
{translate('change_verb')}
- </button>
- <a className="js-modal-close" href="#" onClick={this.handleCancelClick}>
+ </SubmitButton>
+ <ResetButtonLink className="js-modal-close" onClick={this.props.onClose}>
{translate('cancel')}
- </a>
+ </ResetButtonLink>
</footer>
</form>
</Modal>
diff --git a/server/sonar-web/src/main/js/apps/users/components/TokensForm.tsx b/server/sonar-web/src/main/js/apps/users/components/TokensForm.tsx
index 0869b13fbaf..98d6c1e234e 100644
--- a/server/sonar-web/src/main/js/apps/users/components/TokensForm.tsx
+++ b/server/sonar-web/src/main/js/apps/users/components/TokensForm.tsx
@@ -20,8 +20,9 @@
import * as React from 'react';
import TokensFormItem from './TokensFormItem';
import TokensFormNewToken from './TokensFormNewToken';
-import DeferredSpinner from '../../../components/common/DeferredSpinner';
import { getTokens, generateToken, UserToken } from '../../../api/user-tokens';
+import DeferredSpinner from '../../../components/common/DeferredSpinner';
+import { SubmitButton } from '../../../components/ui/buttons';
import { translate } from '../../../helpers/l10n';
interface Props {
@@ -119,7 +120,7 @@ export default class TokensForm extends React.PureComponent<Props, State> {
if (tokens.length <= 0) {
return (
<tr>
- <td colSpan={3} className="note">
+ <td className="note" colSpan={3}>
{translate('users.no_tokens')}
</td>
</tr>
@@ -129,8 +130,8 @@ export default class TokensForm extends React.PureComponent<Props, State> {
<TokensFormItem
key={token.name}
login={this.props.login}
- token={token}
onRevokeToken={this.handleRevokeToken}
+ token={token}
/>
));
}
@@ -147,22 +148,21 @@ export default class TokensForm extends React.PureComponent<Props, State> {
return (
<>
<h3 className="spacer-bottom">{translate('users.generate_tokens')}</h3>
- <form id="generate-token-form" onSubmit={this.handleGenerateToken} autoComplete="off">
+ <form autoComplete="off" id="generate-token-form" onSubmit={this.handleGenerateToken}>
<input
className="spacer-right"
- type="text"
maxLength={100}
onChange={this.handleNewTokenChange}
placeholder={translate('users.enter_token_name')}
required={true}
+ type="text"
value={newTokenName}
/>
- <button
+ <SubmitButton
className="js-generate-token"
- disabled={generating || newTokenName.length <= 0}
- type="submit">
+ disabled={generating || newTokenName.length <= 0}>
{translate('users.generate')}
- </button>
+ </SubmitButton>
</form>
{newToken && <TokensFormNewToken token={newToken} />}
diff --git a/server/sonar-web/src/main/js/apps/users/components/TokensFormItem.tsx b/server/sonar-web/src/main/js/apps/users/components/TokensFormItem.tsx
index ab1a4902aa7..fb48879e3b5 100644
--- a/server/sonar-web/src/main/js/apps/users/components/TokensFormItem.tsx
+++ b/server/sonar-web/src/main/js/apps/users/components/TokensFormItem.tsx
@@ -18,12 +18,13 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import * as React from 'react';
+import { revokeToken, UserToken } from '../../../api/user-tokens';
+import DeferredSpinner from '../../../components/common/DeferredSpinner';
import Tooltip from '../../../components/controls/Tooltip';
import DateFormatter from '../../../components/intl/DateFormatter';
-import DeferredSpinner from '../../../components/common/DeferredSpinner';
-import { revokeToken, UserToken } from '../../../api/user-tokens';
-import { limitComponentName } from '../../../helpers/path';
+import { Button } from '../../../components/ui/buttons';
import { translate } from '../../../helpers/l10n';
+import { limitComponentName } from '../../../helpers/path';
interface Props {
login: string;
@@ -81,14 +82,14 @@ export default class TokensFormItem extends React.PureComponent<Props, State> {
<DeferredSpinner loading={loading}>
<i className="spinner-placeholder " />
</DeferredSpinner>
- <button
+ <Button
className="button-red input-small spacer-left"
- onClick={this.handleRevoke}
- disabled={loading}>
+ disabled={loading}
+ onClick={this.handleRevoke}>
{this.state.deleting
? translate('users.tokens.sure')
: translate('users.tokens.revoke')}
- </button>
+ </Button>
</td>
</tr>
);
diff --git a/server/sonar-web/src/main/js/apps/users/components/UserForm.tsx b/server/sonar-web/src/main/js/apps/users/components/UserForm.tsx
index 6aae2138038..95ccccce126 100644
--- a/server/sonar-web/src/main/js/apps/users/components/UserForm.tsx
+++ b/server/sonar-web/src/main/js/apps/users/components/UserForm.tsx
@@ -20,12 +20,13 @@
import * as React from 'react';
import { uniq } from 'lodash';
import UserScmAccountInput from './UserScmAccountInput';
-import Modal from '../../../components/controls/Modal';
-import throwGlobalError from '../../../app/utils/throwGlobalError';
-import { parseError } from '../../../helpers/request';
import { createUser, updateUser } from '../../../api/users';
import { User } from '../../../app/types';
+import throwGlobalError from '../../../app/utils/throwGlobalError';
+import Modal from '../../../components/controls/Modal';
+import { Button, SubmitButton, ResetButtonLink } from '../../../components/ui/buttons';
import { translate, translateWithParameters } from '../../../helpers/l10n';
+import { parseError } from '../../../helpers/request';
export interface Props {
user?: User;
@@ -101,11 +102,6 @@ export default class UserForm extends React.PureComponent<Props, State> {
handlePasswordChange = (event: React.SyntheticEvent<HTMLInputElement>) =>
this.setState({ password: event.currentTarget.value });
- handleCancelClick = (event: React.SyntheticEvent<HTMLAnchorElement>) => {
- event.preventDefault();
- this.props.onClose();
- };
-
handleCreateUser = (event: React.SyntheticEvent<HTMLFormElement>) => {
event.preventDefault();
this.setState({ submitting: true });
@@ -135,8 +131,7 @@ export default class UserForm extends React.PureComponent<Props, State> {
}, this.handleError);
};
- handleAddScmAccount = (evt: React.SyntheticEvent<HTMLButtonElement>) => {
- evt.preventDefault();
+ handleAddScmAccount = () => {
this.setState(({ scmAccounts }) => ({ scmAccounts: scmAccounts.concat('') }));
};
@@ -160,9 +155,9 @@ export default class UserForm extends React.PureComponent<Props, State> {
return (
<Modal contentLabel={header} onRequestClose={this.props.onClose}>
<form
+ autoComplete="off"
id="user-form"
- onSubmit={this.props.user ? this.handleUpdateUser : this.handleCreateUser}
- autoComplete="off">
+ onSubmit={this.props.user ? this.handleUpdateUser : this.handleCreateUser}>
<header className="modal-head">
<h2>{header}</h2>
</header>
@@ -177,15 +172,15 @@ export default class UserForm extends React.PureComponent<Props, State> {
<em className="mandatory">*</em>
</label>
{/* keep this fake field to hack browser autofill */}
- <input name="login-fake" type="text" className="hidden" />
+ <input className="hidden" name="login-fake" type="text" />
<input
id="create-user-login"
- name="login"
- type="text"
- minLength={3}
maxLength={255}
+ minLength={3}
+ name="login"
onChange={this.handleLoginChange}
required={true}
+ type="text"
value={this.state.login}
/>
<p className="note">{translateWithParameters('users.minimum_x_characters', 3)}</p>
@@ -197,27 +192,27 @@ export default class UserForm extends React.PureComponent<Props, State> {
<em className="mandatory">*</em>
</label>
{/* keep this fake field to hack browser autofill */}
- <input name="name-fake" type="text" className="hidden" />
+ <input className="hidden" name="name-fake" type="text" />
<input
id="create-user-name"
- name="name"
- type="text"
maxLength={200}
+ name="name"
onChange={this.handleNameChange}
required={true}
+ type="text"
value={this.state.name}
/>
</div>
<div className="modal-field">
<label htmlFor="create-user-email">{translate('users.email')}</label>
{/* keep this fake field to hack browser autofill */}
- <input name="email-fake" type="email" className="hidden" />
+ <input className="hidden" name="email-fake" type="email" />
<input
id="create-user-email"
- name="email"
- type="email"
maxLength={100}
+ name="email"
onChange={this.handleEmailChange}
+ type="email"
value={this.state.email}
/>
</div>
@@ -228,14 +223,14 @@ export default class UserForm extends React.PureComponent<Props, State> {
<em className="mandatory">*</em>
</label>
{/* keep this fake field to hack browser autofill */}
- <input name="password-fake" type="password" className="hidden" />
+ <input className="hidden" name="password-fake" type="password" />
<input
id="create-user-password"
- name="password"
- type="password"
maxLength={50}
+ name="password"
onChange={this.handlePasswordChange}
required={true}
+ type="password"
value={this.state.password}
/>
</div>
@@ -252,7 +247,9 @@ export default class UserForm extends React.PureComponent<Props, State> {
/>
))}
<div className="spacer-bottom">
- <button onClick={this.handleAddScmAccount}>{translate('add_verb')}</button>
+ <Button onClick={this.handleAddScmAccount} type="reset">
+ {translate('add_verb')}
+ </Button>
</div>
<p className="note">{translate('user.login_or_email_used_as_scm_account')}</p>
</div>
@@ -260,12 +257,12 @@ export default class UserForm extends React.PureComponent<Props, State> {
<footer className="modal-foot">
{submitting && <i className="spinner spacer-right" />}
- <button className="js-confirm" disabled={submitting} type="submit">
+ <SubmitButton className="js-confirm" disabled={submitting}>
{user ? translate('update_verb') : translate('create')}
- </button>
- <a className="js-modal-close" href="#" onClick={this.handleCancelClick}>
+ </SubmitButton>
+ <ResetButtonLink className="js-modal-close" onClick={this.props.onClose}>
{translate('cancel')}
- </a>
+ </ResetButtonLink>
</footer>
</form>
</Modal>
diff --git a/server/sonar-web/src/main/js/components/common/FiltersHeader.tsx b/server/sonar-web/src/main/js/components/common/FiltersHeader.tsx
index 33567469928..6d643c45df7 100644
--- a/server/sonar-web/src/main/js/components/common/FiltersHeader.tsx
+++ b/server/sonar-web/src/main/js/components/common/FiltersHeader.tsx
@@ -18,6 +18,7 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import * as React from 'react';
+import { Button } from '../ui/buttons';
import { translate } from '../../helpers/l10n';
interface Props {
@@ -25,29 +26,18 @@ interface Props {
onReset: () => void;
}
-export default class FiltersHeader extends React.PureComponent<Props> {
- handleResetClick = (event: React.SyntheticEvent<HTMLButtonElement>) => {
- event.preventDefault();
- event.currentTarget.blur();
- this.props.onReset();
- };
+export default function FiltersHeader({ displayReset, onReset }: Props) {
+ return (
+ <div className="search-navigator-filters-header">
+ {displayReset && (
+ <div className="pull-right">
+ <Button className="button-red" id="coding-rules-clear-all-filters" onClick={onReset}>
+ {translate('clear_all_filters')}
+ </Button>
+ </div>
+ )}
- render() {
- return (
- <div className="search-navigator-filters-header">
- {this.props.displayReset && (
- <div className="pull-right">
- <button
- className="button-red"
- id="coding-rules-clear-all-filters"
- onClick={this.handleResetClick}>
- {translate('clear_all_filters')}
- </button>
- </div>
- )}
-
- <h3>{translate('filters')}</h3>
- </div>
- );
- }
+ <h3>{translate('filters')}</h3>
+ </div>
+ );
}
diff --git a/server/sonar-web/src/main/js/components/common/RestartForm.tsx b/server/sonar-web/src/main/js/components/common/RestartForm.tsx
index 54b694ef5cb..eb4f31f7cfb 100644
--- a/server/sonar-web/src/main/js/components/common/RestartForm.tsx
+++ b/server/sonar-web/src/main/js/components/common/RestartForm.tsx
@@ -21,6 +21,7 @@ import * as React from 'react';
import * as classNames from 'classnames';
import { restartAndWait } from '../../api/system';
import Modal from '../../components/controls/Modal';
+import { SubmitButton, ResetButtonLink } from '../ui/buttons';
import { translate } from '../../helpers/l10n';
interface Props {
@@ -34,11 +35,6 @@ interface State {
export default class RestartForm extends React.PureComponent<Props, State> {
state: State = { restarting: false };
- handleCancelClick = (event: React.SyntheticEvent<HTMLElement>) => {
- event.preventDefault();
- this.props.onClose();
- };
-
handleFormSubmit = (event: React.SyntheticEvent<HTMLFormElement>) => {
event.preventDefault();
if (!this.state.restarting) {
@@ -71,14 +67,13 @@ export default class RestartForm extends React.PureComponent<Props, State> {
</div>
{!restarting && (
<div className="modal-foot">
- <button id="restart-server-submit">{translate('restart')}</button>
- <a
- href="#"
+ <SubmitButton id="restart-server-submit">{translate('restart')}</SubmitButton>
+ <ResetButtonLink
className="js-modal-close"
id="restart-server-cancel"
- onClick={this.handleCancelClick}>
+ onClick={this.props.onClose}>
{translate('cancel')}
- </a>
+ </ResetButtonLink>
</div>
)}
</form>
diff --git a/server/sonar-web/src/main/js/components/controls/ActionsDropdown.tsx b/server/sonar-web/src/main/js/components/controls/ActionsDropdown.tsx
index 39ad938beee..a20842524a6 100644
--- a/server/sonar-web/src/main/js/components/controls/ActionsDropdown.tsx
+++ b/server/sonar-web/src/main/js/components/controls/ActionsDropdown.tsx
@@ -22,6 +22,7 @@ import * as classNames from 'classnames';
import { Link } from 'react-router';
import { LocationDescriptor } from 'history';
import SettingsIcon from '../icons-components/SettingsIcon';
+import { Button } from '../ui/buttons';
interface Props {
className?: string;
@@ -37,7 +38,7 @@ interface Props {
export default function ActionsDropdown({ menuPosition = 'right', ...props }: Props) {
return (
<div className={classNames('dropdown', props.className)}>
- <button
+ <Button
className={classNames('dropdown-toggle', props.toggleClassName, {
'button-small': props.small
})}
@@ -45,7 +46,7 @@ export default function ActionsDropdown({ menuPosition = 'right', ...props }: Pr
onClick={props.onToggleClick}>
<SettingsIcon className="text-text-bottom" />
<i className="icon-dropdown little-spacer-left" />
- </button>
+ </Button>
<ul
className={classNames('dropdown-menu', props.menuClassName, {
'dropdown-menu-right': menuPosition === 'right'
diff --git a/server/sonar-web/src/main/js/components/controls/ClipboardButton.tsx b/server/sonar-web/src/main/js/components/controls/ClipboardButton.tsx
index e7d0ed049f9..6969fc0271f 100644
--- a/server/sonar-web/src/main/js/components/controls/ClipboardButton.tsx
+++ b/server/sonar-web/src/main/js/components/controls/ClipboardButton.tsx
@@ -21,6 +21,7 @@ import * as React from 'react';
import * as classNames from 'classnames';
import * as Clipboard from 'clipboard';
import Tooltip from './Tooltip';
+import { Button } from '../ui/buttons';
import { translate } from '../../helpers/l10n';
interface Props {
@@ -35,7 +36,7 @@ interface State {
export default class ClipboardButton extends React.PureComponent<Props, State> {
clipboard?: Clipboard;
- copyButton?: HTMLButtonElement | null;
+ copyButton?: HTMLElement | null;
mounted = false;
state: State = { tooltipShown: false };
@@ -77,19 +78,19 @@ export default class ClipboardButton extends React.PureComponent<Props, State> {
render() {
const button = (
- <button
+ <Button
className={classNames('js-copy-to-clipboard no-select', this.props.className)}
data-clipboard-text={this.props.copyValue}
- ref={node => (this.copyButton = node)}>
+ innerRef={node => (this.copyButton = node)}>
{translate('copy')}
- </button>
+ </Button>
);
if (this.state.tooltipShown) {
return (
<Tooltip
defaultVisible={true}
- placement={this.props.tooltipPlacement || 'bottom'}
overlay={translate('copied_action')}
+ placement={this.props.tooltipPlacement || 'bottom'}
trigger="manual">
{button}
</Tooltip>
diff --git a/server/sonar-web/src/main/js/components/controls/ConfirmButton.tsx b/server/sonar-web/src/main/js/components/controls/ConfirmButton.tsx
index 54934d9e8ac..0f05db2ac90 100644
--- a/server/sonar-web/src/main/js/components/controls/ConfirmButton.tsx
+++ b/server/sonar-web/src/main/js/components/controls/ConfirmButton.tsx
@@ -21,11 +21,10 @@ import * as React from 'react';
import SimpleModal from './SimpleModal';
import DeferredSpinner from '../common/DeferredSpinner';
import { translate } from '../../helpers/l10n';
+import { SubmitButton, ResetButtonLink } from '../ui/buttons';
interface Props {
- children: (
- props: { onClick: (event?: React.SyntheticEvent<HTMLButtonElement>) => void }
- ) => React.ReactNode;
+ children: (props: { onClick: () => void }) => React.ReactNode;
confirmButtonText: string;
confirmData?: string;
isDestructive?: boolean;
@@ -50,11 +49,7 @@ export default class ConfirmButton extends React.PureComponent<Props, State> {
this.mounted = false;
}
- handleButtonClick = (event?: React.SyntheticEvent<HTMLButtonElement>) => {
- if (event) {
- event.preventDefault();
- event.currentTarget.blur();
- }
+ handleButtonClick = () => {
this.setState({ modal: true });
};
@@ -85,8 +80,8 @@ export default class ConfirmButton extends React.PureComponent<Props, State> {
header={modalHeader}
onClose={this.handleCloseModal}
onSubmit={this.handleSubmit}>
- {({ onCloseClick, onSubmitClick, submitting }) => (
- <>
+ {({ onCloseClick, onFormSubmit, submitting }) => (
+ <form onSubmit={onFormSubmit}>
<header className="modal-head">
<h2>{modalHeader}</h2>
</header>
@@ -95,17 +90,14 @@ export default class ConfirmButton extends React.PureComponent<Props, State> {
<footer className="modal-foot">
<DeferredSpinner className="spacer-right" loading={submitting} />
- <button
+ <SubmitButton
className={isDestructive ? 'button-red' : undefined}
- disabled={submitting}
- onClick={onSubmitClick}>
+ disabled={submitting}>
{confirmButtonText}
- </button>
- <a href="#" onClick={onCloseClick}>
- {translate('cancel')}
- </a>
+ </SubmitButton>
+ <ResetButtonLink onClick={onCloseClick}>{translate('cancel')}</ResetButtonLink>
</footer>
- </>
+ </form>
)}
</SimpleModal>
)}
diff --git a/server/sonar-web/src/main/js/components/controls/Dropdown.tsx b/server/sonar-web/src/main/js/components/controls/Dropdown.tsx
index 1022dc7fc02..3b82fd1c408 100644
--- a/server/sonar-web/src/main/js/components/controls/Dropdown.tsx
+++ b/server/sonar-web/src/main/js/components/controls/Dropdown.tsx
@@ -21,7 +21,7 @@ import * as React from 'react';
interface RenderProps {
closeDropdown: () => void;
- onToggleClick: (event: React.SyntheticEvent<HTMLElement>) => void;
+ onToggleClick: (event?: React.SyntheticEvent<HTMLElement>) => void;
open: boolean;
}
@@ -75,10 +75,12 @@ export default class Dropdown extends React.PureComponent<Props, State> {
closeDropdown = () => this.setState({ open: false });
- handleToggleClick = (event: React.SyntheticEvent<HTMLElement>) => {
- this.toggleNode = event.currentTarget;
- event.preventDefault();
- event.currentTarget.blur();
+ handleToggleClick = (event?: React.SyntheticEvent<HTMLElement>) => {
+ if (event) {
+ this.toggleNode = event.currentTarget;
+ event.preventDefault();
+ event.currentTarget.blur();
+ }
this.setState(state => ({ open: !state.open }));
};
diff --git a/server/sonar-web/src/main/js/components/controls/SimpleModal.tsx b/server/sonar-web/src/main/js/components/controls/SimpleModal.tsx
index b277510245d..e85d13031ed 100644
--- a/server/sonar-web/src/main/js/components/controls/SimpleModal.tsx
+++ b/server/sonar-web/src/main/js/components/controls/SimpleModal.tsx
@@ -21,9 +21,9 @@ import * as React from 'react';
import Modal from '../../components/controls/Modal';
export interface ChildrenProps {
- onCloseClick: (event: React.SyntheticEvent<HTMLElement>) => void;
+ onCloseClick: (event?: React.SyntheticEvent<HTMLElement>) => void;
onFormSubmit: (event: React.SyntheticEvent<HTMLFormElement>) => void;
- onSubmitClick: (event: React.SyntheticEvent<HTMLElement>) => void;
+ onSubmitClick: (event?: React.SyntheticEvent<HTMLElement>) => void;
submitting: boolean;
}
@@ -56,9 +56,11 @@ export default class SimpleModal extends React.PureComponent<Props, State> {
}
};
- handleCloseClick = (event: React.SyntheticEvent<HTMLElement>) => {
- event.preventDefault();
- event.currentTarget.blur();
+ handleCloseClick = (event?: React.SyntheticEvent<HTMLElement>) => {
+ if (event) {
+ event.preventDefault();
+ event.currentTarget.blur();
+ }
this.props.onClose();
};
@@ -67,9 +69,11 @@ export default class SimpleModal extends React.PureComponent<Props, State> {
this.submit();
};
- handleSubmitClick = (event: React.SyntheticEvent<HTMLElement>) => {
- event.preventDefault();
- event.currentTarget.blur();
+ handleSubmitClick = (event?: React.SyntheticEvent<HTMLElement>) => {
+ if (event) {
+ event.preventDefault();
+ event.currentTarget.blur();
+ }
this.submit();
};
diff --git a/server/sonar-web/src/main/js/components/controls/__tests__/Dropdown-test.tsx b/server/sonar-web/src/main/js/components/controls/__tests__/Dropdown-test.tsx
index 84653beb24e..096dc8356ba 100644
--- a/server/sonar-web/src/main/js/components/controls/__tests__/Dropdown-test.tsx
+++ b/server/sonar-web/src/main/js/components/controls/__tests__/Dropdown-test.tsx
@@ -20,6 +20,7 @@
import * as React from 'react';
import { shallow } from 'enzyme';
import Dropdown from '../Dropdown';
+import { Button } from '../../ui/buttons';
import { click } from '../../../helpers/testUtils';
it('renders', () => {
@@ -32,13 +33,13 @@ it('renders', () => {
it('toggles', () => {
const wrapper = shallow(
- <Dropdown>{({ onToggleClick }) => <button onClick={onToggleClick} />}</Dropdown>
+ <Dropdown>{({ onToggleClick }) => <Button onClick={onToggleClick} />}</Dropdown>
);
expect(wrapper.state()).toEqual({ open: false });
- click(wrapper.find('button'));
+ click(wrapper.find('Button'));
expect(wrapper.state()).toEqual({ open: true });
- click(wrapper.find('button'));
+ click(wrapper.find('Button'));
expect(wrapper.state()).toEqual({ open: false });
});
diff --git a/server/sonar-web/src/main/js/components/controls/__tests__/SimpleModal-test.tsx b/server/sonar-web/src/main/js/components/controls/__tests__/SimpleModal-test.tsx
index c4ea074996c..dd07b347bb1 100644
--- a/server/sonar-web/src/main/js/components/controls/__tests__/SimpleModal-test.tsx
+++ b/server/sonar-web/src/main/js/components/controls/__tests__/SimpleModal-test.tsx
@@ -20,6 +20,7 @@
import * as React from 'react';
import { shallow } from 'enzyme';
import SimpleModal, { ChildrenProps } from '../SimpleModal';
+import { Button } from '../../ui/buttons';
import { click, waitAndUpdate } from '../../../helpers/testUtils';
it('renders', () => {
@@ -35,22 +36,22 @@ it('renders', () => {
it('closes', () => {
const onClose = jest.fn();
- const inner = ({ onCloseClick }: ChildrenProps) => <button onClick={onCloseClick}>close</button>;
+ const inner = ({ onCloseClick }: ChildrenProps) => <Button onClick={onCloseClick}>close</Button>;
const wrapper = shallow(
<SimpleModal header="" onClose={onClose} onSubmit={jest.fn()}>
{inner}
</SimpleModal>
);
- click(wrapper.find('button'));
+ click(wrapper.find('Button'));
expect(onClose).toBeCalled();
});
it('submits', async () => {
const onSubmit = jest.fn(() => Promise.resolve());
const inner = ({ onSubmitClick, submitting }: ChildrenProps) => (
- <button disabled={submitting} onClick={onSubmitClick}>
+ <Button disabled={submitting} onClick={onSubmitClick}>
close
- </button>
+ </Button>
);
const wrapper = shallow(
<SimpleModal header="" onClose={jest.fn()} onSubmit={onSubmit}>
@@ -60,7 +61,7 @@ it('submits', async () => {
(wrapper.instance() as SimpleModal).mounted = true;
expect(wrapper).toMatchSnapshot();
- click(wrapper.find('button'));
+ click(wrapper.find('Button'));
expect(onSubmit).toBeCalled();
expect(wrapper).toMatchSnapshot();
diff --git a/server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/ClipboardButton-test.tsx.snap b/server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/ClipboardButton-test.tsx.snap
index 61870f73365..4ad6724747b 100644
--- a/server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/ClipboardButton-test.tsx.snap
+++ b/server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/ClipboardButton-test.tsx.snap
@@ -1,12 +1,13 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`should display correctly 1`] = `
-<button
+<Button
className="js-copy-to-clipboard no-select"
data-clipboard-text="foo"
+ innerRef={[Function]}
>
copy
-</button>
+</Button>
`;
exports[`should display correctly 2`] = `
@@ -16,11 +17,12 @@ exports[`should display correctly 2`] = `
placement="bottom"
trigger="manual"
>
- <button
+ <Button
className="js-copy-to-clipboard no-select"
data-clipboard-text="foo"
+ innerRef={[Function]}
>
copy
- </button>
+ </Button>
</Tooltip>
`;
diff --git a/server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/SimpleModal-test.tsx.snap b/server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/SimpleModal-test.tsx.snap
index 359048021d7..49b14a9e20f 100644
--- a/server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/SimpleModal-test.tsx.snap
+++ b/server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/SimpleModal-test.tsx.snap
@@ -14,12 +14,12 @@ exports[`submits 1`] = `
contentLabel=""
onRequestClose={[MockFunction]}
>
- <button
+ <Button
disabled={false}
onClick={[Function]}
>
close
- </button>
+ </Button>
</Modal>
`;
@@ -28,12 +28,12 @@ exports[`submits 2`] = `
contentLabel=""
onRequestClose={[MockFunction]}
>
- <button
+ <Button
disabled={true}
onClick={[Function]}
>
close
- </button>
+ </Button>
</Modal>
`;
@@ -42,11 +42,11 @@ exports[`submits 3`] = `
contentLabel=""
onRequestClose={[MockFunction]}
>
- <button
+ <Button
disabled={false}
onClick={[Function]}
>
close
- </button>
+ </Button>
</Modal>
`;
diff --git a/server/sonar-web/src/main/js/components/facet/FacetHeader.tsx b/server/sonar-web/src/main/js/components/facet/FacetHeader.tsx
index cfe3f068bc4..f1394dba898 100644
--- a/server/sonar-web/src/main/js/components/facet/FacetHeader.tsx
+++ b/server/sonar-web/src/main/js/components/facet/FacetHeader.tsx
@@ -21,6 +21,7 @@ import * as React from 'react';
import OpenCloseIcon from '../icons-components/OpenCloseIcon';
import HelpIcon from '../icons-components/HelpIcon';
import Tooltip from '../controls/Tooltip';
+import { Button } from '../ui/buttons';
import { translate, translateWithParameters } from '../../helpers/l10n';
interface Props {
@@ -33,14 +34,6 @@ interface Props {
}
export default class FacetHeader extends React.PureComponent<Props> {
- handleClearClick = (event: React.SyntheticEvent<HTMLButtonElement>) => {
- event.preventDefault();
- event.currentTarget.blur();
- if (this.props.onClear) {
- this.props.onClear();
- }
- };
-
handleClick = (event: React.SyntheticEvent<HTMLAnchorElement>) => {
event.preventDefault();
event.currentTarget.blur();
@@ -102,11 +95,11 @@ export default class FacetHeader extends React.PureComponent<Props> {
</span>
{showClearButton && (
- <button
+ <Button
className="search-navigator-facet-header-button button-small button-red"
- onClick={this.handleClearClick}>
+ onClick={this.props.onClear}>
{translate('clear')}
- </button>
+ </Button>
)}
</div>
);
diff --git a/server/sonar-web/src/main/js/components/facet/__tests__/__snapshots__/FacetHeader-test.tsx.snap b/server/sonar-web/src/main/js/components/facet/__tests__/__snapshots__/FacetHeader-test.tsx.snap
index dad6166c959..e68fe594ca1 100644
--- a/server/sonar-web/src/main/js/components/facet/__tests__/__snapshots__/FacetHeader-test.tsx.snap
+++ b/server/sonar-web/src/main/js/components/facet/__tests__/__snapshots__/FacetHeader-test.tsx.snap
@@ -28,12 +28,12 @@ exports[`should clear 1`] = `
x_selected.3
</span>
</span>
- <button
+ <Button
className="search-navigator-facet-header-button button-small button-red"
- onClick={[Function]}
+ onClick={[MockFunction]}
>
clear
- </button>
+ </Button>
</div>
`;
diff --git a/server/sonar-web/src/main/js/components/ui/buttons.css b/server/sonar-web/src/main/js/components/ui/buttons.css
index 5d1d7b0410c..da474c888c4 100644
--- a/server/sonar-web/src/main/js/components/ui/buttons.css
+++ b/server/sonar-web/src/main/js/components/ui/buttons.css
@@ -17,7 +17,10 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-.button-icon {
+
+/* use double selector .button-icon.button-icon to increase the specificity */
+
+.button-icon.button-icon {
display: inline-flex;
justify-content: center;
align-items: center;
@@ -29,28 +32,28 @@
color: inherit;
}
-.button-icon.button-small {
+.button-icon.button-icon.button-small {
width: var(--smallControlHeight);
height: var(--smallControlHeight);
padding: 0;
}
-.button-icon.button-small svg {
+.button-icon.button-icon.button-small svg {
margin-top: 0;
}
-.button-icon.button-tiny {
+.button-icon.button-icon.button-tiny {
width: var(--tinyControlHeight);
height: var(--tinyControlHeight);
padding: 0;
}
-.button-icon:hover,
-.button-icon:focus {
+.button-icon.button-icon:hover,
+.button-icon.button-icon:focus {
background-color: currentColor;
}
-.button-icon:hover svg,
-.button-icon:focus svg {
+.button-icon.button-icon:hover svg,
+.button-icon.button-icon:focus svg {
color: #fff;
}
diff --git a/server/sonar-web/src/main/js/components/ui/buttons.tsx b/server/sonar-web/src/main/js/components/ui/buttons.tsx
index c89c0cda24c..82992ba0a64 100644
--- a/server/sonar-web/src/main/js/components/ui/buttons.tsx
+++ b/server/sonar-web/src/main/js/components/ui/buttons.tsx
@@ -20,50 +20,95 @@
import * as React from 'react';
import * as classNames from 'classnames';
import * as theme from '../../app/theme';
+import { Omit } from '../../app/types';
import ClearIcon from '../icons-components/ClearIcon';
import EditIcon from '../icons-components/EditIcon';
import Tooltip from '../controls/Tooltip';
import './buttons.css';
-interface ButtonIconProps {
- children: React.ReactNode;
+interface ButtonProps {
className?: string;
- color?: string;
- onClick?: () => void;
- tooltip?: string;
- [x: string]: any;
+ children?: React.ReactNode;
+ disabled?: boolean;
+ id?: string;
+ innerRef?: (node: HTMLElement | null) => void;
+ onClick?: (event: React.MouseEvent<HTMLElement>) => void;
+ preventDefault?: boolean;
+ stopPropagation?: boolean;
+ style?: React.CSSProperties;
+ type?: string;
}
-export class ButtonIcon extends React.PureComponent<ButtonIconProps> {
- handleClick = (event: React.SyntheticEvent<HTMLButtonElement>) => {
- event.preventDefault();
+export class Button extends React.PureComponent<ButtonProps> {
+ handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {
+ const { onClick, preventDefault = true, stopPropagation = false } = this.props;
+
event.currentTarget.blur();
- event.stopPropagation();
- if (this.props.onClick) {
- this.props.onClick();
- }
+ if (preventDefault) event.preventDefault();
+ if (stopPropagation) event.stopPropagation();
+ if (onClick) onClick(event);
};
render() {
- const { children, className, color = theme.darkBlue, onClick, tooltip, ...props } = this.props;
- const buttonComponent = (
+ const {
+ className,
+ innerRef,
+ onClick,
+ preventDefault,
+ stopPropagation,
+ type = 'button',
+ ...props
+ } = this.props;
+ return (
+ // eslint-disable-next-line react/button-has-type
<button
- className={classNames(className, 'button-icon')}
+ {...props}
+ className={classNames('button', className)}
+ disabled={this.props.disabled}
+ id={this.props.id}
onClick={this.handleClick}
- style={{ color }}
- {...props}>
- {children}
- </button>
+ ref={this.props.innerRef}
+ type={type}
+ />
+ );
+ }
+}
+
+export function SubmitButton(props: Omit<ButtonProps, 'type'>) {
+ // do not prevent default to actually submit a form
+ return <Button {...props} preventDefault={false} type="submit" />;
+}
+
+export function ResetButtonLink({ className, ...props }: Omit<ButtonProps, 'type'>) {
+ return <Button {...props} className={classNames('button-link', className)} type="reset" />;
+}
+
+interface ButtonIconProps {
+ className?: string;
+ color?: string;
+ onClick?: () => void;
+ tooltip?: string;
+ [x: string]: any;
+}
+
+export function ButtonIcon(props: ButtonIconProps) {
+ const { className, color = theme.darkBlue, tooltip, ...other } = props;
+ const buttonComponent = (
+ <Button
+ className={classNames(className, 'button-icon')}
+ stopPropagation={true}
+ style={{ color }}
+ {...other}
+ />
+ );
+ if (tooltip) {
+ return (
+ <Tooltip mouseEnterDelay={0.4} overlay={tooltip}>
+ {buttonComponent}
+ </Tooltip>
);
- if (tooltip) {
- return (
- <Tooltip overlay={tooltip} mouseEnterDelay={0.4}>
- {buttonComponent}
- </Tooltip>
- );
- }
- return buttonComponent;
}
+ return buttonComponent;
}
interface ActionButtonProps {
diff --git a/server/sonar-web/src/main/js/helpers/testUtils.ts b/server/sonar-web/src/main/js/helpers/testUtils.ts
index 5e7ad5f1d4c..bdd52ec8e1e 100644
--- a/server/sonar-web/src/main/js/helpers/testUtils.ts
+++ b/server/sonar-web/src/main/js/helpers/testUtils.ts
@@ -28,7 +28,15 @@ export const mockEvent = {
};
export function click(element: ShallowWrapper | ReactWrapper, event = {}): void {
- element.simulate('click', { ...mockEvent, ...event });
+ // `type()` returns a component constructor for a composite element and string for DOM nodes
+ if (typeof element.type() === 'function') {
+ element.prop<Function>('onClick')();
+ // TODO find out if `root` is a public api
+ // https://github.com/airbnb/enzyme/blob/master/packages/enzyme/src/ReactWrapper.js#L109
+ (element as any).root().update();
+ } else {
+ element.simulate('click', { ...mockEvent, ...event });
+ }
}
export function clickOutside(event = {}): void {