aboutsummaryrefslogtreecommitdiffstats
path: root/server/sonar-web
diff options
context:
space:
mode:
authorJeremy Davis <jeremy.davis@sonarsource.com>2020-09-22 14:20:28 +0200
committersonartech <sonartech@sonarsource.com>2020-09-28 20:07:23 +0000
commit71cc0592365fc7ff36694c726c1a8ca4e1fcc6cd (patch)
tree79f66251286871397c898aca6ccb050c5f102f23 /server/sonar-web
parent7d546a463731e1410ba34225e2e1aa5d9586a3b2 (diff)
downloadsonarqube-71cc0592365fc7ff36694c726c1a8ca4e1fcc6cd.tar.gz
sonarqube-71cc0592365fc7ff36694c726c1a8ca4e1fcc6cd.zip
SONAR-13880 internationalize tooltips
Diffstat (limited to 'server/sonar-web')
-rw-r--r--server/sonar-web/src/main/js/app/components/nav/component/branch-like/CurrentBranchLike.tsx32
-rw-r--r--server/sonar-web/src/main/js/app/components/nav/component/branch-like/__tests__/__snapshots__/CurrentBranchLike-test.tsx.snap34
-rw-r--r--server/sonar-web/src/main/js/app/utils/startReactApp.tsx2
-rw-r--r--server/sonar-web/src/main/js/apps/coding-rules/components/ProfileFacet.tsx12
-rw-r--r--server/sonar-web/src/main/js/apps/coding-rules/components/RuleDetails.tsx12
-rw-r--r--server/sonar-web/src/main/js/apps/coding-rules/components/RuleDetailsMeta.tsx6
-rw-r--r--server/sonar-web/src/main/js/apps/coding-rules/components/TemplateFacet.tsx10
-rw-r--r--server/sonar-web/src/main/js/apps/create/components/BillingFormShim.tsx47
-rw-r--r--server/sonar-web/src/main/js/apps/create/components/FreeCardPlan.tsx66
-rw-r--r--server/sonar-web/src/main/js/apps/create/components/OrganizationAvatarInput.tsx112
-rw-r--r--server/sonar-web/src/main/js/apps/create/components/OrganizationKeyInput.tsx135
-rw-r--r--server/sonar-web/src/main/js/apps/create/components/OrganizationSelect.tsx84
-rw-r--r--server/sonar-web/src/main/js/apps/create/components/OrganizationUrlInput.tsx96
-rw-r--r--server/sonar-web/src/main/js/apps/create/components/PaidCardPlan.tsx58
-rw-r--r--server/sonar-web/src/main/js/apps/create/components/UpgradeOrganizationAdvantages.tsx49
-rw-r--r--server/sonar-web/src/main/js/apps/create/components/UpgradeOrganizationBox.tsx127
-rw-r--r--server/sonar-web/src/main/js/apps/create/components/UpgradeOrganizationModal.tsx127
-rw-r--r--server/sonar-web/src/main/js/apps/create/components/__mocks__/BillingFormShim.tsx38
-rw-r--r--server/sonar-web/src/main/js/apps/create/components/__tests__/BillingFormShim-test.tsx48
-rw-r--r--server/sonar-web/src/main/js/apps/create/components/__tests__/OrganizationAvatarInput-test.tsx45
-rw-r--r--server/sonar-web/src/main/js/apps/create/components/__tests__/OrganizationKeyInput-test.tsx62
-rw-r--r--server/sonar-web/src/main/js/apps/create/components/__tests__/OrganizationSelect-test.tsx39
-rw-r--r--server/sonar-web/src/main/js/apps/create/components/__tests__/OrganizationUrlInput-test.tsx39
-rw-r--r--server/sonar-web/src/main/js/apps/create/components/__tests__/PaidCardPlan-test.tsx26
-rw-r--r--server/sonar-web/src/main/js/apps/create/components/__tests__/UpgradeOrganizationAdvantages-test.tsx26
-rw-r--r--server/sonar-web/src/main/js/apps/create/components/__tests__/UpgradeOrganizationBox-test.tsx61
-rw-r--r--server/sonar-web/src/main/js/apps/create/components/__tests__/UpgradeOrganizationModal-test.tsx44
-rw-r--r--server/sonar-web/src/main/js/apps/create/components/__tests__/__snapshots__/BillingFormShim-test.tsx.snap16
-rw-r--r--server/sonar-web/src/main/js/apps/create/components/__tests__/__snapshots__/FreeCardPlan-test.tsx.snap101
-rw-r--r--server/sonar-web/src/main/js/apps/create/components/__tests__/__snapshots__/OrganizationAvatarInput-test.tsx.snap63
-rw-r--r--server/sonar-web/src/main/js/apps/create/components/__tests__/__snapshots__/OrganizationKeyInput-test.tsx.snap30
-rw-r--r--server/sonar-web/src/main/js/apps/create/components/__tests__/__snapshots__/OrganizationSelect-test.tsx.snap99
-rw-r--r--server/sonar-web/src/main/js/apps/create/components/__tests__/__snapshots__/OrganizationUrlInput-test.tsx.snap22
-rw-r--r--server/sonar-web/src/main/js/apps/create/components/__tests__/__snapshots__/PaidCardPlan-test.tsx.snap38
-rw-r--r--server/sonar-web/src/main/js/apps/create/components/__tests__/__snapshots__/UpgradeOrganizationAdvantages-test.tsx.snap22
-rw-r--r--server/sonar-web/src/main/js/apps/create/components/__tests__/__snapshots__/UpgradeOrganizationBox-test.tsx.snap45
-rw-r--r--server/sonar-web/src/main/js/apps/create/components/__tests__/__snapshots__/UpgradeOrganizationModal-test.tsx.snap25
-rw-r--r--server/sonar-web/src/main/js/apps/create/organization/AlmApplicationInstalling.tsx43
-rw-r--r--server/sonar-web/src/main/js/apps/create/organization/AutoOrganizationBind.tsx115
-rw-r--r--server/sonar-web/src/main/js/apps/create/organization/AutoOrganizationCreate.tsx215
-rw-r--r--server/sonar-web/src/main/js/apps/create/organization/CreateOrganization.tsx456
-rw-r--r--server/sonar-web/src/main/js/apps/create/organization/ManualOrganizationCreate.tsx76
-rw-r--r--server/sonar-web/src/main/js/apps/create/organization/OrganizationDetailsForm.tsx205
-rw-r--r--server/sonar-web/src/main/js/apps/create/organization/OrganizationDetailsStep.tsx63
-rw-r--r--server/sonar-web/src/main/js/apps/create/organization/PlanSelect.tsx81
-rw-r--r--server/sonar-web/src/main/js/apps/create/organization/PlanStep.tsx165
-rw-r--r--server/sonar-web/src/main/js/apps/create/organization/RemoteOrganizationChoose.tsx204
-rw-r--r--server/sonar-web/src/main/js/apps/create/organization/__tests__/AlmApplicationInstalling-test.tsx27
-rw-r--r--server/sonar-web/src/main/js/apps/create/organization/__tests__/AutoOrganizationBind-test.tsx52
-rw-r--r--server/sonar-web/src/main/js/apps/create/organization/__tests__/AutoOrganizationCreate-test.tsx128
-rw-r--r--server/sonar-web/src/main/js/apps/create/organization/__tests__/CreateOrganization-test.tsx342
-rw-r--r--server/sonar-web/src/main/js/apps/create/organization/__tests__/ManualOrganizationCreate-test.tsx59
-rw-r--r--server/sonar-web/src/main/js/apps/create/organization/__tests__/OrganizationDetailsForm-test.tsx84
-rw-r--r--server/sonar-web/src/main/js/apps/create/organization/__tests__/OrganizationDetailsStep-test.tsx56
-rw-r--r--server/sonar-web/src/main/js/apps/create/organization/__tests__/PlanSelect-test.tsx62
-rw-r--r--server/sonar-web/src/main/js/apps/create/organization/__tests__/PlanStep-test.tsx93
-rw-r--r--server/sonar-web/src/main/js/apps/create/organization/__tests__/RemoteOrganizationChoose-test.tsx77
-rw-r--r--server/sonar-web/src/main/js/apps/create/organization/__tests__/__snapshots__/AlmApplicationInstalling-test.tsx.snap47
-rw-r--r--server/sonar-web/src/main/js/apps/create/organization/__tests__/__snapshots__/AutoOrganizationBind-test.tsx.snap50
-rw-r--r--server/sonar-web/src/main/js/apps/create/organization/__tests__/__snapshots__/AutoOrganizationCreate-test.tsx.snap216
-rw-r--r--server/sonar-web/src/main/js/apps/create/organization/__tests__/__snapshots__/CreateOrganization-test.tsx.snap489
-rw-r--r--server/sonar-web/src/main/js/apps/create/organization/__tests__/__snapshots__/ManualOrganizationCreate-test.tsx.snap84
-rw-r--r--server/sonar-web/src/main/js/apps/create/organization/__tests__/__snapshots__/OrganizationDetailsForm-test.tsx.snap107
-rw-r--r--server/sonar-web/src/main/js/apps/create/organization/__tests__/__snapshots__/OrganizationDetailsStep-test.tsx.snap28
-rw-r--r--server/sonar-web/src/main/js/apps/create/organization/__tests__/__snapshots__/PlanSelect-test.tsx.snap47
-rw-r--r--server/sonar-web/src/main/js/apps/create/organization/__tests__/__snapshots__/PlanStep-test.tsx.snap163
-rw-r--r--server/sonar-web/src/main/js/apps/create/organization/__tests__/__snapshots__/RemoteOrganizationChoose-test.tsx.snap195
-rw-r--r--server/sonar-web/src/main/js/apps/create/organization/__tests__/actions-test.ts79
-rw-r--r--server/sonar-web/src/main/js/apps/create/organization/__tests__/utils-test.tsx32
-rw-r--r--server/sonar-web/src/main/js/apps/create/organization/actions.ts40
-rw-r--r--server/sonar-web/src/main/js/apps/create/organization/utils.ts80
-rw-r--r--server/sonar-web/src/main/js/apps/organizationMembers/AddMemberForm.tsx114
-rw-r--r--server/sonar-web/src/main/js/apps/organizationMembers/ManageMemberGroupsForm.tsx162
-rw-r--r--server/sonar-web/src/main/js/apps/organizationMembers/MembersList.tsx72
-rw-r--r--server/sonar-web/src/main/js/apps/organizationMembers/MembersListHeader.tsx75
-rw-r--r--server/sonar-web/src/main/js/apps/organizationMembers/MembersListItem.tsx143
-rw-r--r--server/sonar-web/src/main/js/apps/organizationMembers/MembersPageHeader.tsx114
-rw-r--r--server/sonar-web/src/main/js/apps/organizationMembers/OrganizationMembers.tsx240
-rw-r--r--server/sonar-web/src/main/js/apps/organizationMembers/OrganizationMembersContainer.tsx37
-rw-r--r--server/sonar-web/src/main/js/apps/organizationMembers/RemoveMemberForm.tsx66
-rw-r--r--server/sonar-web/src/main/js/apps/organizationMembers/SyncMemberForm.tsx175
-rw-r--r--server/sonar-web/src/main/js/apps/organizationMembers/__tests__/AddMemberForm-test.tsx100
-rw-r--r--server/sonar-web/src/main/js/apps/organizationMembers/__tests__/ManageMemberGroupsForm-test.tsx105
-rw-r--r--server/sonar-web/src/main/js/apps/organizationMembers/__tests__/MembersList-test.tsx50
-rw-r--r--server/sonar-web/src/main/js/apps/organizationMembers/__tests__/MembersListHeader-test.tsx58
-rw-r--r--server/sonar-web/src/main/js/apps/organizationMembers/__tests__/MembersListItem-test.tsx79
-rw-r--r--server/sonar-web/src/main/js/apps/organizationMembers/__tests__/MembersPageHeader-test.tsx79
-rw-r--r--server/sonar-web/src/main/js/apps/organizationMembers/__tests__/OrganizationMembers-test.tsx180
-rw-r--r--server/sonar-web/src/main/js/apps/organizationMembers/__tests__/RemoveMemberForm-test.tsx57
-rw-r--r--server/sonar-web/src/main/js/apps/organizationMembers/__tests__/SyncMemberForm-test.tsx80
-rw-r--r--server/sonar-web/src/main/js/apps/organizationMembers/__tests__/__snapshots__/AddMemberForm-test.tsx.snap77
-rw-r--r--server/sonar-web/src/main/js/apps/organizationMembers/__tests__/__snapshots__/ManageMemberGroupsForm-test.tsx.snap115
-rw-r--r--server/sonar-web/src/main/js/apps/organizationMembers/__tests__/__snapshots__/MembersList-test.tsx.snap61
-rw-r--r--server/sonar-web/src/main/js/apps/organizationMembers/__tests__/__snapshots__/MembersListHeader-test.tsx.snap84
-rw-r--r--server/sonar-web/src/main/js/apps/organizationMembers/__tests__/__snapshots__/MembersListItem-test.tsx.snap135
-rw-r--r--server/sonar-web/src/main/js/apps/organizationMembers/__tests__/__snapshots__/MembersPageHeader-test.tsx.snap330
-rw-r--r--server/sonar-web/src/main/js/apps/organizationMembers/__tests__/__snapshots__/OrganizationMembers-test.tsx.snap127
-rw-r--r--server/sonar-web/src/main/js/apps/organizationMembers/__tests__/__snapshots__/RemoveMemberForm-test.tsx.snap43
-rw-r--r--server/sonar-web/src/main/js/apps/organizationMembers/__tests__/__snapshots__/SyncMemberForm-test.tsx.snap187
-rw-r--r--server/sonar-web/src/main/js/apps/organizations/__tests__/actions-test.ts56
-rw-r--r--server/sonar-web/src/main/js/apps/organizations/actions.ts41
-rw-r--r--server/sonar-web/src/main/js/apps/organizations/components/OrganizationAccessContainer.tsx84
-rw-r--r--server/sonar-web/src/main/js/apps/organizations/components/OrganizationBind.tsx128
-rw-r--r--server/sonar-web/src/main/js/apps/organizations/components/OrganizationContainer.tsx51
-rw-r--r--server/sonar-web/src/main/js/apps/organizations/components/OrganizationDelete.tsx166
-rw-r--r--server/sonar-web/src/main/js/apps/organizations/components/OrganizationEdit.tsx223
-rw-r--r--server/sonar-web/src/main/js/apps/organizations/components/OrganizationEmpty.css23
-rw-r--r--server/sonar-web/src/main/js/apps/organizations/components/OrganizationEmpty.tsx58
-rw-r--r--server/sonar-web/src/main/js/apps/organizations/components/OrganizationGroupCheckbox.tsx52
-rw-r--r--server/sonar-web/src/main/js/apps/organizations/components/OrganizationPage.tsx126
-rw-r--r--server/sonar-web/src/main/js/apps/organizations/components/OrganizationProjects.tsx36
-rw-r--r--server/sonar-web/src/main/js/apps/organizations/components/__tests__/OrganizationAccessContainer-test.tsx87
-rw-r--r--server/sonar-web/src/main/js/apps/organizations/components/__tests__/OrganizationBind-test.tsx73
-rw-r--r--server/sonar-web/src/main/js/apps/organizations/components/__tests__/OrganizationDelete-test.tsx71
-rw-r--r--server/sonar-web/src/main/js/apps/organizations/components/__tests__/OrganizationEdit-test.tsx47
-rw-r--r--server/sonar-web/src/main/js/apps/organizations/components/__tests__/OrganizationEmpty-test.tsx53
-rw-r--r--server/sonar-web/src/main/js/apps/organizations/components/__tests__/OrganizationGroupCheckbox-test.tsx62
-rw-r--r--server/sonar-web/src/main/js/apps/organizations/components/__tests__/OrganizationPage-test.tsx65
-rw-r--r--server/sonar-web/src/main/js/apps/organizations/components/__tests__/__snapshots__/OrganizationAccessContainer-test.tsx.snap19
-rw-r--r--server/sonar-web/src/main/js/apps/organizations/components/__tests__/__snapshots__/OrganizationBind-test.tsx.snap23
-rw-r--r--server/sonar-web/src/main/js/apps/organizations/components/__tests__/__snapshots__/OrganizationDelete-test.tsx.snap118
-rw-r--r--server/sonar-web/src/main/js/apps/organizations/components/__tests__/__snapshots__/OrganizationEdit-test.tsx.snap484
-rw-r--r--server/sonar-web/src/main/js/apps/organizations/components/__tests__/__snapshots__/OrganizationEmpty-test.tsx.snap43
-rw-r--r--server/sonar-web/src/main/js/apps/organizations/components/__tests__/__snapshots__/OrganizationGroupCheckbox-test.tsx.snap70
-rw-r--r--server/sonar-web/src/main/js/apps/organizations/components/__tests__/__snapshots__/OrganizationPage-test.tsx.snap58
-rw-r--r--server/sonar-web/src/main/js/apps/organizations/navigation/OrganizationNavigation.tsx57
-rw-r--r--server/sonar-web/src/main/js/apps/organizations/navigation/OrganizationNavigationAdministration.tsx107
-rw-r--r--server/sonar-web/src/main/js/apps/organizations/navigation/OrganizationNavigationExtensions.tsx67
-rw-r--r--server/sonar-web/src/main/js/apps/organizations/navigation/OrganizationNavigationHeader.tsx126
-rw-r--r--server/sonar-web/src/main/js/apps/organizations/navigation/OrganizationNavigationMenuContainer.tsx107
-rw-r--r--server/sonar-web/src/main/js/apps/organizations/navigation/OrganizationNavigationMeta.tsx71
-rw-r--r--server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/OrganizationNavigation-test.tsx39
-rw-r--r--server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/OrganizationNavigationAdministration-test.tsx36
-rw-r--r--server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/OrganizationNavigationHeader-test.tsx101
-rw-r--r--server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/OrganizationNavigationMenuContainer-test.tsx72
-rw-r--r--server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/OrganizationNavigationMeta-test.tsx52
-rw-r--r--server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/__snapshots__/OrganizationNavigation-test.tsx.snap57
-rw-r--r--server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/__snapshots__/OrganizationNavigationAdministration-test.tsx.snap84
-rw-r--r--server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/__snapshots__/OrganizationNavigationHeader-test.tsx.snap216
-rw-r--r--server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/__snapshots__/OrganizationNavigationMenuContainer-test.tsx.snap205
-rw-r--r--server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/__snapshots__/OrganizationNavigationMeta-test.tsx.snap30
-rw-r--r--server/sonar-web/src/main/js/apps/organizations/routes.ts120
-rw-r--r--server/sonar-web/src/main/js/apps/overview/branches/MeasuresPanelIssueMeasureRow.tsx5
-rw-r--r--server/sonar-web/src/main/js/apps/overview/branches/QualityGatePanel.tsx11
-rw-r--r--server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/MeasuresPanelIssueMeasureRow-test.tsx.snap2
-rw-r--r--server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/QualityGatePanel-test.tsx.snap50
-rw-r--r--server/sonar-web/src/main/js/apps/overview/components/IssueLabel.tsx8
-rw-r--r--server/sonar-web/src/main/js/apps/overview/components/__tests__/IssueLabel-test.tsx6
-rw-r--r--server/sonar-web/src/main/js/apps/overview/components/__tests__/__snapshots__/IssueLabel-test.tsx.snap8
-rw-r--r--server/sonar-web/src/main/js/apps/overview/pullRequests/PullRequestOverview.tsx15
-rw-r--r--server/sonar-web/src/main/js/apps/overview/pullRequests/__tests__/__snapshots__/PullRequestOverview-test.tsx.snap28
-rw-r--r--server/sonar-web/src/main/js/apps/permissions/project/components/App.tsx45
-rw-r--r--server/sonar-web/src/main/js/apps/permissions/project/components/AppContainer.ts17
-rw-r--r--server/sonar-web/src/main/js/apps/permissions/project/components/__tests__/App-test.tsx18
-rw-r--r--server/sonar-web/src/main/js/apps/projectQualityGate/Header.tsx12
-rw-r--r--server/sonar-web/src/main/js/apps/projectQualityGate/__tests__/__snapshots__/Header-test.tsx.snap10
-rw-r--r--server/sonar-web/src/main/js/apps/projectQualityProfiles/Header.tsx12
-rw-r--r--server/sonar-web/src/main/js/apps/projectQualityProfiles/__tests__/__snapshots__/Header-test.tsx.snap10
-rw-r--r--server/sonar-web/src/main/js/apps/projectsManagement/CreateProjectForm.tsx13
-rw-r--r--server/sonar-web/src/main/js/apps/projectsManagement/__tests__/__snapshots__/CreateProjectForm-test.tsx.snap57
-rw-r--r--server/sonar-web/src/main/js/apps/quality-gates/components/BuiltInQualityGateBadge.tsx9
-rw-r--r--server/sonar-web/src/main/js/apps/quality-gates/components/Conditions.tsx14
-rw-r--r--server/sonar-web/src/main/js/apps/quality-gates/components/DetailsContent.tsx12
-rw-r--r--server/sonar-web/src/main/js/apps/quality-gates/components/ListHeader.tsx12
-rw-r--r--server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/__snapshots__/BuiltInQualityGateBadge-test.tsx.snap6
-rw-r--r--server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/__snapshots__/Conditions-test.tsx.snap60
-rw-r--r--server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/__snapshots__/DetailsContent-test.tsx.snap20
-rw-r--r--server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/__snapshots__/ListHeader-test.tsx.snap12
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileRules.tsx9
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/home/ProfilesList.tsx12
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/home/ProfilesListRow.tsx8
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/home/__tests__/__snapshots__/ProfilesList-test.tsx.snap30
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/home/__tests__/__snapshots__/ProfilesListRow-test.tsx.snap6
-rw-r--r--server/sonar-web/src/main/js/components/common/DocumentationTooltip.tsx72
-rw-r--r--server/sonar-web/src/main/js/components/common/__tests__/DocumentationTooltip-test.tsx (renamed from server/sonar-web/src/main/js/apps/create/components/__tests__/FreeCardPlan-test.tsx)28
-rw-r--r--server/sonar-web/src/main/js/components/common/__tests__/__snapshots__/DocumentationTooltip-test.tsx.snap112
-rw-r--r--server/sonar-web/src/main/js/components/docs/DocTooltip.tsx79
-rw-r--r--server/sonar-web/src/main/js/components/docs/__tests__/DocTooltip-test.tsx30
-rw-r--r--server/sonar-web/src/main/js/components/docs/__tests__/__snapshots__/DocTooltip-test.tsx.snap19
179 files changed, 556 insertions, 13488 deletions
diff --git a/server/sonar-web/src/main/js/app/components/nav/component/branch-like/CurrentBranchLike.tsx b/server/sonar-web/src/main/js/app/components/nav/component/branch-like/CurrentBranchLike.tsx
index adfb0b37550..120b5d76e9a 100644
--- a/server/sonar-web/src/main/js/app/components/nav/component/branch-like/CurrentBranchLike.tsx
+++ b/server/sonar-web/src/main/js/app/components/nav/component/branch-like/CurrentBranchLike.tsx
@@ -23,7 +23,7 @@ import HelpTooltip from 'sonar-ui-common/components/controls/HelpTooltip';
import DropdownIcon from 'sonar-ui-common/components/icons/DropdownIcon';
import PlusCircleIcon from 'sonar-ui-common/components/icons/PlusCircleIcon';
import { translate } from 'sonar-ui-common/helpers/l10n';
-import DocTooltip from '../../../../../components/docs/DocTooltip';
+import DocumentationTooltip from '../../../../../components/common/DocumentationTooltip';
import BranchLikeIcon from '../../../../../components/icons/BranchLikeIcon';
import { getBranchLikeDisplayName } from '../../../../../helpers/branch-like';
import { getPortfolioAdminUrl } from '../../../../../helpers/urls';
@@ -78,21 +78,39 @@ export function CurrentBranchLike(props: CurrentBranchLikeProps) {
} else {
if (!branchesEnabled) {
return (
- <DocTooltip
+ <DocumentationTooltip
+ content={translate('branch_like_navigation.no_branch_support.content')}
data-test="branches-support-disabled"
- doc={import(/* webpackMode: "eager" */ 'Docs/tooltips/branches/no-branch-support.md')}>
+ links={[
+ {
+ href: 'https://redirect.sonarsource.com/editions/developer.html',
+ label: translate('learn_more')
+ }
+ ]}
+ title={translate('branch_like_navigation.no_branch_support.title')}>
{plusIcon}
- </DocTooltip>
+ </DocumentationTooltip>
);
}
if (!hasManyBranches) {
return (
- <DocTooltip
+ <DocumentationTooltip
+ content={translate('branch_like_navigation.only_one_branch.content')}
data-test="only-one-branch-like"
- doc={import(/* webpackMode: "eager" */ 'Docs/tooltips/branches/single-branch.md')}>
+ links={[
+ {
+ href: '/documentation/branches/overview/',
+ label: translate('branch_like_navigation.only_one_branch.documentation')
+ },
+ {
+ href: '/documentation/analysis/pull-request/',
+ label: translate('branch_like_navigation.only_one_branch.pr_analysis')
+ }
+ ]}
+ title={translate('branch_like_navigation.only_one_branch.title')}>
{plusIcon}
- </DocTooltip>
+ </DocumentationTooltip>
);
}
}
diff --git a/server/sonar-web/src/main/js/app/components/nav/component/branch-like/__tests__/__snapshots__/CurrentBranchLike-test.tsx.snap b/server/sonar-web/src/main/js/app/components/nav/component/branch-like/__tests__/__snapshots__/CurrentBranchLike-test.tsx.snap
index 40ee3ab13ab..a76cb8e9184 100644
--- a/server/sonar-web/src/main/js/app/components/nav/component/branch-like/__tests__/__snapshots__/CurrentBranchLike-test.tsx.snap
+++ b/server/sonar-web/src/main/js/app/components/nav/component/branch-like/__tests__/__snapshots__/CurrentBranchLike-test.tsx.snap
@@ -122,15 +122,24 @@ exports[`CurrentBranchLikeRenderer should render correctly for project when bran
>
master
</span>
- <DocTooltip
+ <DocumentationTooltip
+ content="branch_like_navigation.no_branch_support.content"
data-test="branches-support-disabled"
- doc={Promise {}}
+ links={
+ Array [
+ Object {
+ "href": "https://redirect.sonarsource.com/editions/developer.html",
+ "label": "learn_more",
+ },
+ ]
+ }
+ title="branch_like_navigation.no_branch_support.title"
>
<PlusCircleIcon
fill="#4b9fd5"
size={12}
/>
- </DocTooltip>
+ </DocumentationTooltip>
</span>
`;
@@ -178,14 +187,27 @@ exports[`CurrentBranchLikeRenderer should render correctly for project when ther
>
master
</span>
- <DocTooltip
+ <DocumentationTooltip
+ content="branch_like_navigation.only_one_branch.content"
data-test="only-one-branch-like"
- doc={Promise {}}
+ links={
+ Array [
+ Object {
+ "href": "/documentation/branches/overview/",
+ "label": "branch_like_navigation.only_one_branch.documentation",
+ },
+ Object {
+ "href": "/documentation/analysis/pull-request/",
+ "label": "branch_like_navigation.only_one_branch.pr_analysis",
+ },
+ ]
+ }
+ title="branch_like_navigation.only_one_branch.title"
>
<PlusCircleIcon
fill="#4b9fd5"
size={12}
/>
- </DocTooltip>
+ </DocumentationTooltip>
</span>
`;
diff --git a/server/sonar-web/src/main/js/app/utils/startReactApp.tsx b/server/sonar-web/src/main/js/app/utils/startReactApp.tsx
index 44a7a8a386f..8fd903ea286 100644
--- a/server/sonar-web/src/main/js/app/utils/startReactApp.tsx
+++ b/server/sonar-web/src/main/js/app/utils/startReactApp.tsx
@@ -42,7 +42,6 @@ import groupsRoutes from '../../apps/groups/routes';
import Issues from '../../apps/issues/components/AppContainer';
import { maintenanceRoutes, setupRoutes } from '../../apps/maintenance/routes';
import marketplaceRoutes from '../../apps/marketplace/routes';
-import organizationsRoutes from '../../apps/organizations/routes';
import overviewRoutes from '../../apps/overview/routes';
import permissionTemplatesRoutes from '../../apps/permission-templates/routes';
import { globalPermissionsRoutes, projectPermissionsRoutes } from '../../apps/permissions/routes';
@@ -299,7 +298,6 @@ export default function startReactApp(
path="issues"
component={withIndexationGuard(Issues, PageContext.Issues)}
/>
- <RouteWithChildRoutes path="organizations" childRoutes={organizationsRoutes} />
<RouteWithChildRoutes path="projects" childRoutes={projectsRoutes} />
<RouteWithChildRoutes path="quality_gates" childRoutes={qualityGatesRoutes} />
<Route
diff --git a/server/sonar-web/src/main/js/apps/coding-rules/components/ProfileFacet.tsx b/server/sonar-web/src/main/js/apps/coding-rules/components/ProfileFacet.tsx
index cff73265b60..ed15f030dea 100644
--- a/server/sonar-web/src/main/js/apps/coding-rules/components/ProfileFacet.tsx
+++ b/server/sonar-web/src/main/js/apps/coding-rules/components/ProfileFacet.tsx
@@ -22,7 +22,7 @@ import { sortBy } from 'lodash';
import * as React from 'react';
import { translate } from 'sonar-ui-common/helpers/l10n';
import { Profile } from '../../../api/quality-profiles';
-import DocTooltip from '../../../components/docs/DocTooltip';
+import DocumentationTooltip from '../../../components/common/DocumentationTooltip';
import FacetBox from '../../../components/facet/FacetBox';
import FacetHeader from '../../../components/facet/FacetHeader';
import FacetItem from '../../../components/facet/FacetItem';
@@ -169,9 +169,15 @@ export default class ProfileFacet extends React.PureComponent<Props> {
onClick={this.handleHeaderClick}
open={this.props.open}
values={this.getTextValue()}>
- <DocTooltip
+ <DocumentationTooltip
className="spacer-left"
- doc={import(/* webpackMode: "eager" */ 'Docs/tooltips/rules/rules-quality-profiles.md')}
+ content={translate('coding_rules.facet.qprofile.help')}
+ links={[
+ {
+ href: '/documentation/instance-administration/quality-profiles/',
+ label: translate('coding_rules.facet.qprofile.link')
+ }
+ ]}
/>
</FacetHeader>
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 10e5f8729d2..fecab52d5ee 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
@@ -20,11 +20,11 @@
import * as React from 'react';
import { Button } from 'sonar-ui-common/components/controls/buttons';
import ConfirmButton from 'sonar-ui-common/components/controls/ConfirmButton';
+import HelpTooltip from 'sonar-ui-common/components/controls/HelpTooltip';
import DeferredSpinner from 'sonar-ui-common/components/ui/DeferredSpinner';
import { translate, translateWithParameters } from 'sonar-ui-common/helpers/l10n';
import { Profile } from '../../../api/quality-profiles';
import { deleteRule, getRuleDetails, updateRule } from '../../../api/rules';
-import DocTooltip from '../../../components/docs/DocTooltip';
import { Activation, Query } from '../query';
import CustomRuleButton from './CustomRuleButton';
import RuleDetailsCustomRules from './RuleDetailsCustomRules';
@@ -226,11 +226,13 @@ export default class RuleDetails extends React.PureComponent<Props, State> {
onClick={onClick}>
{translate('delete')}
</Button>
- <DocTooltip
+ <HelpTooltip
className="spacer-left"
- doc={import(
- /* webpackMode: "eager" */ 'Docs/tooltips/rules/custom-rule-removal.md'
- )}
+ overlay={
+ <div className="big-padded-top big-padded-bottom">
+ {translate('coding_rules.custom_rule.removal')}
+ </div>
+ }
/>
</>
)}
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 88c76616153..c0819178da4 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
@@ -21,13 +21,13 @@ import * as React from 'react';
import { Link } from 'react-router';
import { ButtonLink } from 'sonar-ui-common/components/controls/buttons';
import Dropdown from 'sonar-ui-common/components/controls/Dropdown';
+import HelpTooltip from 'sonar-ui-common/components/controls/HelpTooltip';
import Tooltip from 'sonar-ui-common/components/controls/Tooltip';
import IssueTypeIcon from 'sonar-ui-common/components/icons/IssueTypeIcon';
import LinkIcon from 'sonar-ui-common/components/icons/LinkIcon';
import DateFormatter from 'sonar-ui-common/components/intl/DateFormatter';
import { PopupPlacement } from 'sonar-ui-common/components/ui/popups';
import { translate, translateWithParameters } from 'sonar-ui-common/helpers/l10n';
-import DocTooltip from '../../../components/docs/DocTooltip';
import SeverityHelper from '../../../components/shared/SeverityHelper';
import TagsList from '../../../components/tags/TagsList';
import { getRuleUrl } from '../../../helpers/urls';
@@ -169,9 +169,9 @@ export default class RuleDetailsMeta extends React.PureComponent<Props> {
{translate('coding_rules.show_template')}
</Link>
{')'}
- <DocTooltip
+ <HelpTooltip
className="little-spacer-left"
- doc={import(/* webpackMode: "eager" */ 'Docs/tooltips/rules/custom-rules.md')}
+ overlay={translate('coding_rules.custom_rule.help')}
/>
</li>
);
diff --git a/server/sonar-web/src/main/js/apps/coding-rules/components/TemplateFacet.tsx b/server/sonar-web/src/main/js/apps/coding-rules/components/TemplateFacet.tsx
index af73da1278f..c90892f594c 100644
--- a/server/sonar-web/src/main/js/apps/coding-rules/components/TemplateFacet.tsx
+++ b/server/sonar-web/src/main/js/apps/coding-rules/components/TemplateFacet.tsx
@@ -18,8 +18,8 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import * as React from 'react';
+import HelpTooltip from 'sonar-ui-common/components/controls/HelpTooltip';
import { translate } from 'sonar-ui-common/helpers/l10n';
-import DocTooltip from '../../../components/docs/DocTooltip';
import Facet, { BasicProps } from './Facet';
interface Props extends T.Omit<BasicProps, 'onChange' | 'values'> {
@@ -56,9 +56,13 @@ export default class TemplateFacet extends React.PureComponent<Props> {
renderTextName={this.renderName}
singleSelection={true}
values={value !== undefined ? [String(value)] : []}>
- <DocTooltip
+ <HelpTooltip
className="spacer-left"
- doc={import(/* webpackMode: "eager" */ 'Docs/tooltips/rules/rule-templates.md')}
+ overlay={
+ <div className="big-padded-top big-padded-bottom">
+ {translate('coding_rules.rule_template.help')}
+ </div>
+ }
/>
</Facet>
);
diff --git a/server/sonar-web/src/main/js/apps/create/components/BillingFormShim.tsx b/server/sonar-web/src/main/js/apps/create/components/BillingFormShim.tsx
deleted file mode 100644
index bc3cf8b9874..00000000000
--- a/server/sonar-web/src/main/js/apps/create/components/BillingFormShim.tsx
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import * as React from 'react';
-
-interface ChildrenProps {
- onSubmit: React.FormEventHandler;
- processingUpgrade: boolean;
- renderFormFields: () => React.ReactNode;
- renderNextCharge: (className?: string) => React.ReactNode;
- renderRecap: () => React.ReactNode;
- renderSubmitButton: (submitText?: string) => React.ReactNode;
- renderSubmitGroup: (submitText?: string) => React.ReactNode;
-}
-
-interface Props {
- children: (props: ChildrenProps) => React.ReactNode;
- initialCountry?: string;
- currentUser: T.CurrentUser;
- onCommit: () => void | Promise<void>;
- onFailToUpgrade?: () => void;
- organizationKey: string | (() => Promise<string>);
- subscriptionPlans: T.SubscriptionPlan[];
-}
-
-export default class BillingFormShim extends React.Component<Props> {
- render() {
- const { BillingForm } = (window as any).SonarBilling;
- return <BillingForm {...this.props} />;
- }
-}
diff --git a/server/sonar-web/src/main/js/apps/create/components/FreeCardPlan.tsx b/server/sonar-web/src/main/js/apps/create/components/FreeCardPlan.tsx
deleted file mode 100644
index 6d7f0aaab3e..00000000000
--- a/server/sonar-web/src/main/js/apps/create/components/FreeCardPlan.tsx
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import * as React from 'react';
-import { FormattedMessage } from 'react-intl';
-import RadioCard, { RadioCardProps } from 'sonar-ui-common/components/controls/RadioCard';
-import { Alert } from 'sonar-ui-common/components/ui/Alert';
-import { translate } from 'sonar-ui-common/helpers/l10n';
-import { formatPrice } from '../organization/utils';
-
-interface Props extends RadioCardProps {
- almName?: string;
- hasWarning: boolean;
-}
-
-export default function FreeCardPlan({ almName, hasWarning, ...props }: Props) {
- const showInfo = almName && props.disabled;
- const showWarning = almName && hasWarning && !props.disabled;
-
- return (
- <RadioCard title={translate('billing.free_plan.title')} titleInfo={formatPrice(0)} {...props}>
- <div className="spacer-left">
- <ul className="big-spacer-left note">
- <li className="little-spacer-bottom">
- {translate('billing.free_plan.all_projects_analyzed_public')}
- </li>
- <li>{translate('billing.free_plan.anyone_can_browse_source_code')}</li>
- </ul>
- </div>
- {showWarning && (
- <Alert variant="warning">
- <FormattedMessage
- defaultMessage={translate('billing.free_plan.private_repo_warning')}
- id="billing.free_plan.private_repo_warning"
- values={{ alm: almName }}
- />
- </Alert>
- )}
- {showInfo && (
- <Alert variant="info">
- <FormattedMessage
- defaultMessage={translate('billing.free_plan.not_available_info')}
- id="billing.free_plan.not_available_info"
- values={{ alm: almName }}
- />
- </Alert>
- )}
- </RadioCard>
- );
-}
diff --git a/server/sonar-web/src/main/js/apps/create/components/OrganizationAvatarInput.tsx b/server/sonar-web/src/main/js/apps/create/components/OrganizationAvatarInput.tsx
deleted file mode 100644
index 78495b31f6a..00000000000
--- a/server/sonar-web/src/main/js/apps/create/components/OrganizationAvatarInput.tsx
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import * as classNames from 'classnames';
-import * as React from 'react';
-import ValidationInput from 'sonar-ui-common/components/controls/ValidationInput';
-import { translate } from 'sonar-ui-common/helpers/l10n';
-import { isWebUri } from 'valid-url';
-import OrganizationAvatar from '../../../components/common/OrganizationAvatar';
-
-interface Props {
- initialValue?: string;
- name?: string;
- onChange: (value: string | undefined) => void;
-}
-
-interface State {
- editing: boolean;
- error?: string;
- touched: boolean;
- value: string;
-}
-
-export default class OrganizationAvatarInput extends React.PureComponent<Props, State> {
- state: State = { error: undefined, editing: false, touched: false, value: '' };
-
- componentDidMount() {
- if (this.props.initialValue) {
- const value = this.props.initialValue;
- const error = this.validateUrl(value);
- this.setState({ error, touched: Boolean(error), value });
- }
- }
-
- handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
- const value = event.currentTarget.value.trim();
- const error = this.validateUrl(value);
- this.setState({ error, touched: true, value });
- this.props.onChange(error === undefined ? value : undefined);
- };
-
- handleBlur = () => {
- this.setState({ editing: false });
- };
-
- handleFocus = () => {
- this.setState({ editing: true });
- };
-
- validateUrl(url: string) {
- if (url.length > 0 && !isWebUri(url)) {
- return translate('onboarding.create_organization.url.error');
- }
- return undefined;
- }
-
- render() {
- const isInvalid = this.state.touched && !this.state.editing && this.state.error !== undefined;
- const isValidUrl = this.state.error === undefined && this.state.value !== '';
- const isValid = this.state.touched && isValidUrl;
- return (
- <ValidationInput
- description={translate('onboarding.create_organization.avatar.description')}
- error={this.state.error}
- id="organization-avatar"
- isInvalid={isInvalid}
- isValid={isValid}
- label={translate('onboarding.create_organization.avatar')}>
- <>
- {(isValidUrl || this.props.name) && (
- <OrganizationAvatar
- className="display-block spacer-bottom"
- organization={{
- avatar: isValidUrl ? this.state.value : undefined,
- name: this.props.name || ''
- }}
- />
- )}
- <input
- className={classNames('input-super-large', 'text-middle', {
- 'is-invalid': isInvalid,
- 'is-valid': isValid
- })}
- id="organization-avatar"
- onBlur={this.handleBlur}
- onChange={this.handleChange}
- onFocus={this.handleFocus}
- placeholder={translate('onboarding.create_organization.avatar.placeholder')}
- type="text"
- value={this.state.value}
- />
- </>
- </ValidationInput>
- );
- }
-}
diff --git a/server/sonar-web/src/main/js/apps/create/components/OrganizationKeyInput.tsx b/server/sonar-web/src/main/js/apps/create/components/OrganizationKeyInput.tsx
deleted file mode 100644
index f1f88be187b..00000000000
--- a/server/sonar-web/src/main/js/apps/create/components/OrganizationKeyInput.tsx
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import * as classNames from 'classnames';
-import { debounce } from 'lodash';
-import * as React from 'react';
-import ValidationInput from 'sonar-ui-common/components/controls/ValidationInput';
-import { translate } from 'sonar-ui-common/helpers/l10n';
-import { getHostUrl } from 'sonar-ui-common/helpers/urls';
-import { getOrganization } from '../../../api/organizations';
-
-interface Props {
- initialValue?: string;
- onChange: (value: string | undefined) => void;
-}
-
-interface State {
- error?: string;
- touched: boolean;
- validating: boolean;
- value: string;
-}
-
-export default class OrganizationKeyInput extends React.PureComponent<Props, State> {
- mounted = false;
- constructor(props: Props) {
- super(props);
- this.state = { error: undefined, touched: false, validating: false, value: '' };
- this.checkFreeKey = debounce(this.checkFreeKey, 250);
- }
-
- componentDidMount() {
- this.mounted = true;
- if (this.props.initialValue !== undefined) {
- this.setState({ value: this.props.initialValue });
- this.validateKey(this.props.initialValue);
- }
- }
-
- componentWillUnmount() {
- this.mounted = false;
- }
-
- checkFreeKey = (key: string) => {
- this.setState({ validating: true });
- return getOrganization(key)
- .then(organization => {
- if (this.mounted) {
- if (organization === undefined) {
- this.setState({ error: undefined, validating: false });
- this.props.onChange(key);
- } else {
- this.setState({
- error: translate('onboarding.create_organization.organization_name.taken'),
- touched: true,
- validating: false
- });
- this.props.onChange(undefined);
- }
- }
- })
- .catch(() => {
- if (this.mounted) {
- this.setState({ error: undefined, validating: false });
- this.props.onChange(key);
- }
- });
- };
-
- handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
- const { value } = event.currentTarget;
- this.setState({ touched: true, value });
- this.validateKey(value);
- };
-
- validateKey(key: string) {
- if (key.length > 255 || !/^[a-z0-9][a-z0-9-]*[a-z0-9]?$/.test(key)) {
- this.setState({
- error: translate('onboarding.create_organization.organization_name.error'),
- touched: true
- });
- this.props.onChange(undefined);
- } else {
- this.checkFreeKey(key);
- }
- }
-
- render() {
- const isInvalid = this.state.touched && this.state.error !== undefined;
- const isValid = this.state.touched && !this.state.validating && this.state.error === undefined;
- return (
- <ValidationInput
- error={this.state.error}
- id="organization-key"
- isInvalid={isInvalid}
- isValid={isValid}
- label={translate('onboarding.create_organization.organization_name')}
- required={true}>
- <div className="display-inline-flex-baseline">
- <span className="little-spacer-right">
- {getHostUrl().replace(/https*:\/\//, '') + '/organizations/'}
- </span>
- <input
- autoFocus={true}
- className={classNames('input-super-large', {
- 'is-invalid': isInvalid,
- 'is-valid': isValid
- })}
- id="organization-key"
- maxLength={255}
- onChange={this.handleChange}
- type="text"
- value={this.state.value}
- />
- </div>
- </ValidationInput>
- );
- }
-}
diff --git a/server/sonar-web/src/main/js/apps/create/components/OrganizationSelect.tsx b/server/sonar-web/src/main/js/apps/create/components/OrganizationSelect.tsx
deleted file mode 100644
index 34baa319fc5..00000000000
--- a/server/sonar-web/src/main/js/apps/create/components/OrganizationSelect.tsx
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import { sortBy } from 'lodash';
-import * as React from 'react';
-import Select from 'sonar-ui-common/components/controls/Select';
-import { translate } from 'sonar-ui-common/helpers/l10n';
-import { getBaseUrl } from 'sonar-ui-common/helpers/urls';
-import { sanitizeAlmId } from '../../../helpers/almIntegrations';
-
-interface Props {
- hideIcons?: boolean;
- onChange: (organization: T.Organization) => void;
- organization: string;
- organizations: T.Organization[];
-}
-
-export default function OrganizationSelect({
- hideIcons,
- onChange,
- organization,
- organizations
-}: Props) {
- const optionRenderer = getOptionRenderer(hideIcons);
- return (
- <Select
- autoFocus={!organization}
- className="input-super-large"
- clearable={false}
- id="select-organization"
- labelKey="name"
- onChange={onChange}
- optionRenderer={optionRenderer}
- options={sortBy(organizations, o => o.name.toLowerCase())}
- placeholder={translate('onboarding.import_organization.choose_organization')}
- required={true}
- value={organization}
- valueKey="key"
- valueRenderer={optionRenderer}
- />
- );
-}
-
-export function getOptionRenderer(hideIcons?: boolean) {
- return function optionRenderer(organization: T.Organization) {
- const icon = organization.alm
- ? `sonarcloud/${sanitizeAlmId(organization.alm.key)}`
- : 'sonarcloud-square-logo';
- const isPaidOrg = organization.subscription === 'PAID';
- return (
- <div className="display-flex-space-between">
- <span className="text-ellipsis flex-1">
- {!hideIcons && (
- <img
- alt={organization.alm ? organization.alm.key : 'SonarCloud'}
- className="little-spacer-right"
- height={14}
- src={`${getBaseUrl()}/images/${icon}.svg`}
- />
- )}
- {organization.name}
- <span className="note little-spacer-left">{organization.key}</span>
- </span>
- {isPaidOrg && <div className="badge">{translate('organization.paid_plan.badge')}</div>}
- </div>
- );
- };
-}
diff --git a/server/sonar-web/src/main/js/apps/create/components/OrganizationUrlInput.tsx b/server/sonar-web/src/main/js/apps/create/components/OrganizationUrlInput.tsx
deleted file mode 100644
index 5f716947f02..00000000000
--- a/server/sonar-web/src/main/js/apps/create/components/OrganizationUrlInput.tsx
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import * as classNames from 'classnames';
-import * as React from 'react';
-import ValidationInput from 'sonar-ui-common/components/controls/ValidationInput';
-import { translate } from 'sonar-ui-common/helpers/l10n';
-import { isWebUri } from 'valid-url';
-
-interface Props {
- initialValue?: string;
- onChange: (value: string | undefined) => void;
-}
-
-interface State {
- editing: boolean;
- error?: string;
- touched: boolean;
- value: string;
-}
-
-export default class OrganizationUrlInput extends React.PureComponent<Props, State> {
- state: State = { error: undefined, editing: false, touched: false, value: '' };
-
- componentDidMount() {
- if (this.props.initialValue) {
- const value = this.props.initialValue;
- const error = this.validateUrl(value);
- this.setState({ error, touched: Boolean(error), value });
- }
- }
-
- handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
- const value = event.currentTarget.value.trim();
- const error = this.validateUrl(value);
- this.setState({ error, touched: true, value });
- this.props.onChange(error === undefined ? value : undefined);
- };
-
- handleBlur = () => {
- this.setState({ editing: false });
- };
-
- handleFocus = () => {
- this.setState({ editing: true });
- };
-
- validateUrl(url: string) {
- if (url.length > 0 && !isWebUri(url)) {
- return translate('onboarding.create_organization.url.error');
- }
- return undefined;
- }
-
- render() {
- const isInvalid = this.state.touched && !this.state.editing && this.state.error !== undefined;
- const isValid = this.state.touched && this.state.error === undefined && this.state.value !== '';
- return (
- <ValidationInput
- error={this.state.error}
- id="organization-url"
- isInvalid={isInvalid}
- isValid={isValid}
- label={translate('onboarding.create_organization.url')}>
- <input
- className={classNames('input-super-large', 'text-middle', {
- 'is-invalid': isInvalid,
- 'is-valid': isValid
- })}
- id="organization-url"
- onBlur={this.handleBlur}
- onChange={this.handleChange}
- onFocus={this.handleFocus}
- type="text"
- value={this.state.value}
- />
- </ValidationInput>
- );
- }
-}
diff --git a/server/sonar-web/src/main/js/apps/create/components/PaidCardPlan.tsx b/server/sonar-web/src/main/js/apps/create/components/PaidCardPlan.tsx
deleted file mode 100644
index a8150a08a85..00000000000
--- a/server/sonar-web/src/main/js/apps/create/components/PaidCardPlan.tsx
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import * as React from 'react';
-import { FormattedMessage } from 'react-intl';
-import { Link } from 'react-router';
-import RadioCard, { RadioCardProps } from 'sonar-ui-common/components/controls/RadioCard';
-import { translate } from 'sonar-ui-common/helpers/l10n';
-import { formatPrice } from '../organization/utils';
-import UpgradeOrganizationAdvantages from './UpgradeOrganizationAdvantages';
-
-interface Props extends RadioCardProps {
- isRecommended: boolean;
- startingPrice?: number;
-}
-
-export default function PaidCardPlan({ isRecommended, startingPrice, ...props }: Props) {
- return (
- <RadioCard
- recommended={isRecommended ? translate('billing.paid_plan.recommended') : undefined}
- title={translate('billing.paid_plan.title')}
- titleInfo={
- startingPrice !== undefined && (
- <FormattedMessage
- defaultMessage={translate('billing.price_from_x')}
- id="billing.price_from_x"
- values={{
- price: <span className="big">{formatPrice(startingPrice)}</span>
- }}
- />
- )
- }
- {...props}>
- <UpgradeOrganizationAdvantages />
- <div className="big-spacer-left">
- <Link className="spacer-left" target="_blank" to="/about/pricing">
- {translate('billing.pricing.learn_more')}
- </Link>
- </div>
- </RadioCard>
- );
-}
diff --git a/server/sonar-web/src/main/js/apps/create/components/UpgradeOrganizationAdvantages.tsx b/server/sonar-web/src/main/js/apps/create/components/UpgradeOrganizationAdvantages.tsx
deleted file mode 100644
index 6cfe7cf1526..00000000000
--- a/server/sonar-web/src/main/js/apps/create/components/UpgradeOrganizationAdvantages.tsx
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import * as React from 'react';
-import CheckIcon from 'sonar-ui-common/components/icons/CheckIcon';
-import { translate, translateWithParameters } from 'sonar-ui-common/helpers/l10n';
-import { colors } from '../../../app/theme';
-
-const TRIAL_DURATION_DAYS = 14;
-
-export default function UpgradeOrganizationAdvantages() {
- return (
- <ul className="note">
- <Advantage>{translate('billing.upgrade_box.unlimited_private_projects')}</Advantage>
- <Advantage>{translate('billing.upgrade_box.strict_control_private_data')}</Advantage>
- <Advantage>{translate('billing.upgrade_box.cancel_anytime')}</Advantage>
- <Advantage>
- <strong>
- {translateWithParameters('billing.upgrade_box.free_trial_x', TRIAL_DURATION_DAYS)}
- </strong>
- </Advantage>
- </ul>
- );
-}
-
-export function Advantage({ children }: { children: React.ReactNode }) {
- return (
- <li className="display-flex-center little-spacer-bottom">
- <CheckIcon className="spacer-right" fill={colors.lightGreen} />
- {children}
- </li>
- );
-}
diff --git a/server/sonar-web/src/main/js/apps/create/components/UpgradeOrganizationBox.tsx b/server/sonar-web/src/main/js/apps/create/components/UpgradeOrganizationBox.tsx
deleted file mode 100644
index c5466166692..00000000000
--- a/server/sonar-web/src/main/js/apps/create/components/UpgradeOrganizationBox.tsx
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import * as React from 'react';
-import { FormattedMessage } from 'react-intl';
-import { Link } from 'react-router';
-import { Button } from 'sonar-ui-common/components/controls/buttons';
-import RadioCard from 'sonar-ui-common/components/controls/RadioCard';
-import { hasMessage, translate } from 'sonar-ui-common/helpers/l10n';
-import { getSubscriptionPlans } from '../../../api/billing';
-import { formatPrice } from '../organization/utils';
-import UpgradeOrganizationAdvantages from './UpgradeOrganizationAdvantages';
-import UpgradeOrganizationModal from './UpgradeOrganizationModal';
-
-interface Props {
- className?: string;
- insideModal?: boolean;
- onOrganizationUpgrade: () => void;
- organization: T.Organization;
-}
-
-interface State {
- subscriptionPlans: T.SubscriptionPlan[];
- upgradeOrganizationModal: boolean;
-}
-
-export default class UpgradeOrganizationBox extends React.PureComponent<Props, State> {
- mounted = false;
- state: State = { subscriptionPlans: [], upgradeOrganizationModal: false };
-
- componentDidMount() {
- this.mounted = true;
- this.fetchSubscriptionPlans();
- }
-
- componentWillUnmount() {
- this.mounted = false;
- }
-
- fetchSubscriptionPlans = () => {
- return getSubscriptionPlans().then(subscriptionPlans => {
- if (this.mounted) {
- this.setState({ subscriptionPlans });
- }
- });
- };
-
- handleUpgradeClick = () => {
- this.setState({ upgradeOrganizationModal: true });
- };
-
- handleUpgradeOrganizationModalClose = () => {
- if (this.mounted) {
- this.setState({ upgradeOrganizationModal: false });
- }
- };
-
- handleOrganizationUpgrade = () => {
- this.props.onOrganizationUpgrade();
- this.handleUpgradeOrganizationModalClose();
- };
-
- render() {
- if (!hasMessage('billing.upgrade_box.header')) {
- return null;
- }
-
- const { subscriptionPlans, upgradeOrganizationModal } = this.state;
- const startingPrice = subscriptionPlans[0] && subscriptionPlans[0].price;
-
- return (
- <>
- <RadioCard
- className={this.props.className}
- title={translate('billing.upgrade_box.header')}
- titleInfo={
- startingPrice !== undefined && (
- <FormattedMessage
- defaultMessage={translate('billing.price_from_x')}
- id="billing.price_from_x"
- values={{
- price: <span className="big">{formatPrice(startingPrice)}</span>
- }}
- />
- )
- }>
- <>
- <UpgradeOrganizationAdvantages />
- <div className="big-spacer-left">
- <Button className="js-upgrade-organization" onClick={this.handleUpgradeClick}>
- {translate('billing.paid_plan.upgrade')}
- </Button>
- <Link className="spacer-left" target="_blank" to="/about/pricing">
- {translate('billing.pricing.learn_more')}
- </Link>
- </div>
- </>
- </RadioCard>
- {upgradeOrganizationModal && (
- <UpgradeOrganizationModal
- insideModal={this.props.insideModal}
- onClose={this.handleUpgradeOrganizationModalClose}
- onUpgradeDone={this.handleOrganizationUpgrade}
- organization={this.props.organization}
- subscriptionPlans={subscriptionPlans}
- />
- )}
- </>
- );
- }
-}
diff --git a/server/sonar-web/src/main/js/apps/create/components/UpgradeOrganizationModal.tsx b/server/sonar-web/src/main/js/apps/create/components/UpgradeOrganizationModal.tsx
deleted file mode 100644
index 7e1b63ae176..00000000000
--- a/server/sonar-web/src/main/js/apps/create/components/UpgradeOrganizationModal.tsx
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import * as React from 'react';
-import { FormattedMessage } from 'react-intl';
-import { ResetButtonLink } from 'sonar-ui-common/components/controls/buttons';
-import Modal from 'sonar-ui-common/components/controls/Modal';
-import DeferredSpinner from 'sonar-ui-common/components/ui/DeferredSpinner';
-import { translate } from 'sonar-ui-common/helpers/l10n';
-import { withCurrentUser } from '../../../components/hoc/withCurrentUser';
-import { getExtensionStart } from '../../../helpers/extensions';
-import BillingFormShim from './BillingFormShim';
-import UpgradeOrganizationAdvantages from './UpgradeOrganizationAdvantages';
-
-const BillingForm = withCurrentUser(BillingFormShim);
-
-interface Props {
- insideModal?: boolean;
- onUpgradeDone: () => void;
- onClose: () => void;
- organization: T.Organization;
- subscriptionPlans: T.SubscriptionPlan[];
-}
-
-interface State {
- ready: boolean;
-}
-
-export default class UpgradeOrganizationModal extends React.PureComponent<Props, State> {
- mounted = false;
- state: State = { ready: false };
-
- componentDidMount() {
- this.mounted = true;
- getExtensionStart('billing/billing').then(
- () => {
- if (this.mounted) {
- this.setState({ ready: true });
- }
- },
- () => {}
- );
- }
-
- componentWillUnmount() {
- this.mounted = false;
- }
-
- render() {
- const header = translate('billing.upgrade_box.upgrade_to_paid_plan');
-
- if (!this.state.ready) {
- return null;
- }
-
- return (
- <Modal
- contentLabel={header}
- noBackdrop={this.props.insideModal}
- onRequestClose={this.props.onClose}
- shouldCloseOnOverlayClick={false}
- size="medium">
- <div className="modal-head">
- <h2>{header}</h2>
- </div>
- <BillingForm
- onCommit={this.props.onUpgradeDone}
- organizationKey={this.props.organization.key}
- subscriptionPlans={this.props.subscriptionPlans}>
- {({
- onSubmit,
- processingUpgrade,
- renderFormFields,
- renderNextCharge,
- renderRecap,
- renderSubmitButton
- }) => (
- <form id="organization-paid-plan-form" onSubmit={onSubmit}>
- <div className="modal-body modal-container">
- <div className="huge-spacer-bottom">
- <p className="spacer-bottom">
- <FormattedMessage
- defaultMessage={translate('billing.upgrade.org_x_advantages')}
- id="billing.coupon.description"
- values={{
- org: <strong>{this.props.organization.name}</strong>
- }}
- />
- </p>
- <UpgradeOrganizationAdvantages />
- </div>
- {renderFormFields()}
- <div className="big-spacer-top">{renderRecap()}</div>
- </div>
- <footer className="modal-foot display-flex-center display-flex-space-between">
- {renderNextCharge() || <span />}
- <div>
- <DeferredSpinner loading={processingUpgrade} />
- {renderSubmitButton()}
- <ResetButtonLink onClick={this.props.onClose}>
- {translate('cancel')}
- </ResetButtonLink>
- </div>
- </footer>
- </form>
- )}
- </BillingForm>
- </Modal>
- );
- }
-}
diff --git a/server/sonar-web/src/main/js/apps/create/components/__mocks__/BillingFormShim.tsx b/server/sonar-web/src/main/js/apps/create/components/__mocks__/BillingFormShim.tsx
deleted file mode 100644
index ce16888ffaf..00000000000
--- a/server/sonar-web/src/main/js/apps/create/components/__mocks__/BillingFormShim.tsx
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import * as React from 'react';
-
-export default class BillingFormShim extends React.Component<{ children: any }> {
- render() {
- return (
- <div id="BillingFormShim">
- {this.props.children({
- onSubmit: jest.fn(),
- processingUpgrade: true,
- renderFormFields: () => <div id="form-fields" />,
- renderNextCharge: () => <div id="form-next-charge" />,
- renderRecap: () => <div id="form-recap" />,
- renderSubmitButton: () => <div id="form-submit" />,
- renderSubmitGroup: () => <div id="submit-group" />
- })}
- </div>
- );
- }
-}
diff --git a/server/sonar-web/src/main/js/apps/create/components/__tests__/BillingFormShim-test.tsx b/server/sonar-web/src/main/js/apps/create/components/__tests__/BillingFormShim-test.tsx
deleted file mode 100644
index 1fb03480e3f..00000000000
--- a/server/sonar-web/src/main/js/apps/create/components/__tests__/BillingFormShim-test.tsx
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import { shallow } from 'enzyme';
-import * as React from 'react';
-import BillingFormShim from '../BillingFormShim';
-
-beforeAll(() => {
- function BillingForm() {
- return <div id="billing-form" />;
- }
-
- (window as any).SonarBilling = { BillingForm };
-});
-
-afterAll(() => {
- delete (window as any).SonarBilling;
-});
-
-it('should render', () => {
- expect(
- shallow(
- <BillingFormShim
- currentUser={{ isLoggedIn: false }}
- onCommit={jest.fn()}
- organizationKey="org"
- subscriptionPlans={[]}>
- {() => <div id="inner-billing-form" />}
- </BillingFormShim>
- )
- ).toMatchSnapshot();
-});
diff --git a/server/sonar-web/src/main/js/apps/create/components/__tests__/OrganizationAvatarInput-test.tsx b/server/sonar-web/src/main/js/apps/create/components/__tests__/OrganizationAvatarInput-test.tsx
deleted file mode 100644
index 55a2ca81896..00000000000
--- a/server/sonar-web/src/main/js/apps/create/components/__tests__/OrganizationAvatarInput-test.tsx
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import { shallow } from 'enzyme';
-import * as React from 'react';
-import OrganizationAvatarInput from '../OrganizationAvatarInput';
-
-it('should render correctly', () => {
- const wrapper = shallow(
- <OrganizationAvatarInput initialValue="https://my.avatar" onChange={jest.fn()} />
- );
- expect(wrapper).toMatchSnapshot();
- wrapper.setState({ touched: true });
- expect(wrapper.find('ValidationInput').prop('isValid')).toMatchSnapshot();
-});
-
-it('should have an error when the avatar url is not valid', () => {
- expect(
- shallow(<OrganizationAvatarInput initialValue="whatever" onChange={jest.fn()} />)
- .find('ValidationInput')
- .prop('isInvalid')
- ).toBe(true);
-});
-
-it('should display the fallback avatar when there is no url', () => {
- expect(
- shallow(<OrganizationAvatarInput initialValue="" name="Luke Skywalker" onChange={jest.fn()} />)
- ).toMatchSnapshot();
-});
diff --git a/server/sonar-web/src/main/js/apps/create/components/__tests__/OrganizationKeyInput-test.tsx b/server/sonar-web/src/main/js/apps/create/components/__tests__/OrganizationKeyInput-test.tsx
deleted file mode 100644
index 667114a0da0..00000000000
--- a/server/sonar-web/src/main/js/apps/create/components/__tests__/OrganizationKeyInput-test.tsx
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import { shallow } from 'enzyme';
-import * as React from 'react';
-import { waitAndUpdate } from 'sonar-ui-common/helpers/testUtils';
-import { getOrganization } from '../../../../api/organizations';
-import OrganizationKeyInput from '../OrganizationKeyInput';
-
-jest.mock('../../../../api/organizations', () => ({
- getOrganization: jest.fn().mockResolvedValue(undefined)
-}));
-
-beforeEach(() => {
- (getOrganization as jest.Mock<any>).mockClear();
-});
-
-it('should render correctly', async () => {
- const wrapper = shallow(<OrganizationKeyInput initialValue="key" onChange={jest.fn()} />);
- expect(wrapper).toMatchSnapshot();
- wrapper.setState({ touched: true });
- await waitAndUpdate(wrapper);
- expect(wrapper.find('ValidationInput').prop('isValid')).toBe(true);
-});
-
-it('should not display any status when the key is not defined', async () => {
- const wrapper = shallow(<OrganizationKeyInput onChange={jest.fn()} />);
- await waitAndUpdate(wrapper);
- expect(wrapper.find('ValidationInput').prop('isInvalid')).toBe(false);
- expect(wrapper.find('ValidationInput').prop('isValid')).toBe(false);
-});
-
-it('should have an error when the key is invalid', async () => {
- const wrapper = shallow(
- <OrganizationKeyInput initialValue="KEy-with#speci@l_char" onChange={jest.fn()} />
- );
- await waitAndUpdate(wrapper);
- expect(wrapper.find('ValidationInput').prop('isInvalid')).toBe(true);
-});
-
-it('should have an error when the key already exists', async () => {
- (getOrganization as jest.Mock<any>).mockResolvedValue({});
- const wrapper = shallow(<OrganizationKeyInput initialValue="" onChange={jest.fn()} />);
- await waitAndUpdate(wrapper);
- expect(wrapper.find('ValidationInput').prop('isInvalid')).toBe(true);
-});
diff --git a/server/sonar-web/src/main/js/apps/create/components/__tests__/OrganizationSelect-test.tsx b/server/sonar-web/src/main/js/apps/create/components/__tests__/OrganizationSelect-test.tsx
deleted file mode 100644
index f248defd48b..00000000000
--- a/server/sonar-web/src/main/js/apps/create/components/__tests__/OrganizationSelect-test.tsx
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import { shallow } from 'enzyme';
-import * as React from 'react';
-import { mockOrganization, mockOrganizationWithAlm } from '../../../../helpers/testMocks';
-import OrganizationSelect, { getOptionRenderer } from '../OrganizationSelect';
-
-const organizations = [mockOrganization(), mockOrganizationWithAlm({ key: 'bar', name: 'Bar' })];
-
-it('should render correctly', () => {
- expect(
- shallow(
- <OrganizationSelect onChange={jest.fn()} organization="bar" organizations={organizations} />
- )
- ).toMatchSnapshot();
-});
-
-it('should render options correctly', () => {
- expect(shallow(getOptionRenderer()(organizations[0]))).toMatchSnapshot();
- expect(shallow(getOptionRenderer()(organizations[1]))).toMatchSnapshot();
- expect(shallow(getOptionRenderer(true)(organizations[0]))).toMatchSnapshot();
-});
diff --git a/server/sonar-web/src/main/js/apps/create/components/__tests__/OrganizationUrlInput-test.tsx b/server/sonar-web/src/main/js/apps/create/components/__tests__/OrganizationUrlInput-test.tsx
deleted file mode 100644
index bda1bd73d4a..00000000000
--- a/server/sonar-web/src/main/js/apps/create/components/__tests__/OrganizationUrlInput-test.tsx
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import { shallow } from 'enzyme';
-import * as React from 'react';
-import OrganizationUrlInput from '../OrganizationUrlInput';
-
-it('should render correctly', () => {
- const wrapper = shallow(
- <OrganizationUrlInput initialValue="http://my.website" onChange={jest.fn()} />
- );
- expect(wrapper).toMatchSnapshot();
- wrapper.setState({ touched: true });
- expect(wrapper.find('ValidationInput').prop('isValid')).toMatchSnapshot();
-});
-
-it('should have an error when the url is invalid', () => {
- expect(
- shallow(<OrganizationUrlInput initialValue="whatever" onChange={jest.fn()} />)
- .find('ValidationInput')
- .prop('isInvalid')
- ).toBe(true);
-});
diff --git a/server/sonar-web/src/main/js/apps/create/components/__tests__/PaidCardPlan-test.tsx b/server/sonar-web/src/main/js/apps/create/components/__tests__/PaidCardPlan-test.tsx
deleted file mode 100644
index 5e6e7f55256..00000000000
--- a/server/sonar-web/src/main/js/apps/create/components/__tests__/PaidCardPlan-test.tsx
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import { shallow } from 'enzyme';
-import * as React from 'react';
-import PaidCardPlan from '../PaidCardPlan';
-
-it('should render correctly', () => {
- expect(shallow(<PaidCardPlan isRecommended={true} startingPrice={10} />)).toMatchSnapshot();
-});
diff --git a/server/sonar-web/src/main/js/apps/create/components/__tests__/UpgradeOrganizationAdvantages-test.tsx b/server/sonar-web/src/main/js/apps/create/components/__tests__/UpgradeOrganizationAdvantages-test.tsx
deleted file mode 100644
index 388b00f408b..00000000000
--- a/server/sonar-web/src/main/js/apps/create/components/__tests__/UpgradeOrganizationAdvantages-test.tsx
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import { shallow } from 'enzyme';
-import * as React from 'react';
-import UpgradeOrganizationAdvantages from '../UpgradeOrganizationAdvantages';
-
-it('should render correctly', () => {
- expect(shallow(<UpgradeOrganizationAdvantages />)).toMatchSnapshot();
-});
diff --git a/server/sonar-web/src/main/js/apps/create/components/__tests__/UpgradeOrganizationBox-test.tsx b/server/sonar-web/src/main/js/apps/create/components/__tests__/UpgradeOrganizationBox-test.tsx
deleted file mode 100644
index ad1bab841e8..00000000000
--- a/server/sonar-web/src/main/js/apps/create/components/__tests__/UpgradeOrganizationBox-test.tsx
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import { shallow } from 'enzyme';
-import * as React from 'react';
-import { hasMessage } from 'sonar-ui-common/helpers/l10n';
-import { click, waitAndUpdate } from 'sonar-ui-common/helpers/testUtils';
-import { getSubscriptionPlans } from '../../../../api/billing';
-import UpgradeOrganizationBox from '../UpgradeOrganizationBox';
-
-jest.mock('sonar-ui-common/helpers/l10n', () => ({
- ...jest.requireActual('sonar-ui-common/helpers/l10n'),
- hasMessage: jest.fn().mockReturnValue(true)
-}));
-
-jest.mock('../../../../api/billing', () => ({
- getSubscriptionPlans: jest.fn().mockResolvedValue([{ maxNcloc: 100000, price: 10 }])
-}));
-
-const organization = { key: 'foo', name: 'Foo' };
-
-beforeEach(() => {
- (hasMessage as jest.Mock<any>).mockClear();
- (getSubscriptionPlans as jest.Mock<any>).mockClear();
-});
-
-it('should not render', () => {
- (hasMessage as jest.Mock<any>).mockReturnValueOnce(false);
- expect(
- shallow(
- <UpgradeOrganizationBox onOrganizationUpgrade={jest.fn()} organization={organization} />
- ).type()
- ).toBeNull();
-});
-
-it('should render correctly', async () => {
- const wrapper = shallow(
- <UpgradeOrganizationBox onOrganizationUpgrade={jest.fn()} organization={organization} />
- );
- await waitAndUpdate(wrapper);
- expect(getSubscriptionPlans).toHaveBeenCalled();
- expect(wrapper).toMatchSnapshot();
- click(wrapper.find('Button'));
- expect(wrapper.find('UpgradeOrganizationModal').exists()).toBe(true);
-});
diff --git a/server/sonar-web/src/main/js/apps/create/components/__tests__/UpgradeOrganizationModal-test.tsx b/server/sonar-web/src/main/js/apps/create/components/__tests__/UpgradeOrganizationModal-test.tsx
deleted file mode 100644
index b68be4d410d..00000000000
--- a/server/sonar-web/src/main/js/apps/create/components/__tests__/UpgradeOrganizationModal-test.tsx
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import { shallow } from 'enzyme';
-import * as React from 'react';
-import { waitAndUpdate } from 'sonar-ui-common/helpers/testUtils';
-import { getExtensionStart } from '../../../../helpers/extensions';
-import UpgradeOrganizationModal from '../UpgradeOrganizationModal';
-
-jest.mock('../../../../helpers/extensions', () => ({
- getExtensionStart: jest.fn().mockResolvedValue(undefined)
-}));
-
-const organization = { key: 'foo', name: 'Foo' };
-
-it('should render correctly', async () => {
- const wrapper = shallow(
- <UpgradeOrganizationModal
- onClose={jest.fn()}
- onUpgradeDone={jest.fn()}
- organization={organization}
- subscriptionPlans={[]}
- />
- );
- await waitAndUpdate(wrapper);
- expect(getExtensionStart).toHaveBeenCalled();
- expect(wrapper).toMatchSnapshot();
-});
diff --git a/server/sonar-web/src/main/js/apps/create/components/__tests__/__snapshots__/BillingFormShim-test.tsx.snap b/server/sonar-web/src/main/js/apps/create/components/__tests__/__snapshots__/BillingFormShim-test.tsx.snap
deleted file mode 100644
index fc6fb48982e..00000000000
--- a/server/sonar-web/src/main/js/apps/create/components/__tests__/__snapshots__/BillingFormShim-test.tsx.snap
+++ /dev/null
@@ -1,16 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render 1`] = `
-<BillingForm
- currentUser={
- Object {
- "isLoggedIn": false,
- }
- }
- onCommit={[MockFunction]}
- organizationKey="org"
- subscriptionPlans={Array []}
->
- <Component />
-</BillingForm>
-`;
diff --git a/server/sonar-web/src/main/js/apps/create/components/__tests__/__snapshots__/FreeCardPlan-test.tsx.snap b/server/sonar-web/src/main/js/apps/create/components/__tests__/__snapshots__/FreeCardPlan-test.tsx.snap
deleted file mode 100644
index 096ad74b503..00000000000
--- a/server/sonar-web/src/main/js/apps/create/components/__tests__/__snapshots__/FreeCardPlan-test.tsx.snap
+++ /dev/null
@@ -1,101 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render 1`] = `
-<RadioCard
- title="billing.free_plan.title"
- titleInfo="billing.price_format.0"
->
- <div
- className="spacer-left"
- >
- <ul
- className="big-spacer-left note"
- >
- <li
- className="little-spacer-bottom"
- >
- billing.free_plan.all_projects_analyzed_public
- </li>
- <li>
- billing.free_plan.anyone_can_browse_source_code
- </li>
- </ul>
- </div>
-</RadioCard>
-`;
-
-exports[`should render disabled with info 1`] = `
-<RadioCard
- disabled={true}
- title="billing.free_plan.title"
- titleInfo="billing.price_format.0"
->
- <div
- className="spacer-left"
- >
- <ul
- className="big-spacer-left note"
- >
- <li
- className="little-spacer-bottom"
- >
- billing.free_plan.all_projects_analyzed_public
- </li>
- <li>
- billing.free_plan.anyone_can_browse_source_code
- </li>
- </ul>
- </div>
- <Alert
- variant="info"
- >
- <FormattedMessage
- defaultMessage="billing.free_plan.not_available_info"
- id="billing.free_plan.not_available_info"
- values={
- Object {
- "alm": "GitHub",
- }
- }
- />
- </Alert>
-</RadioCard>
-`;
-
-exports[`should render with warning 1`] = `
-<RadioCard
- selected={true}
- title="billing.free_plan.title"
- titleInfo="billing.price_format.0"
->
- <div
- className="spacer-left"
- >
- <ul
- className="big-spacer-left note"
- >
- <li
- className="little-spacer-bottom"
- >
- billing.free_plan.all_projects_analyzed_public
- </li>
- <li>
- billing.free_plan.anyone_can_browse_source_code
- </li>
- </ul>
- </div>
- <Alert
- variant="warning"
- >
- <FormattedMessage
- defaultMessage="billing.free_plan.private_repo_warning"
- id="billing.free_plan.private_repo_warning"
- values={
- Object {
- "alm": "GitHub",
- }
- }
- />
- </Alert>
-</RadioCard>
-`;
diff --git a/server/sonar-web/src/main/js/apps/create/components/__tests__/__snapshots__/OrganizationAvatarInput-test.tsx.snap b/server/sonar-web/src/main/js/apps/create/components/__tests__/__snapshots__/OrganizationAvatarInput-test.tsx.snap
deleted file mode 100644
index a2f801bc5d4..00000000000
--- a/server/sonar-web/src/main/js/apps/create/components/__tests__/__snapshots__/OrganizationAvatarInput-test.tsx.snap
+++ /dev/null
@@ -1,63 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should display the fallback avatar when there is no url 1`] = `
-<ValidationInput
- description="onboarding.create_organization.avatar.description"
- id="organization-avatar"
- isInvalid={false}
- isValid={false}
- label="onboarding.create_organization.avatar"
->
- <OrganizationAvatar
- className="display-block spacer-bottom"
- organization={
- Object {
- "avatar": undefined,
- "name": "Luke Skywalker",
- }
- }
- />
- <input
- className="input-super-large text-middle"
- id="organization-avatar"
- onBlur={[Function]}
- onChange={[Function]}
- onFocus={[Function]}
- placeholder="onboarding.create_organization.avatar.placeholder"
- type="text"
- value=""
- />
-</ValidationInput>
-`;
-
-exports[`should render correctly 1`] = `
-<ValidationInput
- description="onboarding.create_organization.avatar.description"
- id="organization-avatar"
- isInvalid={false}
- isValid={false}
- label="onboarding.create_organization.avatar"
->
- <OrganizationAvatar
- className="display-block spacer-bottom"
- organization={
- Object {
- "avatar": "https://my.avatar",
- "name": "",
- }
- }
- />
- <input
- className="input-super-large text-middle"
- id="organization-avatar"
- onBlur={[Function]}
- onChange={[Function]}
- onFocus={[Function]}
- placeholder="onboarding.create_organization.avatar.placeholder"
- type="text"
- value="https://my.avatar"
- />
-</ValidationInput>
-`;
-
-exports[`should render correctly 2`] = `true`;
diff --git a/server/sonar-web/src/main/js/apps/create/components/__tests__/__snapshots__/OrganizationKeyInput-test.tsx.snap b/server/sonar-web/src/main/js/apps/create/components/__tests__/__snapshots__/OrganizationKeyInput-test.tsx.snap
deleted file mode 100644
index 5a4f352f826..00000000000
--- a/server/sonar-web/src/main/js/apps/create/components/__tests__/__snapshots__/OrganizationKeyInput-test.tsx.snap
+++ /dev/null
@@ -1,30 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render correctly 1`] = `
-<ValidationInput
- id="organization-key"
- isInvalid={false}
- isValid={false}
- label="onboarding.create_organization.organization_name"
- required={true}
->
- <div
- className="display-inline-flex-baseline"
- >
- <span
- className="little-spacer-right"
- >
- localhost/organizations/
- </span>
- <input
- autoFocus={true}
- className="input-super-large"
- id="organization-key"
- maxLength={255}
- onChange={[Function]}
- type="text"
- value="key"
- />
- </div>
-</ValidationInput>
-`;
diff --git a/server/sonar-web/src/main/js/apps/create/components/__tests__/__snapshots__/OrganizationSelect-test.tsx.snap b/server/sonar-web/src/main/js/apps/create/components/__tests__/__snapshots__/OrganizationSelect-test.tsx.snap
deleted file mode 100644
index 46e9dbfcba1..00000000000
--- a/server/sonar-web/src/main/js/apps/create/components/__tests__/__snapshots__/OrganizationSelect-test.tsx.snap
+++ /dev/null
@@ -1,99 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render correctly 1`] = `
-<Select
- autoFocus={false}
- className="input-super-large"
- clearable={false}
- id="select-organization"
- labelKey="name"
- onChange={[MockFunction]}
- optionRenderer={[Function]}
- options={
- Array [
- Object {
- "alm": Object {
- "key": "github",
- "membersSync": false,
- "personal": false,
- "url": "https://github.com/foo",
- },
- "key": "bar",
- "name": "Bar",
- },
- Object {
- "key": "foo",
- "name": "Foo",
- },
- ]
- }
- placeholder="onboarding.import_organization.choose_organization"
- required={true}
- value="bar"
- valueKey="key"
- valueRenderer={[Function]}
-/>
-`;
-
-exports[`should render options correctly 1`] = `
-<div
- className="display-flex-space-between"
->
- <span
- className="text-ellipsis flex-1"
- >
- <img
- alt="SonarCloud"
- className="little-spacer-right"
- height={14}
- src="/images/sonarcloud-square-logo.svg"
- />
- Foo
- <span
- className="note little-spacer-left"
- >
- foo
- </span>
- </span>
-</div>
-`;
-
-exports[`should render options correctly 2`] = `
-<div
- className="display-flex-space-between"
->
- <span
- className="text-ellipsis flex-1"
- >
- <img
- alt="github"
- className="little-spacer-right"
- height={14}
- src="/images/sonarcloud/github.svg"
- />
- Bar
- <span
- className="note little-spacer-left"
- >
- bar
- </span>
- </span>
-</div>
-`;
-
-exports[`should render options correctly 3`] = `
-<div
- className="display-flex-space-between"
->
- <span
- className="text-ellipsis flex-1"
- >
- Foo
- <span
- className="note little-spacer-left"
- >
- foo
- </span>
- </span>
-</div>
-`;
diff --git a/server/sonar-web/src/main/js/apps/create/components/__tests__/__snapshots__/OrganizationUrlInput-test.tsx.snap b/server/sonar-web/src/main/js/apps/create/components/__tests__/__snapshots__/OrganizationUrlInput-test.tsx.snap
deleted file mode 100644
index d3f571b4db8..00000000000
--- a/server/sonar-web/src/main/js/apps/create/components/__tests__/__snapshots__/OrganizationUrlInput-test.tsx.snap
+++ /dev/null
@@ -1,22 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render correctly 1`] = `
-<ValidationInput
- id="organization-url"
- isInvalid={false}
- isValid={false}
- label="onboarding.create_organization.url"
->
- <input
- className="input-super-large text-middle"
- id="organization-url"
- onBlur={[Function]}
- onChange={[Function]}
- onFocus={[Function]}
- type="text"
- value="http://my.website"
- />
-</ValidationInput>
-`;
-
-exports[`should render correctly 2`] = `true`;
diff --git a/server/sonar-web/src/main/js/apps/create/components/__tests__/__snapshots__/PaidCardPlan-test.tsx.snap b/server/sonar-web/src/main/js/apps/create/components/__tests__/__snapshots__/PaidCardPlan-test.tsx.snap
deleted file mode 100644
index 94ac5a89244..00000000000
--- a/server/sonar-web/src/main/js/apps/create/components/__tests__/__snapshots__/PaidCardPlan-test.tsx.snap
+++ /dev/null
@@ -1,38 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render correctly 1`] = `
-<RadioCard
- recommended="billing.paid_plan.recommended"
- title="billing.paid_plan.title"
- titleInfo={
- <FormattedMessage
- defaultMessage="billing.price_from_x"
- id="billing.price_from_x"
- values={
- Object {
- "price": <span
- className="big"
- >
- billing.price_format.10
- </span>,
- }
- }
- />
- }
->
- <UpgradeOrganizationAdvantages />
- <div
- className="big-spacer-left"
- >
- <Link
- className="spacer-left"
- onlyActiveOnIndex={false}
- style={Object {}}
- target="_blank"
- to="/about/pricing"
- >
- billing.pricing.learn_more
- </Link>
- </div>
-</RadioCard>
-`;
diff --git a/server/sonar-web/src/main/js/apps/create/components/__tests__/__snapshots__/UpgradeOrganizationAdvantages-test.tsx.snap b/server/sonar-web/src/main/js/apps/create/components/__tests__/__snapshots__/UpgradeOrganizationAdvantages-test.tsx.snap
deleted file mode 100644
index dce3b0b46e6..00000000000
--- a/server/sonar-web/src/main/js/apps/create/components/__tests__/__snapshots__/UpgradeOrganizationAdvantages-test.tsx.snap
+++ /dev/null
@@ -1,22 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render correctly 1`] = `
-<ul
- className="note"
->
- <Advantage>
- billing.upgrade_box.unlimited_private_projects
- </Advantage>
- <Advantage>
- billing.upgrade_box.strict_control_private_data
- </Advantage>
- <Advantage>
- billing.upgrade_box.cancel_anytime
- </Advantage>
- <Advantage>
- <strong>
- billing.upgrade_box.free_trial_x.14
- </strong>
- </Advantage>
-</ul>
-`;
diff --git a/server/sonar-web/src/main/js/apps/create/components/__tests__/__snapshots__/UpgradeOrganizationBox-test.tsx.snap b/server/sonar-web/src/main/js/apps/create/components/__tests__/__snapshots__/UpgradeOrganizationBox-test.tsx.snap
deleted file mode 100644
index e389049612a..00000000000
--- a/server/sonar-web/src/main/js/apps/create/components/__tests__/__snapshots__/UpgradeOrganizationBox-test.tsx.snap
+++ /dev/null
@@ -1,45 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render correctly 1`] = `
-<Fragment>
- <RadioCard
- title="billing.upgrade_box.header"
- titleInfo={
- <FormattedMessage
- defaultMessage="billing.price_from_x"
- id="billing.price_from_x"
- values={
- Object {
- "price": <span
- className="big"
- >
- billing.price_format.10
- </span>,
- }
- }
- />
- }
- >
- <UpgradeOrganizationAdvantages />
- <div
- className="big-spacer-left"
- >
- <Button
- className="js-upgrade-organization"
- onClick={[Function]}
- >
- billing.paid_plan.upgrade
- </Button>
- <Link
- className="spacer-left"
- onlyActiveOnIndex={false}
- style={Object {}}
- target="_blank"
- to="/about/pricing"
- >
- billing.pricing.learn_more
- </Link>
- </div>
- </RadioCard>
-</Fragment>
-`;
diff --git a/server/sonar-web/src/main/js/apps/create/components/__tests__/__snapshots__/UpgradeOrganizationModal-test.tsx.snap b/server/sonar-web/src/main/js/apps/create/components/__tests__/__snapshots__/UpgradeOrganizationModal-test.tsx.snap
deleted file mode 100644
index 4d294fc1497..00000000000
--- a/server/sonar-web/src/main/js/apps/create/components/__tests__/__snapshots__/UpgradeOrganizationModal-test.tsx.snap
+++ /dev/null
@@ -1,25 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render correctly 1`] = `
-<Modal
- contentLabel="billing.upgrade_box.upgrade_to_paid_plan"
- onRequestClose={[MockFunction]}
- shouldCloseOnOverlayClick={false}
- size="medium"
->
- <div
- className="modal-head"
- >
- <h2>
- billing.upgrade_box.upgrade_to_paid_plan
- </h2>
- </div>
- <Connect(withCurrentUser(BillingFormShim))
- onCommit={[MockFunction]}
- organizationKey="foo"
- subscriptionPlans={Array []}
- >
- <Component />
- </Connect(withCurrentUser(BillingFormShim))>
-</Modal>
-`;
diff --git a/server/sonar-web/src/main/js/apps/create/organization/AlmApplicationInstalling.tsx b/server/sonar-web/src/main/js/apps/create/organization/AlmApplicationInstalling.tsx
deleted file mode 100644
index d6b9dcebf01..00000000000
--- a/server/sonar-web/src/main/js/apps/create/organization/AlmApplicationInstalling.tsx
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import * as React from 'react';
-import DeferredSpinner from 'sonar-ui-common/components/ui/DeferredSpinner';
-import { translate, translateWithParameters } from 'sonar-ui-common/helpers/l10n';
-import { sanitizeAlmId } from '../../../helpers/almIntegrations';
-
-export default function AlmApplicationInstalling({ almKey }: { almKey?: string }) {
- return (
- <DeferredSpinner
- customSpinner={
- <div className="sonarcloud page page-limited">
- <div className="huge-spacer-top text-center">
- <i className="spinner" />
- <p className="big-spacer-top">
- {translateWithParameters(
- 'onboarding.import_organization.installing',
- almKey ? translate(sanitizeAlmId(almKey)) : 'ALM'
- )}
- </p>
- </div>
- </div>
- }
- />
- );
-}
diff --git a/server/sonar-web/src/main/js/apps/create/organization/AutoOrganizationBind.tsx b/server/sonar-web/src/main/js/apps/create/organization/AutoOrganizationBind.tsx
deleted file mode 100644
index 38d3862aa7d..00000000000
--- a/server/sonar-web/src/main/js/apps/create/organization/AutoOrganizationBind.tsx
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import * as React from 'react';
-import { Link } from 'react-router';
-import { SubmitButton } from 'sonar-ui-common/components/controls/buttons';
-import { Alert } from 'sonar-ui-common/components/ui/Alert';
-import DeferredSpinner from 'sonar-ui-common/components/ui/DeferredSpinner';
-import { translate, translateWithParameters } from 'sonar-ui-common/helpers/l10n';
-import { isGithub } from '../../../helpers/almIntegrations';
-import OrganizationSelect from '../components/OrganizationSelect';
-
-interface Props {
- almKey: string;
- onBindOrganization: (organization: string) => Promise<void>;
- unboundOrganizations: T.Organization[];
-}
-
-interface State {
- organization: string;
- submitting: boolean;
-}
-
-export default class AutoOrganizationBind extends React.PureComponent<Props, State> {
- mounted = false;
-
- constructor(props: Props) {
- super(props);
- this.state = { organization: this.getInitialSelectedOrganization(props), submitting: false };
- }
-
- componentDidMount() {
- this.mounted = true;
- }
-
- componentWillUnmount() {
- this.mounted = false;
- }
-
- getInitialSelectedOrganization(props: Props) {
- if (props.unboundOrganizations.length === 1) {
- return props.unboundOrganizations[0].key;
- }
- return '';
- }
-
- handleChange = ({ key }: T.Organization) => {
- this.setState({ organization: key });
- };
-
- handleSubmit = (event: React.FormEvent<HTMLFormElement>) => {
- event.preventDefault();
- const { organization } = this.state;
- if (organization) {
- this.setState({ submitting: true });
- this.props.onBindOrganization(organization).then(this.stopSubmitting, this.stopSubmitting);
- }
- };
-
- stopSubmitting = () => {
- if (this.mounted) {
- this.setState({ submitting: false });
- }
- };
-
- render() {
- const { almKey } = this.props;
- const { organization, submitting } = this.state;
- return (
- <form id="bind-organization-form" onSubmit={this.handleSubmit}>
- <OrganizationSelect
- onChange={this.handleChange}
- organization={organization}
- organizations={this.props.unboundOrganizations}
- />
- {isGithub(almKey) && (
- <Alert className="abs-width-400 big-spacer-top" display="block" variant="info">
- {translateWithParameters(
- 'onboarding.import_organization.bind_members_not_sync_info_x',
- translate('organization', almKey)
- )}
- <Link
- className="spacer-left"
- target="_blank"
- to={{ pathname: '/documentation/organizations/manage-team/' }}>
- {translate('learn_more')}
- </Link>
- </Alert>
- )}
- <div className="display-flex-center big-spacer-top">
- <SubmitButton disabled={submitting || !organization}>
- {translate('onboarding.import_organization.bind')}
- </SubmitButton>
- {submitting && <DeferredSpinner className="spacer-left" />}
- </div>
- </form>
- );
- }
-}
diff --git a/server/sonar-web/src/main/js/apps/create/organization/AutoOrganizationCreate.tsx b/server/sonar-web/src/main/js/apps/create/organization/AutoOrganizationCreate.tsx
deleted file mode 100644
index 1f0542b429c..00000000000
--- a/server/sonar-web/src/main/js/apps/create/organization/AutoOrganizationCreate.tsx
+++ /dev/null
@@ -1,215 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import * as React from 'react';
-import { FormattedMessage } from 'react-intl';
-import { ClearButton } from 'sonar-ui-common/components/controls/buttons';
-import RadioToggle from 'sonar-ui-common/components/controls/RadioToggle';
-import { Alert } from 'sonar-ui-common/components/ui/Alert';
-import { translate, translateWithParameters } from 'sonar-ui-common/helpers/l10n';
-import { getBaseUrl } from 'sonar-ui-common/helpers/urls';
-import { bindAlmOrganization } from '../../../api/alm-integration';
-import { getAlmMembersUrl, isGithub, sanitizeAlmId } from '../../../helpers/almIntegrations';
-import AutoOrganizationBind from './AutoOrganizationBind';
-import OrganizationDetailsForm from './OrganizationDetailsForm';
-import OrganizationDetailsStep from './OrganizationDetailsStep';
-import PlanStep from './PlanStep';
-import { Step } from './utils';
-
-enum Filters {
- Bind = 'bind',
- Create = 'create'
-}
-
-interface Props {
- almApplication: T.AlmApplication;
- almInstallId: string;
- almOrganization: T.AlmOrganization;
- className?: string;
- createOrganization: (
- organization: T.Organization & { installationId?: string }
- ) => Promise<string>;
- handleCancelImport: () => void;
- handleOrgDetailsFinish: (organization: T.Organization) => Promise<void>;
- handleOrgDetailsStepOpen: () => void;
- onDone: () => void;
- onOrgCreated: (organization: string) => void;
- onUpgradeFail: () => void;
- organization?: T.Organization;
- step: Step;
- subscriptionPlans?: T.SubscriptionPlan[];
- unboundOrganizations: T.Organization[];
-}
-
-interface State {
- filter?: Filters;
-}
-
-export default class AutoOrganizationCreate extends React.PureComponent<Props, State> {
- constructor(props: Props) {
- super(props);
- this.state = {
- filter: props.unboundOrganizations.length === 0 ? Filters.Create : undefined
- };
- }
-
- handleBindOrganization = (organization: string) => {
- return bindAlmOrganization({
- organization,
- installationId: this.props.almInstallId
- }).then(() => this.props.onOrgCreated(organization));
- };
-
- handleCreateOrganization = () => {
- const { almApplication, almOrganization, organization } = this.props;
- if (!organization) {
- return Promise.reject();
- }
- return this.props.createOrganization({
- ...organization,
- alm: {
- key: almApplication.key,
- membersSync: true,
- personal: almOrganization.personal,
- url: almOrganization.almUrl
- },
- installationId: this.props.almInstallId
- });
- };
-
- handleOptionChange = (filter: Filters) => {
- this.setState({ filter });
- };
-
- render() {
- const {
- almApplication,
- almOrganization,
- className,
- organization,
- step,
- subscriptionPlans,
- unboundOrganizations
- } = this.props;
- const { filter } = this.state;
- const hasUnboundOrgs = unboundOrganizations.length > 0;
- const almKey = sanitizeAlmId(almApplication.key);
- return (
- <div className={className}>
- <OrganizationDetailsStep
- finished={organization !== undefined}
- onOpen={this.props.handleOrgDetailsStepOpen}
- open={step === Step.OrganizationDetails}
- organization={organization}
- stepTitle={translate('onboarding.import_organization.import_org_details')}>
- <div className="huge-spacer-bottom">
- <p className="display-flex-center big-spacer-bottom">
- <FormattedMessage
- defaultMessage={translate('onboarding.import_organization_x')}
- id="onboarding.import_organization_x"
- values={{
- avatar: (
- <img
- alt={almApplication.name}
- className="little-spacer-left"
- src={`${getBaseUrl()}/images/sonarcloud/${sanitizeAlmId(
- almApplication.key
- )}.svg`}
- width={16}
- />
- ),
- name: <strong>{almOrganization.name}</strong>
- }}
- />
- <ClearButton className="little-spacer-left" onClick={this.props.handleCancelImport} />
- </p>
-
- {hasUnboundOrgs && (
- <RadioToggle
- name="filter"
- onCheck={this.handleOptionChange}
- options={[
- {
- label: translate('onboarding.import_organization.create_new'),
- value: Filters.Create
- },
- {
- label: translate('onboarding.import_organization.bind_existing'),
- value: Filters.Bind
- }
- ]}
- value={filter}
- />
- )}
- </div>
-
- {filter === Filters.Create && (
- <OrganizationDetailsForm
- infoBlock={
- isGithub(almKey) && (
- <Alert className="abs-width-600 big-spacer-top" display="block" variant="info">
- <p>
- {translateWithParameters(
- 'onboarding.import_organization.members_sync_info_x',
- translate('organization', almKey),
- almOrganization.name,
- translate(almKey)
- )}
- </p>
- <a
- href={getAlmMembersUrl(almApplication.key, almOrganization.almUrl)}
- rel="noopener noreferrer"
- target="_blank">
- {translateWithParameters(
- 'organization.members.see_all_members_on_x',
- translate(almKey)
- )}
- </a>
- </Alert>
- )
- }
- onContinue={this.props.handleOrgDetailsFinish}
- organization={almOrganization}
- submitText={translate('continue')}
- />
- )}
- {filter === Filters.Bind && (
- <AutoOrganizationBind
- almKey={almKey}
- onBindOrganization={this.handleBindOrganization}
- unboundOrganizations={unboundOrganizations}
- />
- )}
- </OrganizationDetailsStep>
-
- {subscriptionPlans !== undefined && filter !== Filters.Bind && (
- <PlanStep
- almApplication={this.props.almApplication}
- almOrganization={this.props.almOrganization}
- createOrganization={this.handleCreateOrganization}
- onDone={this.props.onDone}
- onUpgradeFail={this.props.onUpgradeFail}
- open={step === Step.Plan}
- subscriptionPlans={subscriptionPlans}
- />
- )}
- </div>
- );
- }
-}
diff --git a/server/sonar-web/src/main/js/apps/create/organization/CreateOrganization.tsx b/server/sonar-web/src/main/js/apps/create/organization/CreateOrganization.tsx
deleted file mode 100644
index ac6a60056f8..00000000000
--- a/server/sonar-web/src/main/js/apps/create/organization/CreateOrganization.tsx
+++ /dev/null
@@ -1,456 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import * as classNames from 'classnames';
-import * as differenceInMinutes from 'date-fns/difference_in_minutes';
-import { times } from 'lodash';
-import * as React from 'react';
-import { Helmet } from 'react-helmet-async';
-import { connect } from 'react-redux';
-import { withRouter, WithRouterProps } from 'react-router';
-import Tabs from 'sonar-ui-common/components/controls/Tabs';
-import DeferredSpinner from 'sonar-ui-common/components/ui/DeferredSpinner';
-import { translate, translateWithParameters } from 'sonar-ui-common/helpers/l10n';
-import { addWhitePageClass, removeWhitePageClass } from 'sonar-ui-common/helpers/pages';
-import { get, remove } from 'sonar-ui-common/helpers/storage';
-import { slugify } from 'sonar-ui-common/helpers/strings';
-import {
- bindAlmOrganization,
- getAlmAppInfo,
- getAlmOrganization,
- GetAlmOrganizationResponse,
- listUnboundApplications
-} from '../../../api/alm-integration';
-import { getSubscriptionPlans } from '../../../api/billing';
-import * as api from '../../../api/organizations';
-import A11ySkipTarget from '../../../app/components/a11y/A11ySkipTarget';
-import addGlobalSuccessMessage from '../../../app/utils/addGlobalSuccessMessage';
-import { whenLoggedIn } from '../../../components/hoc/whenLoggedIn';
-import { withUserOrganizations } from '../../../components/hoc/withUserOrganizations';
-import { hasAdvancedALMIntegration, sanitizeAlmId } from '../../../helpers/almIntegrations';
-import { getOrganizationUrl } from '../../../helpers/urls';
-import { skipOnboarding } from '../../../store/users';
-import { deleteOrganization } from '../../organizations/actions';
-import { createOrganization } from './actions';
-import AlmApplicationInstalling from './AlmApplicationInstalling';
-import AutoOrganizationCreate from './AutoOrganizationCreate';
-import ManualOrganizationCreate from './ManualOrganizationCreate';
-import RemoteOrganizationChoose from './RemoteOrganizationChoose';
-import {
- BIND_ORGANIZATION_KEY,
- BIND_ORGANIZATION_REDIRECT_TO_ORG_TIMESTAMP,
- ORGANIZATION_IMPORT_BINDING_IN_PROGRESS_TIMESTAMP,
- ORGANIZATION_IMPORT_REDIRECT_TO_PROJECT_TIMESTAMP,
- parseQuery,
- Query,
- serializeQuery,
- Step
-} from './utils';
-
-interface Props {
- createOrganization: (
- organization: T.Organization & { installationId?: string }
- ) => Promise<string>;
- currentUser: T.LoggedInUser;
- deleteOrganization: (key: string) => Promise<void>;
- userOrganizations: T.Organization[];
- skipOnboarding: () => void;
-}
-
-interface State {
- almApplication?: T.AlmApplication;
- almOrganization?: T.AlmOrganization;
- almOrgLoading: boolean;
- almUnboundApplications: T.AlmUnboundApplication[];
- bindingExistingOrg: boolean;
- boundOrganization?: T.OrganizationBase;
- loading: boolean;
- organization?: T.Organization;
- step: Step;
- subscriptionPlans?: T.SubscriptionPlan[];
-}
-
-type StateWithAutoImport = State & Required<Pick<State, 'almApplication'>>;
-
-type TabKeys = 'auto' | 'manual';
-
-interface LocationState {
- tab?: TabKeys;
-}
-
-export class CreateOrganization extends React.PureComponent<Props & WithRouterProps, State> {
- mounted = false;
- state: State = {
- almOrgLoading: false,
- almUnboundApplications: [],
- bindingExistingOrg: false,
- loading: true,
- step: Step.OrganizationDetails
- };
-
- componentDidMount() {
- this.mounted = true;
- addWhitePageClass();
-
- const query = parseQuery(this.props.location.query);
-
- //highjack the process for the organization settings
- if (
- hasAdvancedALMIntegration(this.props.currentUser) &&
- query.almInstallId &&
- this.isStoredTimestampValid(BIND_ORGANIZATION_REDIRECT_TO_ORG_TIMESTAMP)
- ) {
- this.bindAndRedirectToOrganizationSettings(query.almInstallId);
- } else {
- const initRequests = [this.fetchSubscriptionPlans()];
- if (hasAdvancedALMIntegration(this.props.currentUser)) {
- initRequests.push(this.fetchAlmApplication());
-
- if (query.almInstallId) {
- this.fetchAlmOrganization(query.almInstallId);
- } else {
- initRequests.push(this.fetchAlmUnboundApplications());
- }
- }
- Promise.all(initRequests).then(this.stopLoading, this.stopLoading);
- }
- }
-
- componentDidUpdate(prevProps: WithRouterProps) {
- const prevQuery = parseQuery(prevProps.location.query);
- const query = parseQuery(this.props.location.query);
- if (this.state.almApplication && prevQuery.almInstallId !== query.almInstallId) {
- if (query.almInstallId) {
- this.fetchAlmOrganization(query.almInstallId);
- } else {
- this.setState({ almOrganization: undefined, boundOrganization: undefined, loading: true });
- this.fetchAlmUnboundApplications().then(this.stopLoading, this.stopLoading);
- }
- }
- }
-
- componentWillUnmount() {
- this.mounted = false;
- removeWhitePageClass();
- }
-
- deleteOrganization = () => {
- if (this.state.organization) {
- this.props.deleteOrganization(this.state.organization.key);
- }
- };
-
- fetchAlmApplication = () => {
- return getAlmAppInfo().then(({ application }) => {
- if (this.mounted) {
- this.setState({ almApplication: application });
- }
- });
- };
-
- fetchAlmOrganization = (installationId: string) => {
- this.setState({ almOrgLoading: true });
- return getAlmOrganization({ installationId })
- .then(({ almOrganization, boundOrganization }) => {
- if (boundOrganization) {
- return { almOrganization, boundOrganization };
- }
- return this.setValidOrgKey(almOrganization);
- })
- .then(
- ({ almOrganization, boundOrganization }: GetAlmOrganizationResponse) => {
- if (this.mounted) {
- if (
- boundOrganization &&
- boundOrganization.key &&
- !this.isStoredTimestampValid(ORGANIZATION_IMPORT_BINDING_IN_PROGRESS_TIMESTAMP)
- ) {
- this.props.router.push({
- pathname: getOrganizationUrl(boundOrganization.key)
- });
- } else {
- this.setState({ almOrganization, almOrgLoading: false, boundOrganization });
- }
- }
- },
- () => {
- if (this.mounted) {
- this.setState({ almOrgLoading: false });
- }
- }
- );
- };
-
- fetchAlmUnboundApplications = () => {
- return listUnboundApplications().then(almUnboundApplications => {
- if (this.mounted) {
- this.setState({ almUnboundApplications });
- }
- });
- };
-
- fetchSubscriptionPlans = () => {
- return getSubscriptionPlans().then(subscriptionPlans => {
- if (this.mounted) {
- this.setState({ subscriptionPlans });
- }
- });
- };
-
- handleCancelImport = () => {
- this.updateUrlQuery({ almInstallId: undefined, almKey: undefined });
- };
-
- handleOrgCreated = (organization: string) => {
- this.props.skipOnboarding();
- if (this.isStoredTimestampValid(ORGANIZATION_IMPORT_REDIRECT_TO_PROJECT_TIMESTAMP)) {
- this.props.router.push({
- pathname: '/projects/create',
- state: { organization, tab: this.state.almOrganization ? 'auto' : 'manual' }
- });
- } else {
- this.props.router.push({ pathname: getOrganizationUrl(organization) });
- }
- };
-
- handleOrgDetailsFinish = (organization: T.Organization) => {
- this.setState({ organization, step: Step.Plan });
- return Promise.resolve();
- };
-
- handleOrgDetailsStepOpen = () => {
- this.setState({ step: Step.OrganizationDetails });
- };
-
- handlePlanDone = () => {
- if (this.state.organization) {
- this.handleOrgCreated(this.state.organization.key);
- }
- };
-
- hasAutoImport(state: State): state is StateWithAutoImport {
- return Boolean(state.almApplication);
- }
-
- isStoredTimestampValid = (timestampKey: string) => {
- const storedTimestamp = get(timestampKey);
- remove(timestampKey);
- return storedTimestamp && differenceInMinutes(Date.now(), Number(storedTimestamp)) < 10;
- };
-
- onTabChange = (tab: TabKeys) => {
- this.updateUrlState({ tab });
- };
-
- bindAndRedirectToOrganizationSettings(installationId: string) {
- const organizationKey = get(BIND_ORGANIZATION_KEY) || '';
- remove(BIND_ORGANIZATION_KEY);
-
- this.setState({ bindingExistingOrg: true });
-
- bindAlmOrganization({
- installationId,
- organization: organizationKey
- }).then(
- () => {
- this.props.router.push({
- pathname: `/organizations/${organizationKey}`
- });
- addGlobalSuccessMessage(translate('organization.bind.success'));
- },
- () => {}
- );
- }
-
- getHeader = (bindingExistingOrg: boolean) => {
- if (bindingExistingOrg) {
- return translate('onboarding.binding_organization');
- } else {
- return translate('onboarding.create_organization.page.header');
- }
- };
-
- setValidOrgKey = (almOrganization: T.AlmOrganization) => {
- const key = slugify(almOrganization.key);
- const keys = [key, ...times(9, i => `${key}-${i + 1}`)];
- return api
- .getOrganizations({ organizations: keys.join(',') })
- .then(
- ({ organizations }) => {
- const availableKey = keys.find(key => !organizations.find(o => o.key === key));
- return availableKey || `${key}-${Math.ceil(Math.random() * 1000) + 10}`;
- },
- () => key
- )
- .then(key => {
- return { almOrganization: { ...almOrganization, key } };
- });
- };
-
- stopLoading = () => {
- if (this.mounted) {
- this.setState({ loading: false });
- }
- };
-
- updateUrlQuery = (query: Partial<Query> = {}) => {
- this.props.router.push({
- pathname: this.props.location.pathname,
- query: serializeQuery({ ...parseQuery(this.props.location.query), ...query }),
- state: this.props.location.state
- });
- };
-
- updateUrlState = (state: Partial<LocationState> = {}) => {
- this.props.router.replace({
- pathname: this.props.location.pathname,
- query: this.props.location.query,
- state: { ...(this.props.location.state || {}), ...state }
- });
- };
-
- renderContent = (almInstallId?: string) => {
- const { location } = this.props;
- const { state } = this;
- const { organization, step, subscriptionPlans } = state;
- const { tab = 'auto' } = (location.state || {}) as LocationState;
-
- const commonProps = {
- handleOrgDetailsFinish: this.handleOrgDetailsFinish,
- handleOrgDetailsStepOpen: this.handleOrgDetailsStepOpen,
- onDone: this.handlePlanDone,
- organization,
- step,
- subscriptionPlans
- };
-
- if (!this.hasAutoImport(state)) {
- return (
- <ManualOrganizationCreate
- {...commonProps}
- createOrganization={this.props.createOrganization}
- onUpgradeFail={this.deleteOrganization}
- organization={this.state.organization}
- step={this.state.step}
- />
- );
- }
-
- const { almApplication, almOrganization, boundOrganization } = state;
-
- return (
- <>
- <Tabs<TabKeys>
- onChange={this.onTabChange}
- selected={tab || 'auto'}
- tabs={[
- {
- key: 'auto',
- node: translateWithParameters(
- 'onboarding.import_organization.import_from_x',
- translate(sanitizeAlmId(almApplication.key))
- )
- },
- {
- key: 'manual',
- node: translate('onboarding.create_organization.create_manually')
- }
- ]}
- />
-
- <ManualOrganizationCreate
- {...commonProps}
- className={classNames({ hidden: tab !== 'manual' && this.hasAutoImport(state) })}
- createOrganization={this.props.createOrganization}
- onUpgradeFail={this.deleteOrganization}
- />
-
- {almInstallId && almOrganization && !boundOrganization ? (
- <AutoOrganizationCreate
- {...commonProps}
- almApplication={almApplication}
- almInstallId={almInstallId}
- almOrganization={almOrganization}
- className={classNames({ hidden: tab !== 'auto' })}
- createOrganization={this.props.createOrganization}
- handleCancelImport={this.handleCancelImport}
- onOrgCreated={this.handleOrgCreated}
- onUpgradeFail={this.deleteOrganization}
- unboundOrganizations={this.props.userOrganizations.filter(
- ({ actions = {}, alm }) => !alm && actions.admin
- )}
- />
- ) : (
- <RemoteOrganizationChoose
- almApplication={almApplication}
- almInstallId={almInstallId}
- almOrganization={almOrganization}
- almUnboundApplications={state.almUnboundApplications}
- boundOrganization={boundOrganization}
- className={classNames({ hidden: tab !== 'auto' })}
- />
- )}
- </>
- );
- };
-
- render() {
- const { location } = this.props;
- const query = parseQuery(location.query);
-
- if (this.state.almOrgLoading) {
- return <AlmApplicationInstalling almKey={query.almKey} />;
- }
-
- const { bindingExistingOrg, subscriptionPlans } = this.state;
- const header = this.getHeader(bindingExistingOrg);
- const startedPrice = subscriptionPlans && subscriptionPlans[0] && subscriptionPlans[0].price;
-
- return (
- <>
- <Helmet defer={false} title={header} titleTemplate="%s" />
- <div className="page page-limited huge-spacer-top huge-spacer-bottom">
- <A11ySkipTarget anchor="create_org_main" />
-
- <header className="page-header huge-spacer-bottom">
- <h1 className="page-title huge big-spacer-bottom">
- <strong>{header}</strong>
- </h1>
- {startedPrice !== undefined && (
- <p className="page-description">
- {translate('onboarding.create_organization.page.description')}
- </p>
- )}
- </header>
- {this.state.loading ? <DeferredSpinner /> : this.renderContent(query.almInstallId)}
- </div>
- </>
- );
- }
-}
-
-const mapDispatchToProps = {
- createOrganization: createOrganization as any,
- deleteOrganization: deleteOrganization as any,
- skipOnboarding: skipOnboarding as any
-};
-
-export default whenLoggedIn(
- withUserOrganizations(withRouter(connect(null, mapDispatchToProps)(CreateOrganization)))
-);
diff --git a/server/sonar-web/src/main/js/apps/create/organization/ManualOrganizationCreate.tsx b/server/sonar-web/src/main/js/apps/create/organization/ManualOrganizationCreate.tsx
deleted file mode 100644
index 157acec75a5..00000000000
--- a/server/sonar-web/src/main/js/apps/create/organization/ManualOrganizationCreate.tsx
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import * as React from 'react';
-import { translate } from 'sonar-ui-common/helpers/l10n';
-import OrganizationDetailsForm from './OrganizationDetailsForm';
-import OrganizationDetailsStep from './OrganizationDetailsStep';
-import PlanStep from './PlanStep';
-import { Step } from './utils';
-
-interface Props {
- createOrganization: (organization: T.Organization) => Promise<string>;
- className?: string;
- onUpgradeFail: () => void;
- handleOrgDetailsFinish: (organization: T.Organization) => Promise<void>;
- handleOrgDetailsStepOpen: () => void;
- onDone: () => void;
- organization?: T.Organization;
- step: Step;
- subscriptionPlans?: T.SubscriptionPlan[];
-}
-
-export default class ManualOrganizationCreate extends React.PureComponent<Props> {
- handleCreateOrganization = () => {
- const { organization } = this.props;
- if (!organization) {
- return Promise.reject();
- }
- return this.props.createOrganization(organization);
- };
-
- render() {
- const { className, organization, subscriptionPlans } = this.props;
- return (
- <div className={className}>
- <OrganizationDetailsStep
- finished={organization !== undefined}
- onOpen={this.props.handleOrgDetailsStepOpen}
- open={this.props.step === Step.OrganizationDetails}
- organization={organization}>
- <OrganizationDetailsForm
- onContinue={this.props.handleOrgDetailsFinish}
- organization={organization}
- submitText={translate('continue')}
- />
- </OrganizationDetailsStep>
-
- {subscriptionPlans !== undefined && (
- <PlanStep
- createOrganization={this.handleCreateOrganization}
- onDone={this.props.onDone}
- onUpgradeFail={this.props.onUpgradeFail}
- open={this.props.step === Step.Plan}
- subscriptionPlans={subscriptionPlans}
- />
- )}
- </div>
- );
- }
-}
diff --git a/server/sonar-web/src/main/js/apps/create/organization/OrganizationDetailsForm.tsx b/server/sonar-web/src/main/js/apps/create/organization/OrganizationDetailsForm.tsx
deleted file mode 100644
index 928efd8f0cc..00000000000
--- a/server/sonar-web/src/main/js/apps/create/organization/OrganizationDetailsForm.tsx
+++ /dev/null
@@ -1,205 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import * as React from 'react';
-import { ResetButtonLink, SubmitButton } from 'sonar-ui-common/components/controls/buttons';
-import DropdownIcon from 'sonar-ui-common/components/icons/DropdownIcon';
-import DeferredSpinner from 'sonar-ui-common/components/ui/DeferredSpinner';
-import { translate } from 'sonar-ui-common/helpers/l10n';
-import OrganizationAvatarInput from '../components/OrganizationAvatarInput';
-import OrganizationKeyInput from '../components/OrganizationKeyInput';
-import OrganizationUrlInput from '../components/OrganizationUrlInput';
-
-type RequiredOrganization = Required<T.OrganizationBase>;
-
-interface Props {
- infoBlock?: React.ReactNode;
- onContinue: (organization: T.Organization) => Promise<void>;
- organization?: T.Organization;
- submitText: string;
-}
-
-interface State {
- additional: boolean;
- avatar?: string;
- description?: string;
- key?: string;
- name?: string;
- submitting: boolean;
- url?: string;
-}
-
-type ValidState = Pick<State, Exclude<keyof State, RequiredOrganization>> & RequiredOrganization;
-
-export default class OrganizationDetailsForm extends React.PureComponent<Props, State> {
- mounted = false;
-
- constructor(props: Props) {
- super(props);
- const { organization } = props;
- this.state = {
- additional: false,
- avatar: (organization && organization.avatar) || '',
- description: (organization && organization.description) || '',
- key: (organization && organization.key) || undefined,
- name: (organization && organization.name) || '',
- submitting: false,
- url: (organization && organization.url) || ''
- };
- }
-
- componentDidMount() {
- this.mounted = true;
- }
-
- componentWillUnmount() {
- this.mounted = false;
- }
-
- canSubmit(state: State): state is ValidState {
- return Boolean(
- state.key !== undefined &&
- state.name !== undefined &&
- state.description !== undefined &&
- state.avatar !== undefined &&
- state.url !== undefined
- );
- }
-
- handleAdditionalClick = () => {
- this.setState(state => ({ additional: !state.additional }));
- };
-
- handleAvatarUpdate = (avatar: string | undefined) => {
- this.setState({ avatar });
- };
-
- handleDescriptionUpdate = (event: React.ChangeEvent<HTMLTextAreaElement>) => {
- this.setState({ description: event.currentTarget.value });
- };
-
- handleKeyUpdate = (key: string | undefined) => {
- this.setState({ key });
- };
-
- handleNameUpdate = (event: React.ChangeEvent<HTMLInputElement>) => {
- this.setState({ name: event.currentTarget.value });
- };
-
- handleUrlUpdate = (url: string | undefined) => {
- this.setState({ url });
- };
-
- handleSubmit = (event: React.FormEvent) => {
- event.preventDefault();
- const { state } = this;
- if (this.canSubmit(state)) {
- this.setState({ submitting: true });
- this.props
- .onContinue({
- avatar: state.avatar,
- description: state.description,
- key: state.key,
- name: state.name,
- url: state.url
- })
- .then(this.stopSubmitting, this.stopSubmitting);
- }
- };
-
- stopSubmitting = () => {
- if (this.mounted) {
- this.setState({ submitting: false });
- }
- };
-
- render() {
- const { submitting } = this.state;
- const { infoBlock } = this.props;
- return (
- <form id="organization-form" onSubmit={this.handleSubmit}>
- <OrganizationKeyInput initialValue={this.state.key} onChange={this.handleKeyUpdate} />
- <div className="big-spacer-top">
- <ResetButtonLink onClick={this.handleAdditionalClick}>
- {translate(
- this.state.additional
- ? 'onboarding.create_organization.hide_additional_info'
- : 'onboarding.create_organization.add_additional_info'
- )}
- <DropdownIcon className="little-spacer-left" turned={this.state.additional} />
- </ResetButtonLink>
- </div>
- <div className="js-additional-info" hidden={!this.state.additional}>
- <div className="big-spacer-top">
- <label htmlFor="organization-display-name">
- <strong>{translate('onboarding.create_organization.display_name')}</strong>
- </label>
- <div className="little-spacer-top">
- <input
- className="input-super-large text-middle"
- id="organization-display-name"
- maxLength={255}
- onChange={this.handleNameUpdate}
- type="text"
- value={this.state.name}
- />
- </div>
- <div className="note abs-width-400">
- {translate('onboarding.create_organization.display_name.description')}
- </div>
- </div>
- <div className="big-spacer-top">
- <OrganizationAvatarInput
- initialValue={this.state.avatar}
- name={this.state.name}
- onChange={this.handleAvatarUpdate}
- />
- </div>
- <div className="big-spacer-top">
- <label htmlFor="organization-description">
- <strong>{translate('onboarding.create_organization.description')}</strong>
- </label>
- <div className="little-spacer-top">
- <textarea
- className="input-super-large text-middle"
- id="organization-description"
- maxLength={256}
- onChange={this.handleDescriptionUpdate}
- rows={3}
- value={this.state.description}
- />
- </div>
- </div>
- <div className="big-spacer-top">
- <OrganizationUrlInput initialValue={this.state.url} onChange={this.handleUrlUpdate} />
- </div>
- </div>
-
- {infoBlock}
-
- <div className="display-flex-center big-spacer-top">
- <SubmitButton disabled={submitting || !this.canSubmit(this.state)}>
- {this.props.submitText}
- </SubmitButton>
- {submitting && <DeferredSpinner className="spacer-left" />}
- </div>
- </form>
- );
- }
-}
diff --git a/server/sonar-web/src/main/js/apps/create/organization/OrganizationDetailsStep.tsx b/server/sonar-web/src/main/js/apps/create/organization/OrganizationDetailsStep.tsx
deleted file mode 100644
index 91b45c1e44f..00000000000
--- a/server/sonar-web/src/main/js/apps/create/organization/OrganizationDetailsStep.tsx
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import * as React from 'react';
-import AlertSuccessIcon from 'sonar-ui-common/components/icons/AlertSuccessIcon';
-import { translate } from 'sonar-ui-common/helpers/l10n';
-import Step from '../../../components/tutorials/components/Step';
-
-interface Props {
- children: React.ReactNode;
- finished: boolean;
- onOpen: () => void;
- open: boolean;
- organization?: T.Organization;
- stepTitle?: string;
-}
-export default class OrganizationDetailsStep extends React.PureComponent<Props> {
- renderForm = () => {
- return <div className="boxed-group-inner">{this.props.children}</div>;
- };
-
- renderResult = () => {
- const { organization } = this.props;
- return organization ? (
- <div className="boxed-group-actions display-flex-center">
- <AlertSuccessIcon className="spacer-right" />
- <strong className="text-limited">{organization.key}</strong>
- </div>
- ) : null;
- };
-
- render() {
- return (
- <Step
- finished={this.props.finished}
- onOpen={this.props.onOpen}
- open={this.props.open}
- renderForm={this.renderForm}
- renderResult={this.renderResult}
- stepNumber={1}
- stepTitle={
- this.props.stepTitle || translate('onboarding.create_organization.enter_org_details')
- }
- />
- );
- }
-}
diff --git a/server/sonar-web/src/main/js/apps/create/organization/PlanSelect.tsx b/server/sonar-web/src/main/js/apps/create/organization/PlanSelect.tsx
deleted file mode 100644
index 0c2460fd7d9..00000000000
--- a/server/sonar-web/src/main/js/apps/create/organization/PlanSelect.tsx
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import * as React from 'react';
-import { translate } from 'sonar-ui-common/helpers/l10n';
-import FreeCardPlan from '../components/FreeCardPlan';
-import PaidCardPlan from '../components/PaidCardPlan';
-
-export enum Plan {
- Free = 'free',
- Paid = 'paid'
-}
-
-interface Props {
- almApplication?: T.AlmApplication;
- almOrganization?: T.AlmOrganization;
- onChange: (plan: Plan) => void;
- plan: Plan;
- startingPrice: number;
-}
-
-export default class PlanSelect extends React.PureComponent<Props> {
- handleFreePlanClick = () => {
- this.props.onChange(Plan.Free);
- };
-
- handlePaidPlanClick = () => {
- this.props.onChange(Plan.Paid);
- };
-
- render() {
- const { almApplication, almOrganization, plan } = this.props;
- const hasPrivateRepo = Boolean(almOrganization && almOrganization.privateRepos > 0);
- const onlyPrivateRepo = Boolean(
- hasPrivateRepo && almOrganization && almOrganization.publicRepos === 0
- );
-
- const cards = [
- <PaidCardPlan
- isRecommended={hasPrivateRepo}
- key="paid"
- onClick={this.handlePaidPlanClick}
- selected={plan === Plan.Paid}
- startingPrice={this.props.startingPrice}
- />,
- <FreeCardPlan
- almName={almApplication && almApplication.name}
- disabled={onlyPrivateRepo}
- hasWarning={hasPrivateRepo && plan === Plan.Free}
- key="free"
- onClick={this.handleFreePlanClick}
- selected={plan === Plan.Free}
- />
- ];
-
- return (
- <div
- aria-label={translate('onboarding.create_organization.choose_plan')}
- className="display-flex-row huge-spacer-bottom"
- role="radiogroup">
- {hasPrivateRepo ? cards : cards.reverse()}
- </div>
- );
- }
-}
diff --git a/server/sonar-web/src/main/js/apps/create/organization/PlanStep.tsx b/server/sonar-web/src/main/js/apps/create/organization/PlanStep.tsx
deleted file mode 100644
index 042210cee1e..00000000000
--- a/server/sonar-web/src/main/js/apps/create/organization/PlanStep.tsx
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import * as React from 'react';
-import { SubmitButton } from 'sonar-ui-common/components/controls/buttons';
-import DeferredSpinner from 'sonar-ui-common/components/ui/DeferredSpinner';
-import { translate } from 'sonar-ui-common/helpers/l10n';
-import { withCurrentUser } from '../../../components/hoc/withCurrentUser';
-import Step from '../../../components/tutorials/components/Step';
-import { getExtensionStart } from '../../../helpers/extensions';
-import BillingFormShim from '../components/BillingFormShim';
-import PlanSelect, { Plan } from './PlanSelect';
-
-const BillingForm = withCurrentUser(BillingFormShim);
-
-interface Props {
- almApplication?: T.AlmApplication;
- almOrganization?: T.AlmOrganization;
- createOrganization: () => Promise<string>;
- onDone: () => void;
- onUpgradeFail?: () => void;
- open: boolean;
- subscriptionPlans: T.SubscriptionPlan[];
-}
-
-interface State {
- plan: Plan;
- ready: boolean;
- submitting: boolean;
-}
-
-export default class PlanStep extends React.PureComponent<Props, State> {
- mounted = false;
-
- constructor(props: Props) {
- super(props);
- this.state = {
- plan: props.almOrganization && props.almOrganization.privateRepos > 0 ? Plan.Paid : Plan.Free,
- ready: false,
- submitting: false
- };
- }
-
- componentDidMount() {
- this.mounted = true;
- getExtensionStart('billing/billing').then(
- () => {
- if (this.mounted) {
- this.setState({ ready: true });
- }
- },
- () => {}
- );
- }
-
- componentWillUnmount() {
- this.mounted = false;
- }
-
- handlePlanChange = (plan: Plan) => {
- this.setState({ plan });
- };
-
- stopSubmitting = () => {
- if (this.mounted) {
- this.setState({ submitting: false });
- }
- };
-
- handleFreePlanSubmit = (event: React.FormEvent) => {
- event.preventDefault();
- this.setState({ submitting: true });
- return this.props.createOrganization().then(() => {
- this.props.onDone();
- this.stopSubmitting();
- }, this.stopSubmitting);
- };
-
- renderForm = () => {
- const { submitting } = this.state;
- const { subscriptionPlans } = this.props;
- const startingPrice = subscriptionPlans && subscriptionPlans[0] && subscriptionPlans[0].price;
- return (
- <div className="boxed-group-inner">
- {this.state.ready && (
- <>
- <PlanSelect
- almApplication={this.props.almApplication}
- almOrganization={this.props.almOrganization}
- onChange={this.handlePlanChange}
- plan={this.state.plan}
- startingPrice={startingPrice}
- />
-
- {this.state.plan === Plan.Paid ? (
- <BillingForm
- onCommit={this.props.onDone}
- onFailToUpgrade={this.props.onUpgradeFail}
- organizationKey={this.props.createOrganization}
- subscriptionPlans={this.props.subscriptionPlans}>
- {({ onSubmit, renderFormFields, renderSubmitGroup }) => (
- <form id="organization-paid-plan-form" onSubmit={onSubmit}>
- {renderFormFields()}
- <div className="billing-input-large big-spacer-top">
- {renderSubmitGroup(
- translate('onboarding.create_organization.create_and_upgrade')
- )}
- </div>
- </form>
- )}
- </BillingForm>
- ) : (
- <form
- className="display-flex-center big-spacer-top"
- id="organization-free-plan-form"
- onSubmit={this.handleFreePlanSubmit}>
- <SubmitButton disabled={submitting}>
- {translate('my_account.create_organization')}
- </SubmitButton>
- {submitting && <DeferredSpinner className="spacer-left" />}
- </form>
- )}
- </>
- )}
- </div>
- );
- };
-
- render() {
- const { almOrganization } = this.props;
- const stepTitle = translate(
- almOrganization && almOrganization.privateRepos > 0 && almOrganization.publicRepos === 0
- ? 'onboarding.create_organization.enter_payment_details'
- : 'onboarding.create_organization.choose_plan'
- );
-
- return (
- <Step
- finished={false}
- onOpen={() => {}}
- open={this.props.open}
- renderForm={this.renderForm}
- renderResult={() => null}
- stepNumber={2}
- stepTitle={stepTitle}
- />
- );
- }
-}
diff --git a/server/sonar-web/src/main/js/apps/create/organization/RemoteOrganizationChoose.tsx b/server/sonar-web/src/main/js/apps/create/organization/RemoteOrganizationChoose.tsx
deleted file mode 100644
index 00b9744b7cb..00000000000
--- a/server/sonar-web/src/main/js/apps/create/organization/RemoteOrganizationChoose.tsx
+++ /dev/null
@@ -1,204 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import * as classNames from 'classnames';
-import { sortBy } from 'lodash';
-import * as React from 'react';
-import { FormattedMessage } from 'react-intl';
-import { withRouter, WithRouterProps } from 'react-router';
-import { SubmitButton } from 'sonar-ui-common/components/controls/buttons';
-import IdentityProviderLink from 'sonar-ui-common/components/controls/IdentityProviderLink';
-import Select from 'sonar-ui-common/components/controls/Select';
-import { Alert } from 'sonar-ui-common/components/ui/Alert';
-import { translate, translateWithParameters } from 'sonar-ui-common/helpers/l10n';
-import { save } from 'sonar-ui-common/helpers/storage';
-import { getBaseUrl } from 'sonar-ui-common/helpers/urls';
-import OrganizationAvatar from '../../../components/common/OrganizationAvatar';
-import { sanitizeAlmId } from '../../../helpers/almIntegrations';
-import { ORGANIZATION_IMPORT_BINDING_IN_PROGRESS_TIMESTAMP, serializeQuery } from './utils';
-
-interface Props {
- almApplication: T.AlmApplication;
- almInstallId?: string;
- almOrganization?: T.AlmOrganization;
- almUnboundApplications: T.AlmUnboundApplication[];
- boundOrganization?: T.OrganizationBase;
- className?: string;
-}
-
-interface State {
- unboundInstallationId: string;
-}
-
-export class RemoteOrganizationChoose extends React.PureComponent<Props & WithRouterProps, State> {
- state: State = { unboundInstallationId: '' };
-
- handleSubmit = (event: React.FormEvent<HTMLFormElement>) => {
- event.preventDefault();
-
- const { unboundInstallationId } = this.state;
- if (unboundInstallationId) {
- this.props.router.push({
- pathname: '/create-organization',
- query: serializeQuery({
- almInstallId: unboundInstallationId,
- almKey: this.props.almApplication.key
- })
- });
- }
- };
-
- handleInstallAppClick = () => {
- save(ORGANIZATION_IMPORT_BINDING_IN_PROGRESS_TIMESTAMP, Date.now().toString(10));
- };
-
- handleInstallationChange = ({ installationId }: T.AlmUnboundApplication) => {
- this.setState({ unboundInstallationId: installationId });
- };
-
- renderOption = (organization: T.AlmUnboundApplication) => {
- const { almApplication } = this.props;
- return (
- <span>
- <img
- alt={almApplication.name}
- className="spacer-right"
- height={14}
- src={`${getBaseUrl()}/images/sonarcloud/${sanitizeAlmId(almApplication.key)}.svg`}
- />
- {organization.name}
- </span>
- );
- };
-
- render() {
- const {
- almApplication,
- almInstallId,
- almOrganization,
- almUnboundApplications,
- boundOrganization,
- className
- } = this.props;
- const { unboundInstallationId } = this.state;
- return (
- <div className={classNames('boxed-group', className)}>
- <div className="boxed-group-header">
- <h2>{translate('onboarding.import_organization.import_org_details')}</h2>
- </div>
- <div className="boxed-group-inner">
- {almInstallId && !almOrganization && (
- <Alert className="big-spacer-bottom width-60" variant="error">
- <div className="markdown">
- {translate('onboarding.import_organization.org_not_found')}
- <ul>
- <li>{translate('onboarding.import_organization.org_not_found.tips_1')}</li>
- <li>{translate('onboarding.import_organization.org_not_found.tips_2')}</li>
- </ul>
- </div>
- </Alert>
- )}
- {almOrganization && boundOrganization && (
- <Alert className="big-spacer-bottom width-60" variant="error">
- <FormattedMessage
- defaultMessage={translate('onboarding.import_organization.already_bound_x')}
- id="onboarding.import_organization.already_bound_x"
- values={{
- avatar: (
- <img
- alt={almApplication.name}
- className="little-spacer-left"
- src={`${getBaseUrl()}/images/sonarcloud/${sanitizeAlmId(
- almApplication.key
- )}.svg`}
- width={16}
- />
- ),
- name: <strong>{almOrganization.name}</strong>,
- boundAvatar: (
- <OrganizationAvatar
- className="little-spacer-left"
- organization={boundOrganization}
- small={true}
- />
- ),
- boundName: <strong>{boundOrganization.name}</strong>
- }}
- />
- </Alert>
- )}
- <div className="display-flex-center">
- <div className="display-inline-block">
- <IdentityProviderLink
- backgroundColor={almApplication.backgroundColor}
- className="display-inline-block"
- iconPath={almApplication.iconPath}
- name={almApplication.name}
- onClick={this.handleInstallAppClick}
- small={true}
- url={almApplication.installationUrl}>
- {translate(
- 'onboarding.import_organization.choose_organization_button',
- almApplication.key
- )}
- </IdentityProviderLink>
- </div>
- {almUnboundApplications.length > 0 && (
- <div className="display-flex-stretch">
- <div className="vertical-pipe-separator">
- <div className="vertical-separator " />
- <span className="note">{translate('or')}</span>
- <div className="vertical-separator" />
- </div>
- <form className="big-spacer-top big-spacer-bottom" onSubmit={this.handleSubmit}>
- <div className="form-field abs-width-400">
- <label className="text-normal" htmlFor="select-unbound-installation">
- {translateWithParameters(
- 'onboarding.import_organization.choose_unbound_installation_x',
- translate(sanitizeAlmId(almApplication.key))
- )}
- </label>
- <Select
- className="input-super-large"
- clearable={false}
- id="select-unbound-installation"
- labelKey="name"
- onChange={this.handleInstallationChange}
- optionRenderer={this.renderOption}
- options={sortBy(almUnboundApplications, o => o.name.toLowerCase())}
- placeholder={translate('onboarding.import_organization.choose_organization')}
- value={unboundInstallationId}
- valueKey="installationId"
- valueRenderer={this.renderOption}
- />
- </div>
- <SubmitButton disabled={!unboundInstallationId}>
- {translate('continue')}
- </SubmitButton>
- </form>
- </div>
- )}
- </div>
- </div>
- </div>
- );
- }
-}
-
-export default withRouter(RemoteOrganizationChoose);
diff --git a/server/sonar-web/src/main/js/apps/create/organization/__tests__/AlmApplicationInstalling-test.tsx b/server/sonar-web/src/main/js/apps/create/organization/__tests__/AlmApplicationInstalling-test.tsx
deleted file mode 100644
index 352e72f3781..00000000000
--- a/server/sonar-web/src/main/js/apps/create/organization/__tests__/AlmApplicationInstalling-test.tsx
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import { shallow } from 'enzyme';
-import * as React from 'react';
-import AlmApplicationInstalling from '../AlmApplicationInstalling';
-
-it('should render correctly', () => {
- expect(shallow(<AlmApplicationInstalling />)).toMatchSnapshot();
- expect(shallow(<AlmApplicationInstalling almKey="github" />)).toMatchSnapshot();
-});
diff --git a/server/sonar-web/src/main/js/apps/create/organization/__tests__/AutoOrganizationBind-test.tsx b/server/sonar-web/src/main/js/apps/create/organization/__tests__/AutoOrganizationBind-test.tsx
deleted file mode 100644
index ecc8107689c..00000000000
--- a/server/sonar-web/src/main/js/apps/create/organization/__tests__/AutoOrganizationBind-test.tsx
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import { shallow } from 'enzyme';
-import * as React from 'react';
-import { submit } from 'sonar-ui-common/helpers/testUtils';
-import { mockOrganization } from '../../../../helpers/testMocks';
-import AutoOrganizationBind from '../AutoOrganizationBind';
-
-it('should render correctly', () => {
- const onBindOrganization = jest.fn().mockResolvedValue({});
- const wrapper = shallowRender({ onBindOrganization });
- expect(wrapper).toMatchSnapshot();
-
- submit(wrapper.find('form'));
- expect(onBindOrganization).toHaveBeenCalled();
-});
-
-it('should not show member sync info box for Bitbucket', () => {
- expect(
- shallowRender({ almKey: 'bitbucket' })
- .find('Alert')
- .exists()
- ).toBe(false);
-});
-
-function shallowRender(props: Partial<AutoOrganizationBind['props']> = {}) {
- return shallow(
- <AutoOrganizationBind
- almKey="github"
- onBindOrganization={jest.fn()}
- unboundOrganizations={[mockOrganization()]}
- {...props}
- />
- );
-}
diff --git a/server/sonar-web/src/main/js/apps/create/organization/__tests__/AutoOrganizationCreate-test.tsx b/server/sonar-web/src/main/js/apps/create/organization/__tests__/AutoOrganizationCreate-test.tsx
deleted file mode 100644
index c358824365d..00000000000
--- a/server/sonar-web/src/main/js/apps/create/organization/__tests__/AutoOrganizationCreate-test.tsx
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import { shallow } from 'enzyme';
-import * as React from 'react';
-import { click, waitAndUpdate } from 'sonar-ui-common/helpers/testUtils';
-import { bindAlmOrganization } from '../../../../api/alm-integration';
-import { mockAlmApplication, mockAlmOrganization } from '../../../../helpers/testMocks';
-import AutoOrganizationCreate from '../AutoOrganizationCreate';
-import { Step } from '../utils';
-
-jest.mock('../../../../api/alm-integration', () => ({
- bindAlmOrganization: jest.fn().mockResolvedValue({})
-}));
-
-const organization = mockAlmOrganization();
-
-it('should render prefilled and create org', async () => {
- const createOrganization = jest.fn().mockResolvedValue({ key: 'foo' });
- const handleOrgDetailsFinish = jest.fn();
- const almOrganization = mockAlmOrganization({ almUrl: 'http://github.com/thing' });
- const wrapper = shallowRender({
- almOrganization,
- createOrganization,
- handleOrgDetailsFinish
- });
-
- expect(wrapper).toMatchSnapshot();
-
- wrapper.find('OrganizationDetailsForm').prop<Function>('onContinue')(organization);
- await waitAndUpdate(wrapper);
- expect(handleOrgDetailsFinish).toBeCalled();
-
- wrapper.setProps({ organization });
- wrapper.find('PlanStep').prop<Function>('createOrganization')();
-
- const alm: T.Organization['alm'] = {
- key: 'github',
- membersSync: true,
- personal: false,
- url: 'http://github.com/thing'
- };
- expect(createOrganization).toBeCalledWith({ ...organization, alm, installationId: 'id-foo' });
-});
-
-it('should allow to cancel org import', () => {
- const handleCancelImport = jest.fn().mockResolvedValue({ key: 'foo' });
- const wrapper = shallowRender({ handleCancelImport });
-
- click(wrapper.find('ClearButton'));
- expect(handleCancelImport).toBeCalled();
-});
-
-it('should display choice between import or creation', () => {
- const wrapper = shallowRender({ unboundOrganizations: [organization] });
- expect(wrapper).toMatchSnapshot();
-
- wrapper.find('RadioToggle').prop<Function>('onCheck')('create');
- wrapper.update();
- expect(wrapper.find('OrganizationDetailsForm').exists()).toBe(true);
-
- wrapper.find('RadioToggle').prop<Function>('onCheck')('bind');
- wrapper.update();
- expect(wrapper.find('AutoOrganizationBind').exists()).toBe(true);
-});
-
-it('should bind existing organization', async () => {
- const onOrgCreated = jest.fn();
- const wrapper = shallowRender({ onOrgCreated, unboundOrganizations: [organization] });
-
- wrapper.find('RadioToggle').prop<Function>('onCheck')('bind');
- wrapper.update();
- wrapper.find('AutoOrganizationBind').prop<Function>('onBindOrganization')('foo');
- expect(bindAlmOrganization as jest.Mock<any>).toHaveBeenCalledWith({
- installationId: 'id-foo',
- organization: 'foo'
- });
- await waitAndUpdate(wrapper);
- expect(onOrgCreated).toHaveBeenCalledWith('foo');
-});
-
-it('should not show member sync info box for Bitbucket', () => {
- expect(
- shallowRender({ almApplication: mockAlmApplication({ key: 'bitbucket-cloud' }) })
- .find('Alert')
- .exists()
- ).toBe(false);
-});
-
-function shallowRender(props: Partial<AutoOrganizationCreate['props']> = {}) {
- return shallow(
- <AutoOrganizationCreate
- almApplication={mockAlmApplication()}
- almInstallId="id-foo"
- almOrganization={organization}
- createOrganization={jest.fn()}
- handleCancelImport={jest.fn()}
- handleOrgDetailsFinish={jest.fn()}
- handleOrgDetailsStepOpen={jest.fn()}
- onDone={jest.fn()}
- onOrgCreated={jest.fn()}
- onUpgradeFail={jest.fn()}
- step={Step.OrganizationDetails}
- subscriptionPlans={[
- { maxNcloc: 100000, price: 10 },
- { maxNcloc: 250000, price: 75 }
- ]}
- unboundOrganizations={[]}
- {...props}
- />
- );
-}
diff --git a/server/sonar-web/src/main/js/apps/create/organization/__tests__/CreateOrganization-test.tsx b/server/sonar-web/src/main/js/apps/create/organization/__tests__/CreateOrganization-test.tsx
deleted file mode 100644
index 1f1e0a03dad..00000000000
--- a/server/sonar-web/src/main/js/apps/create/organization/__tests__/CreateOrganization-test.tsx
+++ /dev/null
@@ -1,342 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import { mount, shallow } from 'enzyme';
-import { Location } from 'history';
-import { times } from 'lodash';
-import * as React from 'react';
-import { HelmetProvider } from 'react-helmet-async';
-import { get, remove } from 'sonar-ui-common/helpers/storage';
-import { waitAndUpdate } from 'sonar-ui-common/helpers/testUtils';
-import {
- bindAlmOrganization,
- getAlmAppInfo,
- getAlmOrganization,
- listUnboundApplications
-} from '../../../../api/alm-integration';
-import { getSubscriptionPlans } from '../../../../api/billing';
-import { getOrganizations } from '../../../../api/organizations';
-import {
- mockAlmOrganization,
- mockLocation,
- mockLoggedInUser,
- mockOrganizationWithAdminActions,
- mockOrganizationWithAlm,
- mockRouter
-} from '../../../../helpers/testMocks';
-import { CreateOrganization } from '../CreateOrganization';
-
-jest.mock('../../../../api/billing', () => ({
- getSubscriptionPlans: jest.fn().mockResolvedValue([
- { maxNcloc: 100000, price: 10 },
- { maxNcloc: 250000, price: 75 }
- ])
-}));
-
-jest.mock('../../../../api/alm-integration', () => ({
- getAlmAppInfo: jest.fn().mockResolvedValue({
- application: {
- backgroundColor: 'blue',
- iconPath: 'icon/path',
- installationUrl: 'https://alm.installation.url',
- key: 'github',
- name: 'GitHub'
- }
- }),
- getAlmOrganization: jest.fn().mockResolvedValue({
- almOrganization: {
- avatar: 'my-avatar',
- description: 'Continuous Code Quality',
- key: 'sonarsource',
- name: 'SonarSource',
- privateRepos: 0,
- publicRepos: 3,
- url: 'https://www.sonarsource.com'
- }
- }),
- listUnboundApplications: jest.fn().mockResolvedValue([]),
- bindAlmOrganization: jest.fn().mockResolvedValue({})
-}));
-
-jest.mock('../../../../api/organizations', () => ({
- getOrganizations: jest.fn().mockResolvedValue({ organizations: [] })
-}));
-
-jest.mock('sonar-ui-common/helpers/storage', () => ({
- get: jest.fn().mockReturnValue(undefined),
- remove: jest.fn()
-}));
-
-const user = mockLoggedInUser();
-const fooAlmOrganization = mockAlmOrganization();
-const fooBarAlmOrganization = mockAlmOrganization({
- avatar: 'https://avatars3.githubusercontent.com/u/37629810?v=4',
- key: 'Foo&Bar',
- name: 'Foo & Bar'
-});
-
-const boundOrganization = { key: 'foobar', name: 'Foo & Bar' };
-
-beforeEach(() => {
- (getAlmAppInfo as jest.Mock<any>).mockClear();
- (getAlmOrganization as jest.Mock<any>).mockClear();
- (listUnboundApplications as jest.Mock<any>).mockClear();
- (getSubscriptionPlans as jest.Mock<any>).mockClear();
- (getOrganizations as jest.Mock<any>).mockClear();
- (get as jest.Mock<any>).mockClear();
- (remove as jest.Mock<any>).mockClear();
-});
-
-it('should render with manual tab displayed', async () => {
- const wrapper = shallowRender();
- await waitAndUpdate(wrapper);
- expect(wrapper).toMatchSnapshot();
- expect(getSubscriptionPlans).toHaveBeenCalled();
- expect(getAlmAppInfo).not.toHaveBeenCalled();
-});
-
-it('should render with auto tab displayed', async () => {
- const wrapper = shallowRender({ currentUser: { ...user, externalProvider: 'github' } });
- await waitAndUpdate(wrapper);
- expect(wrapper).toMatchSnapshot();
- expect(getAlmAppInfo).toHaveBeenCalled();
- expect(listUnboundApplications).toHaveBeenCalled();
-});
-
-it('should render with auto tab selected and manual disabled', async () => {
- const wrapper = shallowRender({
- currentUser: { ...user, externalProvider: 'github' },
- location: { query: { installation_id: 'foo' } } as Location
- });
- expect(wrapper).toMatchSnapshot();
- await waitAndUpdate(wrapper);
- expect(wrapper).toMatchSnapshot();
- expect(getAlmAppInfo).toHaveBeenCalled();
- expect(getAlmOrganization).toHaveBeenCalled();
- expect(getOrganizations).toHaveBeenCalled();
-});
-
-it('should render with organization bind page', async () => {
- (getAlmOrganization as jest.Mock<any>).mockResolvedValueOnce({
- almOrganization: fooAlmOrganization
- });
- const wrapper = shallowRender({
- currentUser: { ...user, externalProvider: 'github' },
- location: { query: { installation_id: 'foo' } } as Location
- });
- expect(wrapper).toMatchSnapshot();
- await waitAndUpdate(wrapper);
- expect(wrapper).toMatchSnapshot();
-});
-
-it('should slugify and find a uniq organization key', async () => {
- (getAlmOrganization as jest.Mock<any>).mockResolvedValueOnce({
- almOrganization: fooBarAlmOrganization
- });
- (getOrganizations as jest.Mock<any>).mockResolvedValueOnce({
- organizations: [{ key: 'foo-and-bar' }, { key: 'foo-and-bar-1' }]
- });
- const wrapper = shallowRender({
- currentUser: { ...user, externalProvider: 'github' },
- location: { query: { installation_id: 'foo' } } as Location
- });
- await waitAndUpdate(wrapper);
- expect(getOrganizations).toHaveBeenCalledWith({
- organizations: ['foo-and-bar', ...times(9, i => `foo-and-bar-${i + 1}`)].join(',')
- });
- expect(wrapper.find('AutoOrganizationCreate').prop('almOrganization')).toMatchObject({
- key: 'foo-and-bar-2'
- });
-});
-
-it('should switch tabs', async () => {
- const replace = jest.fn();
- const wrapper = shallowRender({
- currentUser: { ...user, externalProvider: 'github' },
- router: mockRouter({ replace })
- });
-
- replace.mockImplementation(location => {
- wrapper.setProps({ location }).update();
- });
-
- await waitAndUpdate(wrapper);
- expect(wrapper).toMatchSnapshot();
-
- (wrapper.find('Tabs').prop('onChange') as Function)('manual');
- expect(wrapper.find('ManualOrganizationCreate').hasClass('hidden')).toBe(false);
- expect(wrapper.find('withRouter(RemoteOrganizationChoose)').hasClass('hidden')).toBe(true);
- (wrapper.find('Tabs').prop('onChange') as Function)('auto');
- expect(wrapper.find('withRouter(RemoteOrganizationChoose)').hasClass('hidden')).toBe(false);
- expect(wrapper.find('ManualOrganizationCreate').hasClass('hidden')).toBe(true);
-});
-
-it('should reload the alm organization when the url query changes', async () => {
- const wrapper = shallowRender({ currentUser: { ...user, externalProvider: 'github' } });
- await waitAndUpdate(wrapper);
- expect(getAlmOrganization).not.toHaveBeenCalled();
- wrapper.setProps({ location: { query: { installation_id: 'foo' } } as Location });
- expect(getAlmOrganization).toHaveBeenCalledWith({ installationId: 'foo' });
- wrapper.setProps({ location: { query: {} } as Location });
- expect(wrapper.state('almOrganization')).toBeUndefined();
- expect(listUnboundApplications).toHaveBeenCalledTimes(2);
-});
-
-it('should redirect to organization page after creation', async () => {
- const push = jest.fn();
- const wrapper = shallowRender({ router: mockRouter({ push }) });
- await waitAndUpdate(wrapper);
-
- wrapper.setState({ organization: boundOrganization });
- wrapper.instance().handleOrgCreated('foo');
- expect(push).toHaveBeenCalledWith({ pathname: '/organizations/foo' });
-});
-
-it('should redirect to projects creation page after creation', async () => {
- const push = jest.fn();
- const wrapper = shallowRender({ router: mockRouter({ push }) });
- await waitAndUpdate(wrapper);
-
- (get as jest.Mock<any>).mockReturnValueOnce(Date.now().toString());
- wrapper.instance().handleOrgCreated('foo');
- expect(get).toHaveBeenCalled();
- expect(remove).toHaveBeenCalled();
- expect(push).toHaveBeenCalledWith({
- pathname: '/projects/create',
- state: { organization: 'foo', tab: 'manual' }
- });
-
- wrapper.setState({ almOrganization: fooAlmOrganization });
- (get as jest.Mock<any>).mockReturnValueOnce(Date.now().toString());
- wrapper.instance().handleOrgCreated('foo');
- expect(push).toHaveBeenCalledWith({
- pathname: '/projects/create',
- state: { organization: 'foo', tab: 'auto' }
- });
-});
-
-it('should display AutoOrganizationCreate with already bound organization', async () => {
- (getAlmOrganization as jest.Mock<any>).mockResolvedValueOnce({
- almOrganization: fooBarAlmOrganization,
- boundOrganization
- });
- (get as jest.Mock<any>)
- .mockReturnValueOnce(undefined) // For BIND_ORGANIZATION_REDIRECT_TO_ORG_TIMESTAMP
- .mockReturnValueOnce(Date.now().toString()); // For ORGANIZATION_IMPORT_BINDING_IN_PROGRESS_TIMESTAMP
- const push = jest.fn();
- const wrapper = shallowRender({
- currentUser: { ...user, externalProvider: 'github' },
- location: { query: { installation_id: 'foo' } } as Location,
- router: mockRouter({ push })
- });
- await waitAndUpdate(wrapper);
- expect(get).toHaveBeenCalled();
- expect(remove).toHaveBeenCalled();
- expect(getAlmOrganization).toHaveBeenCalledWith({ installationId: 'foo' });
- expect(push).not.toHaveBeenCalled();
- expect(wrapper.find('withRouter(RemoteOrganizationChoose)').prop('boundOrganization')).toEqual({
- key: 'foobar',
- name: 'Foo & Bar'
- });
-});
-
-it('should redirect to org page when already bound and no binding in progress', async () => {
- (getAlmOrganization as jest.Mock<any>).mockResolvedValueOnce({
- almOrganization: fooBarAlmOrganization,
- boundOrganization
- });
- const push = jest.fn();
- const wrapper = shallowRender({
- currentUser: { ...user, externalProvider: 'github' },
- location: { query: { installation_id: 'foo' } } as Location,
- router: mockRouter({ push })
- });
- await waitAndUpdate(wrapper);
- expect(getAlmOrganization).toHaveBeenCalledWith({ installationId: 'foo' });
- expect(push).toHaveBeenCalledWith({ pathname: '/organizations/foobar' });
-});
-
-it('should roll back after upgrade failure', async () => {
- const deleteOrganization = jest.fn();
- const wrapper = shallowRender({ deleteOrganization });
- await waitAndUpdate(wrapper);
- wrapper.setState({ organization: boundOrganization });
- wrapper.find('ManualOrganizationCreate').prop<Function>('onUpgradeFail')();
- expect(deleteOrganization).toBeCalled();
-});
-
-it('should cancel imports', async () => {
- const push = jest.fn();
- const wrapper = shallowRender({ router: mockRouter({ push }) });
- await waitAndUpdate(wrapper);
- wrapper.instance().handleCancelImport();
- expect(push).toBeCalledWith({ pathname: '/path', query: {}, state: {} });
-});
-
-it('should bind org and redirect to org home when coming from org binding', async () => {
- const installation_id = '5328';
- const orgKey = 'org4test';
- const push = jest.fn();
-
- (get as jest.Mock<any>)
- .mockReturnValueOnce(Date.now().toString()) // For BIND_ORGANIZATION_REDIRECT_TO_ORG_TIMESTAMP
- .mockReturnValueOnce(orgKey); // For BIND_ORGANIZATION_KEY
-
- const wrapper = mountRender({
- currentUser: mockLoggedInUser({ ...user, externalProvider: 'github' }),
- location: mockLocation({ query: { installation_id } }),
- router: mockRouter({ push })
- });
- await waitAndUpdate(wrapper);
-
- expect(bindAlmOrganization).toBeCalled();
- expect(getAlmOrganization).not.toBeCalled();
- expect(push).toBeCalledWith({
- pathname: `/organizations/${orgKey}`
- });
-});
-
-function mountRender(props: Partial<CreateOrganization['props']> = {}) {
- return mount<CreateOrganization>(<HelmetProvider>{createComponent(props)}</HelmetProvider>);
-}
-
-function shallowRender(props: Partial<CreateOrganization['props']> = {}) {
- return shallow<CreateOrganization>(createComponent(props));
-}
-
-function createComponent(props: Partial<CreateOrganization['props']> = {}) {
- return (
- <CreateOrganization
- createOrganization={jest.fn()}
- currentUser={user}
- deleteOrganization={jest.fn()}
- location={mockLocation()}
- params={{}}
- router={mockRouter()}
- routes={[]}
- skipOnboarding={jest.fn()}
- userOrganizations={[
- mockOrganizationWithAdminActions(),
- mockOrganizationWithAdminActions(mockOrganizationWithAlm({ key: 'bar', name: 'Bar' })),
- mockOrganizationWithAdminActions({ key: 'baz', name: 'Baz' }, { admin: false })
- ]}
- {...props}
- />
- );
-}
diff --git a/server/sonar-web/src/main/js/apps/create/organization/__tests__/ManualOrganizationCreate-test.tsx b/server/sonar-web/src/main/js/apps/create/organization/__tests__/ManualOrganizationCreate-test.tsx
deleted file mode 100644
index 46c1fab37f4..00000000000
--- a/server/sonar-web/src/main/js/apps/create/organization/__tests__/ManualOrganizationCreate-test.tsx
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import { shallow } from 'enzyme';
-import * as React from 'react';
-import { waitAndUpdate } from 'sonar-ui-common/helpers/testUtils';
-import { mockOrganization } from '../../../../helpers/testMocks';
-import ManualOrganizationCreate from '../ManualOrganizationCreate';
-import { Step } from '../utils';
-
-it('should render and create organization', async () => {
- const createOrganization = jest.fn().mockResolvedValue({ key: 'foo' });
- const onDone = jest.fn();
- const handleOrgDetailsFinish = jest.fn();
- const wrapper = shallowRender({ createOrganization, handleOrgDetailsFinish, onDone });
-
- await waitAndUpdate(wrapper);
- expect(wrapper).toMatchSnapshot();
-
- wrapper.find('OrganizationDetailsForm').prop<Function>('onContinue')(mockOrganization());
- await waitAndUpdate(wrapper);
- expect(handleOrgDetailsFinish).toHaveBeenCalled();
- wrapper.setProps({ step: Step.Plan });
- expect(wrapper).toMatchSnapshot();
-});
-
-function shallowRender(props: Partial<ManualOrganizationCreate['props']> = {}) {
- return shallow(
- <ManualOrganizationCreate
- createOrganization={jest.fn()}
- handleOrgDetailsFinish={jest.fn()}
- handleOrgDetailsStepOpen={jest.fn()}
- onDone={jest.fn()}
- onUpgradeFail={jest.fn()}
- step={Step.OrganizationDetails}
- subscriptionPlans={[
- { maxNcloc: 100000, price: 10 },
- { maxNcloc: 250000, price: 75 }
- ]}
- {...props}
- />
- );
-}
diff --git a/server/sonar-web/src/main/js/apps/create/organization/__tests__/OrganizationDetailsForm-test.tsx b/server/sonar-web/src/main/js/apps/create/organization/__tests__/OrganizationDetailsForm-test.tsx
deleted file mode 100644
index 548d59e4cec..00000000000
--- a/server/sonar-web/src/main/js/apps/create/organization/__tests__/OrganizationDetailsForm-test.tsx
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import { shallow } from 'enzyme';
-import * as React from 'react';
-import { click, submit } from 'sonar-ui-common/helpers/testUtils';
-import OrganizationDetailsForm from '../OrganizationDetailsForm';
-
-it('should render form', () => {
- const wrapper = shallowRender();
- expect(wrapper).toMatchSnapshot();
- expect(wrapper.find('.js-additional-info').prop('hidden')).toBe(true);
-
- click(wrapper.find('ResetButtonLink'));
- wrapper.update();
- expect(wrapper.find('.js-additional-info').prop('hidden')).toBe(false);
-});
-
-it('should validate before submit', () => {
- const wrapper = shallowRender();
- const instance = wrapper.instance() as OrganizationDetailsForm;
-
- expect(
- instance.canSubmit({
- additional: false,
- avatar: '',
- description: '',
- name: '',
- key: 'foo',
- submitting: false,
- url: ''
- })
- ).toBe(true);
-
- expect(
- instance.canSubmit({
- additional: false,
- avatar: '',
- description: '',
- name: '',
- key: undefined,
- submitting: false,
- url: ''
- })
- ).toBe(false);
-
- expect(
- instance.canSubmit({
- additional: false,
- avatar: undefined,
- description: '',
- name: '',
- key: 'foo',
- submitting: false,
- url: ''
- })
- ).toBe(false);
-
- instance.canSubmit = jest.fn() as any;
- submit(wrapper.find('form'));
- expect(instance.canSubmit).toHaveBeenCalled();
-});
-
-function shallowRender(props: Partial<OrganizationDetailsForm['props']> = {}) {
- return shallow(
- <OrganizationDetailsForm onContinue={jest.fn()} submitText="continue" {...props} />
- );
-}
diff --git a/server/sonar-web/src/main/js/apps/create/organization/__tests__/OrganizationDetailsStep-test.tsx b/server/sonar-web/src/main/js/apps/create/organization/__tests__/OrganizationDetailsStep-test.tsx
deleted file mode 100644
index c88443b685d..00000000000
--- a/server/sonar-web/src/main/js/apps/create/organization/__tests__/OrganizationDetailsStep-test.tsx
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import { shallow } from 'enzyme';
-import * as React from 'react';
-import OrganizationDetailsStep from '../OrganizationDetailsStep';
-
-it('should render form', () => {
- const wrapper = shallow(
- <OrganizationDetailsStep finished={false} onOpen={jest.fn()} open={true}>
- <form />
- </OrganizationDetailsStep>
- );
- expect(wrapper).toMatchSnapshot();
- expect(
- wrapper
- .dive()
- .find('form')
- .exists()
- ).toBe(true);
-});
-
-it('should render result', () => {
- const wrapper = shallow(
- <OrganizationDetailsStep
- finished={true}
- onOpen={jest.fn()}
- open={false}
- organization={{ avatar: '', description: '', key: 'org', name: 'Organization', url: '' }}>
- <div />
- </OrganizationDetailsStep>
- );
- expect(wrapper.dive().find('.boxed-group-actions')).toMatchSnapshot();
- expect(
- wrapper
- .dive()
- .find('.hidden')
- .exists()
- ).toBe(true);
-});
diff --git a/server/sonar-web/src/main/js/apps/create/organization/__tests__/PlanSelect-test.tsx b/server/sonar-web/src/main/js/apps/create/organization/__tests__/PlanSelect-test.tsx
deleted file mode 100644
index 55fa395aead..00000000000
--- a/server/sonar-web/src/main/js/apps/create/organization/__tests__/PlanSelect-test.tsx
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import { shallow } from 'enzyme';
-import * as React from 'react';
-import { click } from 'sonar-ui-common/helpers/testUtils';
-import { mockAlmOrganization } from '../../../../helpers/testMocks';
-import PlanSelect, { Plan } from '../PlanSelect';
-
-it('should render and select', () => {
- const onChange = jest.fn();
- const wrapper = shallowRender({ onChange });
- expect(wrapper).toMatchSnapshot();
-
- click(wrapper.find('PaidCardPlan'));
- expect(onChange).toBeCalledWith(Plan.Paid);
- wrapper.setProps({ plan: Plan.Paid });
- expect(wrapper).toMatchSnapshot();
-});
-
-it('should recommend paid plan', () => {
- const wrapper = shallowRender({
- almOrganization: mockAlmOrganization({ privateRepos: 1, publicRepos: 5 }),
- plan: Plan.Paid
- });
- expect(wrapper.find('PaidCardPlan').prop('isRecommended')).toBe(true);
- expect(wrapper.find('FreeCardPlan').prop('disabled')).toBe(false);
- expect(wrapper.find('FreeCardPlan').prop('hasWarning')).toBe(false);
-
- wrapper.setProps({ plan: Plan.Free });
- expect(wrapper.find('FreeCardPlan').prop('hasWarning')).toBe(true);
-});
-
-it('should recommend paid plan and disable free plan', () => {
- const wrapper = shallowRender({
- almOrganization: mockAlmOrganization({ privateRepos: 1, publicRepos: 0 })
- });
- expect(wrapper.find('PaidCardPlan').prop('isRecommended')).toBe(true);
- expect(wrapper.find('FreeCardPlan').prop('disabled')).toBe(true);
-});
-
-function shallowRender(props: Partial<PlanSelect['props']> = {}) {
- return shallow(
- <PlanSelect onChange={jest.fn()} plan={Plan.Free} startingPrice={10} {...props} />
- );
-}
diff --git a/server/sonar-web/src/main/js/apps/create/organization/__tests__/PlanStep-test.tsx b/server/sonar-web/src/main/js/apps/create/organization/__tests__/PlanStep-test.tsx
deleted file mode 100644
index a306d1ccf0a..00000000000
--- a/server/sonar-web/src/main/js/apps/create/organization/__tests__/PlanStep-test.tsx
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import { shallow } from 'enzyme';
-import * as React from 'react';
-import { submit, waitAndUpdate } from 'sonar-ui-common/helpers/testUtils';
-import { mockAlmOrganization } from '../../../../helpers/testMocks';
-import { Plan } from '../PlanSelect';
-import PlanStep from '../PlanStep';
-
-jest.mock('../../../../helpers/extensions', () => ({
- getExtensionStart: jest.fn().mockResolvedValue(undefined)
-}));
-const subscriptionPlans = [{ maxNcloc: 1000, price: 100 }];
-
-it('should render and use free plan', async () => {
- const onDone = jest.fn();
- const createOrganization = jest.fn().mockResolvedValue('org');
- const wrapper = shallow(
- <PlanStep
- createOrganization={createOrganization}
- onDone={onDone}
- onUpgradeFail={jest.fn()}
- open={true}
- subscriptionPlans={subscriptionPlans}
- />
- );
- await waitAndUpdate(wrapper);
- expect(wrapper).toMatchSnapshot();
- expect(wrapper.dive()).toMatchSnapshot();
-
- submit(wrapper.dive().find('form'));
- await waitAndUpdate(wrapper);
- expect(createOrganization).toBeCalled();
- expect(onDone).toBeCalled();
-});
-
-it('should upgrade', async () => {
- const onDone = jest.fn();
- const wrapper = shallow(
- <PlanStep
- createOrganization={jest.fn().mockResolvedValue('org')}
- onDone={onDone}
- onUpgradeFail={jest.fn()}
- open={true}
- subscriptionPlans={subscriptionPlans}
- />
- );
- await waitAndUpdate(wrapper);
-
- wrapper
- .dive()
- .find('PlanSelect')
- .prop<Function>('onChange')(Plan.Paid);
- expect(wrapper.dive()).toMatchSnapshot();
-
- wrapper
- .dive()
- .find('Connect(withCurrentUser(BillingFormShim))')
- .prop<Function>('onCommit')();
- expect(onDone).toBeCalled();
-});
-
-it('should preselect paid plan', async () => {
- const wrapper = shallow(
- <PlanStep
- almOrganization={mockAlmOrganization({ privateRepos: 5, publicRepos: 0 })}
- createOrganization={jest.fn()}
- onDone={jest.fn()}
- onUpgradeFail={jest.fn()}
- open={true}
- subscriptionPlans={subscriptionPlans}
- />
- );
- await waitAndUpdate(wrapper);
- expect(wrapper.dive()).toMatchSnapshot();
-});
diff --git a/server/sonar-web/src/main/js/apps/create/organization/__tests__/RemoteOrganizationChoose-test.tsx b/server/sonar-web/src/main/js/apps/create/organization/__tests__/RemoteOrganizationChoose-test.tsx
deleted file mode 100644
index b19e2bfa6c3..00000000000
--- a/server/sonar-web/src/main/js/apps/create/organization/__tests__/RemoteOrganizationChoose-test.tsx
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import { shallow } from 'enzyme';
-import * as React from 'react';
-import { submit } from 'sonar-ui-common/helpers/testUtils';
-import { mockAlmOrganization, mockRouter } from '../../../../helpers/testMocks';
-import { RemoteOrganizationChoose } from '../RemoteOrganizationChoose';
-
-it('should render', () => {
- expect(shallowRender()).toMatchSnapshot();
-});
-
-it('should display an alert message', () => {
- expect(shallowRender({ almInstallId: 'foo' }).find('Alert')).toMatchSnapshot();
-});
-
-it('should display unbound installations', () => {
- const installation = { installationId: '12345', key: 'foo', name: 'Foo' };
- const push = jest.fn();
- const wrapper = shallowRender({
- almUnboundApplications: [installation],
- router: mockRouter({ push })
- });
- expect(wrapper).toMatchSnapshot();
-
- wrapper.find('Select').prop<Function>('onChange')(installation);
- submit(wrapper.find('form'));
- expect(push).toHaveBeenCalledWith({
- pathname: '/create-organization',
- query: { installation_id: installation.installationId }
- });
-});
-
-it('should display already bound alert message', () => {
- expect(
- shallowRender({
- almInstallId: 'foo',
- almOrganization: mockAlmOrganization(),
- boundOrganization: { avatar: 'bound-avatar', key: 'bound', name: 'Bound' }
- }).find('Alert')
- ).toMatchSnapshot();
-});
-
-function shallowRender(props: Partial<RemoteOrganizationChoose['props']> = {}) {
- return shallow(
- // @ts-ignore avoid passing everything from WithRouterProps
- <RemoteOrganizationChoose
- almApplication={{
- backgroundColor: 'blue',
- iconPath: 'icon/path',
- installationUrl: 'https://alm.application.url',
- key: 'github',
- name: 'GitHub'
- }}
- almUnboundApplications={[]}
- router={mockRouter()}
- {...props}
- />
- );
-}
diff --git a/server/sonar-web/src/main/js/apps/create/organization/__tests__/__snapshots__/AlmApplicationInstalling-test.tsx.snap b/server/sonar-web/src/main/js/apps/create/organization/__tests__/__snapshots__/AlmApplicationInstalling-test.tsx.snap
deleted file mode 100644
index 135829ce072..00000000000
--- a/server/sonar-web/src/main/js/apps/create/organization/__tests__/__snapshots__/AlmApplicationInstalling-test.tsx.snap
+++ /dev/null
@@ -1,47 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render correctly 1`] = `
-<DeferredSpinner
- customSpinner={
- <div
- className="sonarcloud page page-limited"
- >
- <div
- className="huge-spacer-top text-center"
- >
- <i
- className="spinner"
- />
- <p
- className="big-spacer-top"
- >
- onboarding.import_organization.installing.ALM
- </p>
- </div>
- </div>
- }
-/>
-`;
-
-exports[`should render correctly 2`] = `
-<DeferredSpinner
- customSpinner={
- <div
- className="sonarcloud page page-limited"
- >
- <div
- className="huge-spacer-top text-center"
- >
- <i
- className="spinner"
- />
- <p
- className="big-spacer-top"
- >
- onboarding.import_organization.installing.github
- </p>
- </div>
- </div>
- }
-/>
-`;
diff --git a/server/sonar-web/src/main/js/apps/create/organization/__tests__/__snapshots__/AutoOrganizationBind-test.tsx.snap b/server/sonar-web/src/main/js/apps/create/organization/__tests__/__snapshots__/AutoOrganizationBind-test.tsx.snap
deleted file mode 100644
index 7c32193e58c..00000000000
--- a/server/sonar-web/src/main/js/apps/create/organization/__tests__/__snapshots__/AutoOrganizationBind-test.tsx.snap
+++ /dev/null
@@ -1,50 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render correctly 1`] = `
-<form
- id="bind-organization-form"
- onSubmit={[Function]}
->
- <OrganizationSelect
- onChange={[Function]}
- organization="foo"
- organizations={
- Array [
- Object {
- "key": "foo",
- "name": "Foo",
- },
- ]
- }
- />
- <Alert
- className="abs-width-400 big-spacer-top"
- display="block"
- variant="info"
- >
- onboarding.import_organization.bind_members_not_sync_info_x.organization.github
- <Link
- className="spacer-left"
- onlyActiveOnIndex={false}
- style={Object {}}
- target="_blank"
- to={
- Object {
- "pathname": "/documentation/organizations/manage-team/",
- }
- }
- >
- learn_more
- </Link>
- </Alert>
- <div
- className="display-flex-center big-spacer-top"
- >
- <SubmitButton
- disabled={false}
- >
- onboarding.import_organization.bind
- </SubmitButton>
- </div>
-</form>
-`;
diff --git a/server/sonar-web/src/main/js/apps/create/organization/__tests__/__snapshots__/AutoOrganizationCreate-test.tsx.snap b/server/sonar-web/src/main/js/apps/create/organization/__tests__/__snapshots__/AutoOrganizationCreate-test.tsx.snap
deleted file mode 100644
index 9b74fb68d47..00000000000
--- a/server/sonar-web/src/main/js/apps/create/organization/__tests__/__snapshots__/AutoOrganizationCreate-test.tsx.snap
+++ /dev/null
@@ -1,216 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should display choice between import or creation 1`] = `
-<div>
- <OrganizationDetailsStep
- finished={false}
- onOpen={[MockFunction]}
- open={true}
- stepTitle="onboarding.import_organization.import_org_details"
- >
- <div
- className="huge-spacer-bottom"
- >
- <p
- className="display-flex-center big-spacer-bottom"
- >
- <FormattedMessage
- defaultMessage="onboarding.import_organization_x"
- id="onboarding.import_organization_x"
- values={
- Object {
- "avatar": <img
- alt="GitHub"
- className="little-spacer-left"
- src="/images/sonarcloud/github.svg"
- width={16}
- />,
- "name": <strong>
- foo
- </strong>,
- }
- }
- />
- <ClearButton
- className="little-spacer-left"
- onClick={[MockFunction]}
- />
- </p>
- <RadioToggle
- disabled={false}
- name="filter"
- onCheck={[Function]}
- options={
- Array [
- Object {
- "label": "onboarding.import_organization.create_new",
- "value": "create",
- },
- Object {
- "label": "onboarding.import_organization.bind_existing",
- "value": "bind",
- },
- ]
- }
- value={null}
- />
- </div>
- </OrganizationDetailsStep>
- <PlanStep
- almApplication={
- Object {
- "backgroundColor": "#444444",
- "iconPath": "/images/sonarcloud/github-white.svg",
- "installationUrl": "https://github.com/apps/greg-sonarcloud/installations/new",
- "key": "github",
- "name": "GitHub",
- }
- }
- almOrganization={
- Object {
- "almUrl": "https://github.com/foo",
- "avatar": "http://example.com/avatar",
- "description": "description-foo",
- "key": "foo",
- "name": "foo",
- "personal": false,
- "privateRepos": 0,
- "publicRepos": 3,
- "url": "http://example.com/foo",
- }
- }
- createOrganization={[Function]}
- onDone={[MockFunction]}
- onUpgradeFail={[MockFunction]}
- open={false}
- subscriptionPlans={
- Array [
- Object {
- "maxNcloc": 100000,
- "price": 10,
- },
- Object {
- "maxNcloc": 250000,
- "price": 75,
- },
- ]
- }
- />
-</div>
-`;
-
-exports[`should render prefilled and create org 1`] = `
-<div>
- <OrganizationDetailsStep
- finished={false}
- onOpen={[MockFunction]}
- open={true}
- stepTitle="onboarding.import_organization.import_org_details"
- >
- <div
- className="huge-spacer-bottom"
- >
- <p
- className="display-flex-center big-spacer-bottom"
- >
- <FormattedMessage
- defaultMessage="onboarding.import_organization_x"
- id="onboarding.import_organization_x"
- values={
- Object {
- "avatar": <img
- alt="GitHub"
- className="little-spacer-left"
- src="/images/sonarcloud/github.svg"
- width={16}
- />,
- "name": <strong>
- foo
- </strong>,
- }
- }
- />
- <ClearButton
- className="little-spacer-left"
- onClick={[MockFunction]}
- />
- </p>
- </div>
- <OrganizationDetailsForm
- infoBlock={
- <Alert
- className="abs-width-600 big-spacer-top"
- display="block"
- variant="info"
- >
- <p>
- onboarding.import_organization.members_sync_info_x.organization.github.foo.github
- </p>
- <a
- href="http://github.com/orgs/thing/people"
- rel="noopener noreferrer"
- target="_blank"
- >
- organization.members.see_all_members_on_x.github
- </a>
- </Alert>
- }
- onContinue={[MockFunction]}
- organization={
- Object {
- "almUrl": "http://github.com/thing",
- "avatar": "http://example.com/avatar",
- "description": "description-foo",
- "key": "foo",
- "name": "foo",
- "personal": false,
- "privateRepos": 0,
- "publicRepos": 3,
- "url": "http://example.com/foo",
- }
- }
- submitText="continue"
- />
- </OrganizationDetailsStep>
- <PlanStep
- almApplication={
- Object {
- "backgroundColor": "#444444",
- "iconPath": "/images/sonarcloud/github-white.svg",
- "installationUrl": "https://github.com/apps/greg-sonarcloud/installations/new",
- "key": "github",
- "name": "GitHub",
- }
- }
- almOrganization={
- Object {
- "almUrl": "http://github.com/thing",
- "avatar": "http://example.com/avatar",
- "description": "description-foo",
- "key": "foo",
- "name": "foo",
- "personal": false,
- "privateRepos": 0,
- "publicRepos": 3,
- "url": "http://example.com/foo",
- }
- }
- createOrganization={[Function]}
- onDone={[MockFunction]}
- onUpgradeFail={[MockFunction]}
- open={false}
- subscriptionPlans={
- Array [
- Object {
- "maxNcloc": 100000,
- "price": 10,
- },
- Object {
- "maxNcloc": 250000,
- "price": 75,
- },
- ]
- }
- />
-</div>
-`;
diff --git a/server/sonar-web/src/main/js/apps/create/organization/__tests__/__snapshots__/CreateOrganization-test.tsx.snap b/server/sonar-web/src/main/js/apps/create/organization/__tests__/__snapshots__/CreateOrganization-test.tsx.snap
deleted file mode 100644
index 927b7d368f9..00000000000
--- a/server/sonar-web/src/main/js/apps/create/organization/__tests__/__snapshots__/CreateOrganization-test.tsx.snap
+++ /dev/null
@@ -1,489 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render with auto tab displayed 1`] = `
-<Fragment>
- <Helmet
- defer={false}
- encodeSpecialCharacters={true}
- title="onboarding.create_organization.page.header"
- titleTemplate="%s"
- />
- <div
- className="page page-limited huge-spacer-top huge-spacer-bottom"
- >
- <A11ySkipTarget
- anchor="create_org_main"
- />
- <header
- className="page-header huge-spacer-bottom"
- >
- <h1
- className="page-title huge big-spacer-bottom"
- >
- <strong>
- onboarding.create_organization.page.header
- </strong>
- </h1>
- <p
- className="page-description"
- >
- onboarding.create_organization.page.description
- </p>
- </header>
- <Tabs
- onChange={[Function]}
- selected="auto"
- tabs={
- Array [
- Object {
- "key": "auto",
- "node": "onboarding.import_organization.import_from_x.github",
- },
- Object {
- "key": "manual",
- "node": "onboarding.create_organization.create_manually",
- },
- ]
- }
- />
- <ManualOrganizationCreate
- className="hidden"
- createOrganization={[MockFunction]}
- handleOrgDetailsFinish={[Function]}
- handleOrgDetailsStepOpen={[Function]}
- onDone={[Function]}
- onUpgradeFail={[Function]}
- step={0}
- subscriptionPlans={
- Array [
- Object {
- "maxNcloc": 100000,
- "price": 10,
- },
- Object {
- "maxNcloc": 250000,
- "price": 75,
- },
- ]
- }
- />
- <withRouter(RemoteOrganizationChoose)
- almApplication={
- Object {
- "backgroundColor": "blue",
- "iconPath": "icon/path",
- "installationUrl": "https://alm.installation.url",
- "key": "github",
- "name": "GitHub",
- }
- }
- almUnboundApplications={Array []}
- className=""
- />
- </div>
-</Fragment>
-`;
-
-exports[`should render with auto tab selected and manual disabled 1`] = `
-<AlmApplicationInstalling
- almKey="github"
-/>
-`;
-
-exports[`should render with auto tab selected and manual disabled 2`] = `
-<Fragment>
- <Helmet
- defer={false}
- encodeSpecialCharacters={true}
- title="onboarding.create_organization.page.header"
- titleTemplate="%s"
- />
- <div
- className="page page-limited huge-spacer-top huge-spacer-bottom"
- >
- <A11ySkipTarget
- anchor="create_org_main"
- />
- <header
- className="page-header huge-spacer-bottom"
- >
- <h1
- className="page-title huge big-spacer-bottom"
- >
- <strong>
- onboarding.create_organization.page.header
- </strong>
- </h1>
- <p
- className="page-description"
- >
- onboarding.create_organization.page.description
- </p>
- </header>
- <Tabs
- onChange={[Function]}
- selected="auto"
- tabs={
- Array [
- Object {
- "key": "auto",
- "node": "onboarding.import_organization.import_from_x.github",
- },
- Object {
- "key": "manual",
- "node": "onboarding.create_organization.create_manually",
- },
- ]
- }
- />
- <ManualOrganizationCreate
- className="hidden"
- createOrganization={[MockFunction]}
- handleOrgDetailsFinish={[Function]}
- handleOrgDetailsStepOpen={[Function]}
- onDone={[Function]}
- onUpgradeFail={[Function]}
- step={0}
- subscriptionPlans={
- Array [
- Object {
- "maxNcloc": 100000,
- "price": 10,
- },
- Object {
- "maxNcloc": 250000,
- "price": 75,
- },
- ]
- }
- />
- <AutoOrganizationCreate
- almApplication={
- Object {
- "backgroundColor": "blue",
- "iconPath": "icon/path",
- "installationUrl": "https://alm.installation.url",
- "key": "github",
- "name": "GitHub",
- }
- }
- almInstallId="foo"
- almOrganization={
- Object {
- "avatar": "my-avatar",
- "description": "Continuous Code Quality",
- "key": "sonarsource",
- "name": "SonarSource",
- "privateRepos": 0,
- "publicRepos": 3,
- "url": "https://www.sonarsource.com",
- }
- }
- className=""
- createOrganization={[MockFunction]}
- handleCancelImport={[Function]}
- handleOrgDetailsFinish={[Function]}
- handleOrgDetailsStepOpen={[Function]}
- onDone={[Function]}
- onOrgCreated={[Function]}
- onUpgradeFail={[Function]}
- step={0}
- subscriptionPlans={
- Array [
- Object {
- "maxNcloc": 100000,
- "price": 10,
- },
- Object {
- "maxNcloc": 250000,
- "price": 75,
- },
- ]
- }
- unboundOrganizations={
- Array [
- Object {
- "actions": Object {
- "admin": true,
- },
- "key": "foo",
- "name": "Foo",
- },
- ]
- }
- />
- </div>
-</Fragment>
-`;
-
-exports[`should render with manual tab displayed 1`] = `
-<Fragment>
- <Helmet
- defer={false}
- encodeSpecialCharacters={true}
- title="onboarding.create_organization.page.header"
- titleTemplate="%s"
- />
- <div
- className="page page-limited huge-spacer-top huge-spacer-bottom"
- >
- <A11ySkipTarget
- anchor="create_org_main"
- />
- <header
- className="page-header huge-spacer-bottom"
- >
- <h1
- className="page-title huge big-spacer-bottom"
- >
- <strong>
- onboarding.create_organization.page.header
- </strong>
- </h1>
- <p
- className="page-description"
- >
- onboarding.create_organization.page.description
- </p>
- </header>
- <ManualOrganizationCreate
- createOrganization={[MockFunction]}
- handleOrgDetailsFinish={[Function]}
- handleOrgDetailsStepOpen={[Function]}
- onDone={[Function]}
- onUpgradeFail={[Function]}
- step={0}
- subscriptionPlans={
- Array [
- Object {
- "maxNcloc": 100000,
- "price": 10,
- },
- Object {
- "maxNcloc": 250000,
- "price": 75,
- },
- ]
- }
- />
- </div>
-</Fragment>
-`;
-
-exports[`should render with organization bind page 1`] = `
-<AlmApplicationInstalling
- almKey="github"
-/>
-`;
-
-exports[`should render with organization bind page 2`] = `
-<Fragment>
- <Helmet
- defer={false}
- encodeSpecialCharacters={true}
- title="onboarding.create_organization.page.header"
- titleTemplate="%s"
- />
- <div
- className="page page-limited huge-spacer-top huge-spacer-bottom"
- >
- <A11ySkipTarget
- anchor="create_org_main"
- />
- <header
- className="page-header huge-spacer-bottom"
- >
- <h1
- className="page-title huge big-spacer-bottom"
- >
- <strong>
- onboarding.create_organization.page.header
- </strong>
- </h1>
- <p
- className="page-description"
- >
- onboarding.create_organization.page.description
- </p>
- </header>
- <Tabs
- onChange={[Function]}
- selected="auto"
- tabs={
- Array [
- Object {
- "key": "auto",
- "node": "onboarding.import_organization.import_from_x.github",
- },
- Object {
- "key": "manual",
- "node": "onboarding.create_organization.create_manually",
- },
- ]
- }
- />
- <ManualOrganizationCreate
- className="hidden"
- createOrganization={[MockFunction]}
- handleOrgDetailsFinish={[Function]}
- handleOrgDetailsStepOpen={[Function]}
- onDone={[Function]}
- onUpgradeFail={[Function]}
- step={0}
- subscriptionPlans={
- Array [
- Object {
- "maxNcloc": 100000,
- "price": 10,
- },
- Object {
- "maxNcloc": 250000,
- "price": 75,
- },
- ]
- }
- />
- <AutoOrganizationCreate
- almApplication={
- Object {
- "backgroundColor": "blue",
- "iconPath": "icon/path",
- "installationUrl": "https://alm.installation.url",
- "key": "github",
- "name": "GitHub",
- }
- }
- almInstallId="foo"
- almOrganization={
- Object {
- "almUrl": "https://github.com/foo",
- "avatar": "http://example.com/avatar",
- "description": "description-foo",
- "key": "foo",
- "name": "foo",
- "personal": false,
- "privateRepos": 0,
- "publicRepos": 3,
- "url": "http://example.com/foo",
- }
- }
- className=""
- createOrganization={[MockFunction]}
- handleCancelImport={[Function]}
- handleOrgDetailsFinish={[Function]}
- handleOrgDetailsStepOpen={[Function]}
- onDone={[Function]}
- onOrgCreated={[Function]}
- onUpgradeFail={[Function]}
- step={0}
- subscriptionPlans={
- Array [
- Object {
- "maxNcloc": 100000,
- "price": 10,
- },
- Object {
- "maxNcloc": 250000,
- "price": 75,
- },
- ]
- }
- unboundOrganizations={
- Array [
- Object {
- "actions": Object {
- "admin": true,
- },
- "key": "foo",
- "name": "Foo",
- },
- ]
- }
- />
- </div>
-</Fragment>
-`;
-
-exports[`should switch tabs 1`] = `
-<Fragment>
- <Helmet
- defer={false}
- encodeSpecialCharacters={true}
- title="onboarding.create_organization.page.header"
- titleTemplate="%s"
- />
- <div
- className="page page-limited huge-spacer-top huge-spacer-bottom"
- >
- <A11ySkipTarget
- anchor="create_org_main"
- />
- <header
- className="page-header huge-spacer-bottom"
- >
- <h1
- className="page-title huge big-spacer-bottom"
- >
- <strong>
- onboarding.create_organization.page.header
- </strong>
- </h1>
- <p
- className="page-description"
- >
- onboarding.create_organization.page.description
- </p>
- </header>
- <Tabs
- onChange={[Function]}
- selected="auto"
- tabs={
- Array [
- Object {
- "key": "auto",
- "node": "onboarding.import_organization.import_from_x.github",
- },
- Object {
- "key": "manual",
- "node": "onboarding.create_organization.create_manually",
- },
- ]
- }
- />
- <ManualOrganizationCreate
- className="hidden"
- createOrganization={[MockFunction]}
- handleOrgDetailsFinish={[Function]}
- handleOrgDetailsStepOpen={[Function]}
- onDone={[Function]}
- onUpgradeFail={[Function]}
- step={0}
- subscriptionPlans={
- Array [
- Object {
- "maxNcloc": 100000,
- "price": 10,
- },
- Object {
- "maxNcloc": 250000,
- "price": 75,
- },
- ]
- }
- />
- <withRouter(RemoteOrganizationChoose)
- almApplication={
- Object {
- "backgroundColor": "blue",
- "iconPath": "icon/path",
- "installationUrl": "https://alm.installation.url",
- "key": "github",
- "name": "GitHub",
- }
- }
- almUnboundApplications={Array []}
- className=""
- />
- </div>
-</Fragment>
-`;
diff --git a/server/sonar-web/src/main/js/apps/create/organization/__tests__/__snapshots__/ManualOrganizationCreate-test.tsx.snap b/server/sonar-web/src/main/js/apps/create/organization/__tests__/__snapshots__/ManualOrganizationCreate-test.tsx.snap
deleted file mode 100644
index 9ede472a8d9..00000000000
--- a/server/sonar-web/src/main/js/apps/create/organization/__tests__/__snapshots__/ManualOrganizationCreate-test.tsx.snap
+++ /dev/null
@@ -1,84 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render and create organization 1`] = `
-<div>
- <OrganizationDetailsStep
- finished={false}
- onOpen={[MockFunction]}
- open={true}
- >
- <OrganizationDetailsForm
- onContinue={[MockFunction]}
- submitText="continue"
- />
- </OrganizationDetailsStep>
- <PlanStep
- createOrganization={[Function]}
- onDone={[MockFunction]}
- onUpgradeFail={[MockFunction]}
- open={false}
- subscriptionPlans={
- Array [
- Object {
- "maxNcloc": 100000,
- "price": 10,
- },
- Object {
- "maxNcloc": 250000,
- "price": 75,
- },
- ]
- }
- />
-</div>
-`;
-
-exports[`should render and create organization 2`] = `
-<div>
- <OrganizationDetailsStep
- finished={false}
- onOpen={[MockFunction]}
- open={false}
- >
- <OrganizationDetailsForm
- onContinue={
- [MockFunction] {
- "calls": Array [
- Array [
- Object {
- "key": "foo",
- "name": "Foo",
- },
- ],
- ],
- "results": Array [
- Object {
- "type": "return",
- "value": undefined,
- },
- ],
- }
- }
- submitText="continue"
- />
- </OrganizationDetailsStep>
- <PlanStep
- createOrganization={[Function]}
- onDone={[MockFunction]}
- onUpgradeFail={[MockFunction]}
- open={true}
- subscriptionPlans={
- Array [
- Object {
- "maxNcloc": 100000,
- "price": 10,
- },
- Object {
- "maxNcloc": 250000,
- "price": 75,
- },
- ]
- }
- />
-</div>
-`;
diff --git a/server/sonar-web/src/main/js/apps/create/organization/__tests__/__snapshots__/OrganizationDetailsForm-test.tsx.snap b/server/sonar-web/src/main/js/apps/create/organization/__tests__/__snapshots__/OrganizationDetailsForm-test.tsx.snap
deleted file mode 100644
index b29f23245fe..00000000000
--- a/server/sonar-web/src/main/js/apps/create/organization/__tests__/__snapshots__/OrganizationDetailsForm-test.tsx.snap
+++ /dev/null
@@ -1,107 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render form 1`] = `
-<form
- id="organization-form"
- onSubmit={[Function]}
->
- <OrganizationKeyInput
- onChange={[Function]}
- />
- <div
- className="big-spacer-top"
- >
- <ResetButtonLink
- onClick={[Function]}
- >
- onboarding.create_organization.add_additional_info
- <DropdownIcon
- className="little-spacer-left"
- turned={false}
- />
- </ResetButtonLink>
- </div>
- <div
- className="js-additional-info"
- hidden={true}
- >
- <div
- className="big-spacer-top"
- >
- <label
- htmlFor="organization-display-name"
- >
- <strong>
- onboarding.create_organization.display_name
- </strong>
- </label>
- <div
- className="little-spacer-top"
- >
- <input
- className="input-super-large text-middle"
- id="organization-display-name"
- maxLength={255}
- onChange={[Function]}
- type="text"
- value=""
- />
- </div>
- <div
- className="note abs-width-400"
- >
- onboarding.create_organization.display_name.description
- </div>
- </div>
- <div
- className="big-spacer-top"
- >
- <OrganizationAvatarInput
- initialValue=""
- name=""
- onChange={[Function]}
- />
- </div>
- <div
- className="big-spacer-top"
- >
- <label
- htmlFor="organization-description"
- >
- <strong>
- onboarding.create_organization.description
- </strong>
- </label>
- <div
- className="little-spacer-top"
- >
- <textarea
- className="input-super-large text-middle"
- id="organization-description"
- maxLength={256}
- onChange={[Function]}
- rows={3}
- value=""
- />
- </div>
- </div>
- <div
- className="big-spacer-top"
- >
- <OrganizationUrlInput
- initialValue=""
- onChange={[Function]}
- />
- </div>
- </div>
- <div
- className="display-flex-center big-spacer-top"
- >
- <SubmitButton
- disabled={true}
- >
- continue
- </SubmitButton>
- </div>
-</form>
-`;
diff --git a/server/sonar-web/src/main/js/apps/create/organization/__tests__/__snapshots__/OrganizationDetailsStep-test.tsx.snap b/server/sonar-web/src/main/js/apps/create/organization/__tests__/__snapshots__/OrganizationDetailsStep-test.tsx.snap
deleted file mode 100644
index 3b15b770b40..00000000000
--- a/server/sonar-web/src/main/js/apps/create/organization/__tests__/__snapshots__/OrganizationDetailsStep-test.tsx.snap
+++ /dev/null
@@ -1,28 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render form 1`] = `
-<Step
- finished={false}
- onOpen={[MockFunction]}
- open={true}
- renderForm={[Function]}
- renderResult={[Function]}
- stepNumber={1}
- stepTitle="onboarding.create_organization.enter_org_details"
-/>
-`;
-
-exports[`should render result 1`] = `
-<div
- className="boxed-group-actions display-flex-center"
->
- <AlertSuccessIcon
- className="spacer-right"
- />
- <strong
- className="text-limited"
- >
- org
- </strong>
-</div>
-`;
diff --git a/server/sonar-web/src/main/js/apps/create/organization/__tests__/__snapshots__/PlanSelect-test.tsx.snap b/server/sonar-web/src/main/js/apps/create/organization/__tests__/__snapshots__/PlanSelect-test.tsx.snap
deleted file mode 100644
index cb99c558c4a..00000000000
--- a/server/sonar-web/src/main/js/apps/create/organization/__tests__/__snapshots__/PlanSelect-test.tsx.snap
+++ /dev/null
@@ -1,47 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render and select 1`] = `
-<div
- aria-label="onboarding.create_organization.choose_plan"
- className="display-flex-row huge-spacer-bottom"
- role="radiogroup"
->
- <FreeCardPlan
- disabled={false}
- hasWarning={false}
- key="free"
- onClick={[Function]}
- selected={true}
- />
- <PaidCardPlan
- isRecommended={false}
- key="paid"
- onClick={[Function]}
- selected={false}
- startingPrice={10}
- />
-</div>
-`;
-
-exports[`should render and select 2`] = `
-<div
- aria-label="onboarding.create_organization.choose_plan"
- className="display-flex-row huge-spacer-bottom"
- role="radiogroup"
->
- <FreeCardPlan
- disabled={false}
- hasWarning={false}
- key="free"
- onClick={[Function]}
- selected={false}
- />
- <PaidCardPlan
- isRecommended={false}
- key="paid"
- onClick={[Function]}
- selected={true}
- startingPrice={10}
- />
-</div>
-`;
diff --git a/server/sonar-web/src/main/js/apps/create/organization/__tests__/__snapshots__/PlanStep-test.tsx.snap b/server/sonar-web/src/main/js/apps/create/organization/__tests__/__snapshots__/PlanStep-test.tsx.snap
deleted file mode 100644
index ca7cb711940..00000000000
--- a/server/sonar-web/src/main/js/apps/create/organization/__tests__/__snapshots__/PlanStep-test.tsx.snap
+++ /dev/null
@@ -1,163 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should preselect paid plan 1`] = `
-<div
- className="boxed-group onboarding-step is-open"
->
- <div
- className="onboarding-step-number"
- >
- 2
- </div>
- <div
- className="boxed-group-header"
- >
- <h2>
- onboarding.create_organization.enter_payment_details
- </h2>
- </div>
- <div
- className=""
- >
- <div
- className="boxed-group-inner"
- >
- <PlanSelect
- almOrganization={
- Object {
- "almUrl": "https://github.com/foo",
- "avatar": "http://example.com/avatar",
- "description": "description-foo",
- "key": "foo",
- "name": "foo",
- "personal": false,
- "privateRepos": 5,
- "publicRepos": 0,
- "url": "http://example.com/foo",
- }
- }
- onChange={[Function]}
- plan="paid"
- startingPrice={100}
- />
- <Connect(withCurrentUser(BillingFormShim))
- onCommit={[MockFunction]}
- onFailToUpgrade={[MockFunction]}
- organizationKey={[MockFunction]}
- subscriptionPlans={
- Array [
- Object {
- "maxNcloc": 1000,
- "price": 100,
- },
- ]
- }
- >
- <Component />
- </Connect(withCurrentUser(BillingFormShim))>
- </div>
- </div>
-</div>
-`;
-
-exports[`should render and use free plan 1`] = `
-<Step
- finished={false}
- onOpen={[Function]}
- open={true}
- renderForm={[Function]}
- renderResult={[Function]}
- stepNumber={2}
- stepTitle="onboarding.create_organization.choose_plan"
-/>
-`;
-
-exports[`should render and use free plan 2`] = `
-<div
- className="boxed-group onboarding-step is-open"
->
- <div
- className="onboarding-step-number"
- >
- 2
- </div>
- <div
- className="boxed-group-header"
- >
- <h2>
- onboarding.create_organization.choose_plan
- </h2>
- </div>
- <div
- className=""
- >
- <div
- className="boxed-group-inner"
- >
- <PlanSelect
- onChange={[Function]}
- plan="free"
- startingPrice={100}
- />
- <form
- className="display-flex-center big-spacer-top"
- id="organization-free-plan-form"
- onSubmit={[Function]}
- >
- <SubmitButton
- disabled={false}
- >
- my_account.create_organization
- </SubmitButton>
- </form>
- </div>
- </div>
-</div>
-`;
-
-exports[`should upgrade 1`] = `
-<div
- className="boxed-group onboarding-step is-open"
->
- <div
- className="onboarding-step-number"
- >
- 2
- </div>
- <div
- className="boxed-group-header"
- >
- <h2>
- onboarding.create_organization.choose_plan
- </h2>
- </div>
- <div
- className=""
- >
- <div
- className="boxed-group-inner"
- >
- <PlanSelect
- onChange={[Function]}
- plan="paid"
- startingPrice={100}
- />
- <Connect(withCurrentUser(BillingFormShim))
- onCommit={[MockFunction]}
- onFailToUpgrade={[MockFunction]}
- organizationKey={[MockFunction]}
- subscriptionPlans={
- Array [
- Object {
- "maxNcloc": 1000,
- "price": 100,
- },
- ]
- }
- >
- <Component />
- </Connect(withCurrentUser(BillingFormShim))>
- </div>
- </div>
-</div>
-`;
diff --git a/server/sonar-web/src/main/js/apps/create/organization/__tests__/__snapshots__/RemoteOrganizationChoose-test.tsx.snap b/server/sonar-web/src/main/js/apps/create/organization/__tests__/__snapshots__/RemoteOrganizationChoose-test.tsx.snap
deleted file mode 100644
index 946d551efa3..00000000000
--- a/server/sonar-web/src/main/js/apps/create/organization/__tests__/__snapshots__/RemoteOrganizationChoose-test.tsx.snap
+++ /dev/null
@@ -1,195 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should display already bound alert message 1`] = `
-<Alert
- className="big-spacer-bottom width-60"
- variant="error"
->
- <FormattedMessage
- defaultMessage="onboarding.import_organization.already_bound_x"
- id="onboarding.import_organization.already_bound_x"
- values={
- Object {
- "avatar": <img
- alt="GitHub"
- className="little-spacer-left"
- src="/images/sonarcloud/github.svg"
- width={16}
- />,
- "boundAvatar": <OrganizationAvatar
- className="little-spacer-left"
- organization={
- Object {
- "avatar": "bound-avatar",
- "key": "bound",
- "name": "Bound",
- }
- }
- small={true}
- />,
- "boundName": <strong>
- Bound
- </strong>,
- "name": <strong>
- foo
- </strong>,
- }
- }
- />
-</Alert>
-`;
-
-exports[`should display an alert message 1`] = `
-<Alert
- className="big-spacer-bottom width-60"
- variant="error"
->
- <div
- className="markdown"
- >
- onboarding.import_organization.org_not_found
- <ul>
- <li>
- onboarding.import_organization.org_not_found.tips_1
- </li>
- <li>
- onboarding.import_organization.org_not_found.tips_2
- </li>
- </ul>
- </div>
-</Alert>
-`;
-
-exports[`should display unbound installations 1`] = `
-<div
- className="boxed-group"
->
- <div
- className="boxed-group-header"
- >
- <h2>
- onboarding.import_organization.import_org_details
- </h2>
- </div>
- <div
- className="boxed-group-inner"
- >
- <div
- className="display-flex-center"
- >
- <div
- className="display-inline-block"
- >
- <IdentityProviderLink
- backgroundColor="blue"
- className="display-inline-block"
- iconPath="icon/path"
- name="GitHub"
- onClick={[Function]}
- small={true}
- url="https://alm.application.url"
- >
- onboarding.import_organization.choose_organization_button.github
- </IdentityProviderLink>
- </div>
- <div
- className="display-flex-stretch"
- >
- <div
- className="vertical-pipe-separator"
- >
- <div
- className="vertical-separator "
- />
- <span
- className="note"
- >
- or
- </span>
- <div
- className="vertical-separator"
- />
- </div>
- <form
- className="big-spacer-top big-spacer-bottom"
- onSubmit={[Function]}
- >
- <div
- className="form-field abs-width-400"
- >
- <label
- className="text-normal"
- htmlFor="select-unbound-installation"
- >
- onboarding.import_organization.choose_unbound_installation_x.github
- </label>
- <Select
- className="input-super-large"
- clearable={false}
- id="select-unbound-installation"
- labelKey="name"
- onChange={[Function]}
- optionRenderer={[Function]}
- options={
- Array [
- Object {
- "installationId": "12345",
- "key": "foo",
- "name": "Foo",
- },
- ]
- }
- placeholder="onboarding.import_organization.choose_organization"
- value=""
- valueKey="installationId"
- valueRenderer={[Function]}
- />
- </div>
- <SubmitButton
- disabled={true}
- >
- continue
- </SubmitButton>
- </form>
- </div>
- </div>
- </div>
-</div>
-`;
-
-exports[`should render 1`] = `
-<div
- className="boxed-group"
->
- <div
- className="boxed-group-header"
- >
- <h2>
- onboarding.import_organization.import_org_details
- </h2>
- </div>
- <div
- className="boxed-group-inner"
- >
- <div
- className="display-flex-center"
- >
- <div
- className="display-inline-block"
- >
- <IdentityProviderLink
- backgroundColor="blue"
- className="display-inline-block"
- iconPath="icon/path"
- name="GitHub"
- onClick={[Function]}
- small={true}
- url="https://alm.application.url"
- >
- onboarding.import_organization.choose_organization_button.github
- </IdentityProviderLink>
- </div>
- </div>
- </div>
-</div>
-`;
diff --git a/server/sonar-web/src/main/js/apps/create/organization/__tests__/actions-test.ts b/server/sonar-web/src/main/js/apps/create/organization/__tests__/actions-test.ts
deleted file mode 100644
index 9248d38b46b..00000000000
--- a/server/sonar-web/src/main/js/apps/create/organization/__tests__/actions-test.ts
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import { createOrganization, syncMembers } from '../../../../api/organizations';
-import { mockOrganization, mockOrganizationWithAlm } from '../../../../helpers/testMocks';
-import * as actions from '../actions';
-
-jest.mock('../../../../api/alm-integration', () => ({
- bindAlmOrganization: jest.fn().mockResolvedValue({})
-}));
-
-jest.mock('../../../../api/organizations', () => ({
- createOrganization: jest.fn().mockResolvedValue({ key: 'foo', name: 'Foo' }),
- updateOrganization: jest.fn().mockResolvedValue({}),
- syncMembers: jest.fn()
-}));
-
-const dispatch = jest.fn();
-
-beforeEach(() => {
- jest.clearAllMocks();
-});
-
-describe('#createOrganization', () => {
- it('should create and return an org key', async () => {
- const org = mockOrganization();
- const promise = actions.createOrganization(org)(dispatch);
-
- expect(createOrganization).toHaveBeenCalledWith(org);
- const returnValue = await promise;
- expect(dispatch).toHaveBeenCalledWith({ organization: org, type: 'CREATE_ORGANIZATION' });
- expect(syncMembers).not.toBeCalled();
- expect(returnValue).toBe(org.key);
- });
-
- it('should create and sync members', async () => {
- const { alm, ...org } = mockOrganizationWithAlm(
- {},
- { key: 'github', membersSync: true, url: 'https://github.com/foo' }
- );
-
- (createOrganization as jest.Mock).mockResolvedValueOnce(org);
- const promise = actions.createOrganization({ alm, ...org })(dispatch);
-
- expect(createOrganization).toHaveBeenCalledWith(org);
- await promise;
- expect(syncMembers).toHaveBeenCalledWith(org.key);
- });
-
- it('should not sync members for personal Github orgs', async () => {
- const { alm, ...org } = mockOrganizationWithAlm(
- {},
- { key: 'github', membersSync: true, personal: true, url: 'https://github.com/foo' }
- );
-
- (createOrganization as jest.Mock).mockResolvedValueOnce(org);
- const promise = actions.createOrganization({ alm, ...org })(dispatch);
-
- expect(createOrganization).toHaveBeenCalledWith(org);
- await promise;
- expect(syncMembers).not.toBeCalled();
- });
-});
diff --git a/server/sonar-web/src/main/js/apps/create/organization/__tests__/utils-test.tsx b/server/sonar-web/src/main/js/apps/create/organization/__tests__/utils-test.tsx
deleted file mode 100644
index 8ba2a9f1824..00000000000
--- a/server/sonar-web/src/main/js/apps/create/organization/__tests__/utils-test.tsx
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import { formatPrice } from '../utils';
-
-jest.mock('sonar-ui-common/helpers/urls', () => ({
- getHostUrl: () => 'http://host.url'
-}));
-
-describe('#formatPrice', () => {
- it('formats correctly', () => {
- expect(formatPrice(10)).toBe('billing.price_format.10');
- expect(formatPrice(10000)).toBe('billing.price_format.10,000');
- expect(formatPrice(10000, true)).toBe('10,000');
- });
-});
diff --git a/server/sonar-web/src/main/js/apps/create/organization/actions.ts b/server/sonar-web/src/main/js/apps/create/organization/actions.ts
deleted file mode 100644
index 4abaa682d0f..00000000000
--- a/server/sonar-web/src/main/js/apps/create/organization/actions.ts
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import { Dispatch } from 'redux';
-import * as api from '../../../api/organizations';
-import { isGithub } from '../../../helpers/almIntegrations';
-import * as actions from '../../../store/organizations';
-
-export function createOrganization({
- alm,
- ...organization
-}: T.Organization & { installationId?: string }) {
- return (dispatch: Dispatch) => {
- return api
- .createOrganization({ ...organization, name: organization.name || organization.key })
- .then((newOrganization: T.Organization) => {
- dispatch(actions.createOrganization({ ...newOrganization, alm }));
- if (alm && alm.membersSync && !alm.personal && isGithub(alm.key)) {
- api.syncMembers(newOrganization.key);
- }
- return newOrganization.key;
- });
- };
-}
diff --git a/server/sonar-web/src/main/js/apps/create/organization/utils.ts b/server/sonar-web/src/main/js/apps/create/organization/utils.ts
deleted file mode 100644
index e0d5ca58124..00000000000
--- a/server/sonar-web/src/main/js/apps/create/organization/utils.ts
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import { memoize } from 'lodash';
-import { translateWithParameters } from 'sonar-ui-common/helpers/l10n';
-import { formatMeasure } from 'sonar-ui-common/helpers/measures';
-import { cleanQuery, parseAsOptionalString, serializeString } from 'sonar-ui-common/helpers/query';
-import { decodeJwt } from 'sonar-ui-common/helpers/strings';
-import { isBitbucket, isGithub } from '../../../helpers/almIntegrations';
-
-export const ORGANIZATION_IMPORT_BINDING_IN_PROGRESS_TIMESTAMP =
- 'sonarcloud.import_org.binding_in_progress';
-
-export const ORGANIZATION_IMPORT_REDIRECT_TO_PROJECT_TIMESTAMP =
- 'sonarcloud.import_org.redirect_to_projects';
-
-export const BIND_ORGANIZATION_KEY = 'sonarcloud.bind_org.key';
-
-export const BIND_ORGANIZATION_REDIRECT_TO_ORG_TIMESTAMP = 'sonarcloud.bind_org.redirect_to_org';
-
-export enum Step {
- OrganizationDetails,
- Plan
-}
-
-export function formatPrice(price?: number, noSign?: boolean) {
- const priceFormatted = formatMeasure(price, 'FLOAT')
- .replace(/[.|,]0$/, '')
- .replace(/([.|,]\d)$/, '$10');
- return noSign ? priceFormatted : translateWithParameters('billing.price_format', priceFormatted);
-}
-
-export interface Query {
- almInstallId?: string;
- almKey?: string;
-}
-
-export const parseQuery = memoize(
- (urlQuery: T.RawQuery = {}): Query => {
- let almInstallId = undefined;
- let almKey = undefined;
-
- if (urlQuery['installation_id']) {
- almKey = 'github';
- almInstallId = parseAsOptionalString(urlQuery['installation_id']);
- } else if (urlQuery['clientKey']) {
- almKey = 'bitbucket';
- almInstallId = parseAsOptionalString(urlQuery['clientKey']);
- } else if (urlQuery['jwt']) {
- const jwt = decodeJwt(urlQuery['jwt']);
- if (jwt && jwt.iss) {
- almKey = 'bitbucket';
- almInstallId = jwt.iss;
- }
- }
- return { almInstallId, almKey };
- }
-);
-
-export const serializeQuery = (query: Query): T.RawQuery =>
- cleanQuery({
- installation_id: isGithub(query.almKey) ? serializeString(query.almInstallId) : undefined,
- clientKey: isBitbucket(query.almKey) ? serializeString(query.almInstallId) : undefined
- });
diff --git a/server/sonar-web/src/main/js/apps/organizationMembers/AddMemberForm.tsx b/server/sonar-web/src/main/js/apps/organizationMembers/AddMemberForm.tsx
deleted file mode 100644
index 40bd2b774c8..00000000000
--- a/server/sonar-web/src/main/js/apps/organizationMembers/AddMemberForm.tsx
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import * as React from 'react';
-import { Button, ResetButtonLink, SubmitButton } from 'sonar-ui-common/components/controls/buttons';
-import Modal from 'sonar-ui-common/components/controls/Modal';
-import { translate } from 'sonar-ui-common/helpers/l10n';
-import { searchMembers } from '../../api/organizations';
-import UsersSelectSearch from '../users/components/UsersSelectSearch';
-
-interface Props {
- addMember: (member: T.OrganizationMember) => void;
- organization: T.Organization;
- memberLogins: string[];
-}
-
-interface State {
- open: boolean;
- selectedMember?: T.OrganizationMember;
-}
-
-export default class AddMemberForm extends React.PureComponent<Props, State> {
- state: State = {
- open: false
- };
-
- openForm = () => {
- this.setState({ open: true });
- };
-
- closeForm = () => {
- this.setState({ open: false, selectedMember: undefined });
- };
-
- handleSearch = (query: string | undefined, ps: number) => {
- const data = { organization: this.props.organization.key, ps, selected: 'deselected' };
- if (!query) {
- return searchMembers(data);
- }
- return searchMembers({ ...data, q: query });
- };
-
- handleSubmit = (event: React.FormEvent<HTMLFormElement>) => {
- event.preventDefault();
- if (this.state.selectedMember) {
- this.props.addMember(this.state.selectedMember);
- this.closeForm();
- }
- };
-
- selectedMemberChange = (member: T.OrganizationMember) => {
- this.setState({ selectedMember: member });
- };
-
- renderModal() {
- const header = translate('users.add');
- return (
- <Modal contentLabel={header} key="add-member-modal" onRequestClose={this.closeForm}>
- <header className="modal-head">
- <h2>{header}</h2>
- </header>
- <form onSubmit={this.handleSubmit}>
- <div className="modal-body">
- <div className="modal-field">
- <label>{translate('users.search_description')}</label>
- <UsersSelectSearch
- autoFocus={true}
- excludedUsers={this.props.memberLogins}
- handleValueChange={this.selectedMemberChange}
- searchUsers={this.handleSearch}
- selectedUser={this.state.selectedMember}
- />
- </div>
- </div>
- <footer className="modal-foot">
- <div>
- <SubmitButton disabled={!this.state.selectedMember}>
- {translate('organization.members.add_to_members')}
- </SubmitButton>
- <ResetButtonLink onClick={this.closeForm}>{translate('cancel')}</ResetButtonLink>
- </div>
- </footer>
- </form>
- </Modal>
- );
- }
-
- render() {
- return (
- <>
- <Button key="add-member-button" onClick={this.openForm}>
- {translate('organization.members.add')}
- </Button>
- {this.state.open && this.renderModal()}
- </>
- );
- }
-}
diff --git a/server/sonar-web/src/main/js/apps/organizationMembers/ManageMemberGroupsForm.tsx b/server/sonar-web/src/main/js/apps/organizationMembers/ManageMemberGroupsForm.tsx
deleted file mode 100644
index c1198762ffb..00000000000
--- a/server/sonar-web/src/main/js/apps/organizationMembers/ManageMemberGroupsForm.tsx
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import { keyBy, pickBy, some } from 'lodash';
-import * as React from 'react';
-import { ResetButtonLink, SubmitButton } from 'sonar-ui-common/components/controls/buttons';
-import SimpleModal from 'sonar-ui-common/components/controls/SimpleModal';
-import DeferredSpinner from 'sonar-ui-common/components/ui/DeferredSpinner';
-import { translate, translateWithParameters } from 'sonar-ui-common/helpers/l10n';
-import { getUserGroups, UserGroup } from '../../api/users';
-import OrganizationGroupCheckbox from '../organizations/components/OrganizationGroupCheckbox';
-
-interface Props {
- onClose: () => void;
- member: T.OrganizationMember;
- organization: T.Organization;
- organizationGroups: T.Group[];
- updateMemberGroups: (
- member: T.OrganizationMember,
- add: string[],
- remove: string[]
- ) => Promise<void>;
-}
-
-interface State {
- userGroups?: T.Dict<UserGroup & { status?: string }>;
- loading?: boolean;
-}
-
-export default class ManageMemberGroupsForm extends React.PureComponent<Props, State> {
- mounted = false;
- state: State = {};
-
- componentDidMount() {
- this.mounted = true;
- this.loadUserGroups();
- }
-
- componentWillUnmount() {
- this.mounted = false;
- }
-
- loadUserGroups = () => {
- this.setState({ loading: true });
- getUserGroups({
- login: this.props.member.login,
- organization: this.props.organization.key
- }).then(
- response => {
- if (this.mounted) {
- this.setState({ loading: false, userGroups: keyBy(response.groups, 'name') });
- }
- },
- () => {
- if (this.mounted) {
- this.setState({ loading: false });
- }
- }
- );
- };
-
- isGroupSelected = (groupName: string) => {
- if (this.state.userGroups) {
- const group = this.state.userGroups[groupName] || {};
- if (group.status) {
- return group.status === 'add';
- } else {
- return group.selected === true;
- }
- }
- return false;
- };
-
- onCheck = (groupName: string, checked: boolean) => {
- this.setState((prevState: State) => {
- const { userGroups = {} } = prevState;
- const group = userGroups[groupName] || {};
- let status = '';
- if (group.selected && !checked) {
- status = 'remove';
- } else if (!group.selected && checked) {
- status = 'add';
- }
- return { userGroups: { ...userGroups, [groupName]: { ...group, status } } };
- });
- };
-
- handleSubmit = () => {
- return this.props
- .updateMemberGroups(
- this.props.member,
- Object.keys(pickBy(this.state.userGroups, group => group.status === 'add')),
- Object.keys(pickBy(this.state.userGroups, group => group.status === 'remove'))
- )
- .then(this.props.onClose);
- };
-
- render() {
- const { loading, userGroups = {} } = this.state;
- const header = translate('organization.members.manage_groups');
- const hasChanges = some(userGroups, group => group.status !== undefined);
- return (
- <SimpleModal header={header} onClose={this.props.onClose} onSubmit={this.handleSubmit}>
- {({ onCloseClick, onFormSubmit, submitting }) => (
- <form onSubmit={onFormSubmit}>
- <header className="modal-head">
- <h2>{header}</h2>
- </header>
- <div className="modal-body modal-container">
- <p>
- <strong>
- {translateWithParameters(
- 'organization.members.members_groups',
- this.props.member.name
- )}
- </strong>
- </p>
- {loading ? (
- <DeferredSpinner className="spacer-top" />
- ) : (
- <ul className="list-spaced">
- {this.props.organizationGroups.map(group => (
- <OrganizationGroupCheckbox
- checked={this.isGroupSelected(group.name)}
- group={group}
- key={group.name}
- onCheck={this.onCheck}
- />
- ))}
- </ul>
- )}
- </div>
-
- <footer className="modal-foot">
- <DeferredSpinner className="spacer-right" loading={submitting} />
- <SubmitButton disabled={submitting || !hasChanges}>{translate('save')}</SubmitButton>
- <ResetButtonLink disabled={submitting} onClick={onCloseClick}>
- {translate('cancel')}
- </ResetButtonLink>
- </footer>
- </form>
- )}
- </SimpleModal>
- );
- }
-}
diff --git a/server/sonar-web/src/main/js/apps/organizationMembers/MembersList.tsx b/server/sonar-web/src/main/js/apps/organizationMembers/MembersList.tsx
deleted file mode 100644
index 551ca6b51c9..00000000000
--- a/server/sonar-web/src/main/js/apps/organizationMembers/MembersList.tsx
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import { sortBy } from 'lodash';
-import * as React from 'react';
-import { translate } from 'sonar-ui-common/helpers/l10n';
-import MembersListItem from './MembersListItem';
-
-interface Props {
- currentUser: T.LoggedInUser;
- members: T.OrganizationMember[];
- organizationGroups: T.Group[];
- organization: T.Organization;
- removeMember?: (member: T.OrganizationMember) => void;
- updateMemberGroups: (
- member: T.OrganizationMember,
- add: Array<string>,
- remove: Array<string>
- ) => Promise<void>;
-}
-
-export default class MembersList extends React.PureComponent<Props> {
- render() {
- const { currentUser, members } = this.props;
-
- if (!members.length) {
- return <div className="note">{translate('no_results')}</div>;
- }
-
- const sortedMembers = sortBy(
- members,
- member => member.name,
- member => member.login
- );
- return (
- <div className="boxed-group boxed-group-inner">
- <table className="data zebra">
- <tbody>
- {sortedMembers.map(member => (
- <MembersListItem
- key={member.login}
- member={member}
- organization={this.props.organization}
- organizationGroups={this.props.organizationGroups}
- removeMember={
- currentUser.login !== member.login ? this.props.removeMember : undefined
- }
- updateMemberGroups={this.props.updateMemberGroups}
- />
- ))}
- </tbody>
- </table>
- </div>
- );
- }
-}
diff --git a/server/sonar-web/src/main/js/apps/organizationMembers/MembersListHeader.tsx b/server/sonar-web/src/main/js/apps/organizationMembers/MembersListHeader.tsx
deleted file mode 100644
index a4d39692988..00000000000
--- a/server/sonar-web/src/main/js/apps/organizationMembers/MembersListHeader.tsx
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import * as React from 'react';
-import HelpTooltip from 'sonar-ui-common/components/controls/HelpTooltip';
-import SearchBox from 'sonar-ui-common/components/controls/SearchBox';
-import { translate, translateWithParameters } from 'sonar-ui-common/helpers/l10n';
-import { formatMeasure } from 'sonar-ui-common/helpers/measures';
-import { getAlmMembersUrl, sanitizeAlmId } from '../../helpers/almIntegrations';
-
-export interface Props {
- handleSearch: (query?: string) => void;
- organization: T.Organization;
- total?: number;
-}
-
-export default function MembersListHeader({ handleSearch, organization, total }: Props) {
- return (
- <div className="panel panel-vertical bordered-bottom spacer-bottom">
- <SearchBox
- minLength={2}
- onChange={handleSearch}
- placeholder={translate('search.search_for_members')}
- />
- {total !== undefined && (
- <span className="pull-right little-spacer-top">
- <strong>{formatMeasure(total, 'INT')}</strong> {translate('organization.members.members')}
- {organization.alm && organization.alm.membersSync && (
- <HelpTooltip
- className="spacer-left"
- overlay={
- <div className="abs-width-300 markdown cut-margins">
- <p>
- {translate(
- 'organization.members.auto_sync_total_help',
- sanitizeAlmId(organization.alm.key)
- )}
- </p>
- <hr />
- <p>
- <a
- href={getAlmMembersUrl(organization.alm.key, organization.alm.url)}
- rel="noopener noreferrer"
- target="_blank">
- {translateWithParameters(
- 'organization.members.see_all_members_on_x',
- translate(sanitizeAlmId(organization.alm.key))
- )}
- </a>
- </p>
- </div>
- }
- />
- )}
- </span>
- )}
- </div>
- );
-}
diff --git a/server/sonar-web/src/main/js/apps/organizationMembers/MembersListItem.tsx b/server/sonar-web/src/main/js/apps/organizationMembers/MembersListItem.tsx
deleted file mode 100644
index c059d8daf39..00000000000
--- a/server/sonar-web/src/main/js/apps/organizationMembers/MembersListItem.tsx
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import * as React from 'react';
-import ActionsDropdown, {
- ActionsDropdownDivider,
- ActionsDropdownItem
-} from 'sonar-ui-common/components/controls/ActionsDropdown';
-import { translate, translateWithParameters } from 'sonar-ui-common/helpers/l10n';
-import { formatMeasure } from 'sonar-ui-common/helpers/measures';
-import Avatar from '../../components/ui/Avatar';
-import ManageMemberGroupsForm from './ManageMemberGroupsForm';
-import RemoveMemberForm from './RemoveMemberForm';
-
-interface Props {
- member: T.OrganizationMember;
- organization: T.Organization;
- organizationGroups: T.Group[];
- removeMember?: (member: T.OrganizationMember) => void;
- updateMemberGroups: (
- member: T.OrganizationMember,
- add: string[],
- remove: string[]
- ) => Promise<void>;
-}
-
-interface State {
- removeMemberForm: boolean;
- manageGroupsForm: boolean;
-}
-
-const AVATAR_SIZE = 36;
-
-export default class MembersListItem extends React.PureComponent<Props, State> {
- mounted = false;
- state: State = { removeMemberForm: false, manageGroupsForm: false };
-
- componentDidMount() {
- this.mounted = true;
- }
-
- componentWillUnmount() {
- this.mounted = false;
- }
-
- handleManageGroupsClick = () => {
- this.setState({ manageGroupsForm: true });
- };
-
- closeManageGroupsForm = () => {
- if (this.mounted) {
- this.setState({ manageGroupsForm: false });
- }
- };
-
- handleRemoveMemberClick = () => {
- this.setState({ removeMemberForm: true });
- };
-
- closeRemoveMemberForm = () => {
- if (this.mounted) {
- this.setState({ removeMemberForm: false });
- }
- };
-
- render() {
- const { member, organization, removeMember } = this.props;
- const { actions = {} } = organization;
- return (
- <tr>
- <td className="thin nowrap">
- <Avatar hash={member.avatar} name={member.name} size={AVATAR_SIZE} />
- </td>
- <td className="nowrap text-middle">
- <strong>{member.name}</strong>
- <span className="note little-spacer-left">{member.login}</span>
- </td>
- {actions.admin && (
- <td className="text-right text-middle">
- {translateWithParameters(
- 'organization.members.x_groups',
- formatMeasure(member.groupCount || 0, 'INT')
- )}
- </td>
- )}
- {actions.admin && (
- <>
- <td className="nowrap text-middle text-right">
- <ActionsDropdown>
- <ActionsDropdownItem onClick={this.handleManageGroupsClick}>
- {translate('organization.members.manage_groups')}
- </ActionsDropdownItem>
- {removeMember && (
- <>
- <ActionsDropdownDivider />
- <ActionsDropdownItem destructive={true} onClick={this.handleRemoveMemberClick}>
- {translate('organization.members.remove')}
- </ActionsDropdownItem>
- </>
- )}
- </ActionsDropdown>
- </td>
-
- {this.state.manageGroupsForm && (
- <ManageMemberGroupsForm
- member={this.props.member}
- onClose={this.closeManageGroupsForm}
- organization={this.props.organization}
- organizationGroups={this.props.organizationGroups}
- updateMemberGroups={this.props.updateMemberGroups}
- />
- )}
-
- {removeMember && this.state.removeMemberForm && (
- <RemoveMemberForm
- member={this.props.member}
- onClose={this.closeRemoveMemberForm}
- organization={this.props.organization}
- removeMember={removeMember}
- />
- )}
- </>
- )}
- </tr>
- );
- }
-}
diff --git a/server/sonar-web/src/main/js/apps/organizationMembers/MembersPageHeader.tsx b/server/sonar-web/src/main/js/apps/organizationMembers/MembersPageHeader.tsx
deleted file mode 100644
index 06bc49340fc..00000000000
--- a/server/sonar-web/src/main/js/apps/organizationMembers/MembersPageHeader.tsx
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import * as React from 'react';
-import { FormattedMessage } from 'react-intl';
-import { Link } from 'react-router';
-import { Alert } from 'sonar-ui-common/components/ui/Alert';
-import DeferredSpinner from 'sonar-ui-common/components/ui/DeferredSpinner';
-import { translate, translateWithParameters } from 'sonar-ui-common/helpers/l10n';
-import DocTooltip from '../../components/docs/DocTooltip';
-import { isGithub, sanitizeAlmId } from '../../helpers/almIntegrations';
-import AddMemberForm from './AddMemberForm';
-import SyncMemberForm from './SyncMemberForm';
-
-export interface Props {
- handleAddMember: (member: T.OrganizationMember) => void;
- loading: boolean;
- members?: T.OrganizationMember[];
- organization: T.Organization;
- refreshMembers: () => Promise<void>;
-}
-
-export default function MembersPageHeader(props: Props) {
- const { members, organization, refreshMembers } = props;
- const memberLogins = members ? members.map(member => member.login) : [];
- const isAdmin = organization.actions && organization.actions.admin;
- const almKey = organization.alm && sanitizeAlmId(organization.alm.key);
- const hasMemberSync = organization.alm && organization.alm.membersSync;
- const showSyncNotif = isAdmin && organization.alm && !hasMemberSync;
- const isSyncEligible =
- almKey && isGithub(almKey) && organization.alm && !organization.alm.personal;
-
- return (
- <header className="page-header">
- <h1 className="page-title">
- {translate('organization.members.page')}
- <DeferredSpinner className="little-spacer-left" loading={props.loading} />
- </h1>
-
- {isAdmin && (
- <div className="page-actions text-right">
- {isSyncEligible && !showSyncNotif && (
- <SyncMemberForm
- buttonText={translate('organization.members.config_synchro')}
- hasOtherMembers={members && members.length > 1}
- organization={organization}
- refreshMembers={refreshMembers}
- />
- )}
- {!hasMemberSync && (
- <div className="display-inline-block spacer-left spacer-bottom">
- <AddMemberForm
- addMember={props.handleAddMember}
- memberLogins={memberLogins}
- organization={organization}
- />
- <DocTooltip
- className="spacer-left"
- doc={import(
- /* webpackMode: "eager" */ 'Docs/tooltips/organizations/add-organization-member.md'
- )}
- />
- </div>
- )}
- </div>
- )}
- <div className="page-description">
- <FormattedMessage
- defaultMessage={translate('organization.members.page.description')}
- id="organization.members.page.description"
- values={{
- link: (
- <Link target="_blank" to="/documentation/organizations/manage-team/">
- {translate('organization.members.manage_a_team')}
- </Link>
- )
- }}
- />
- {almKey && isSyncEligible && showSyncNotif && (
- <Alert className="spacer-top" display="inline" variant="info">
- {translateWithParameters(
- 'organization.members.auto_sync_members_from_org_x',
- translate('organization', almKey)
- )}
- <span className="spacer-left">
- <SyncMemberForm
- buttonText={translate('configure')}
- hasOtherMembers={members && members.length > 1}
- organization={organization}
- refreshMembers={refreshMembers}
- />
- </span>
- </Alert>
- )}
- </div>
- </header>
- );
-}
diff --git a/server/sonar-web/src/main/js/apps/organizationMembers/OrganizationMembers.tsx b/server/sonar-web/src/main/js/apps/organizationMembers/OrganizationMembers.tsx
deleted file mode 100644
index 766921c28cf..00000000000
--- a/server/sonar-web/src/main/js/apps/organizationMembers/OrganizationMembers.tsx
+++ /dev/null
@@ -1,240 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import * as React from 'react';
-import { Helmet } from 'react-helmet-async';
-import ListFooter from 'sonar-ui-common/components/controls/ListFooter';
-import { translate } from 'sonar-ui-common/helpers/l10n';
-import { addMember, removeMember, searchMembers } from '../../api/organizations';
-import { addUserToGroup, removeUserFromGroup, searchUsersGroups } from '../../api/user_groups';
-import A11ySkipTarget from '../../app/components/a11y/A11ySkipTarget';
-import Suggestions from '../../app/components/embed-docs-modal/Suggestions';
-import MembersList from './MembersList';
-import MembersListHeader from './MembersListHeader';
-import MembersPageHeader from './MembersPageHeader';
-
-interface Props {
- currentUser: T.LoggedInUser;
- organization: T.Organization;
-}
-
-interface State {
- groups: T.Group[];
- loading: boolean;
- members?: T.OrganizationMember[];
- paging?: T.Paging;
- query: string;
-}
-
-const PAGE_SIZE = 50;
-
-export default class OrganizationMembers extends React.PureComponent<Props, State> {
- mounted = false;
- state: State = {
- groups: [],
- loading: true,
- query: ''
- };
-
- componentDidMount() {
- this.mounted = true;
- this.fetchMembers();
- if (this.props.organization.actions && this.props.organization.actions.admin) {
- this.fetchGroups();
- }
- }
-
- componentWillUnmount() {
- this.mounted = false;
- }
-
- stopLoading = () => {
- if (this.mounted) {
- this.setState({ loading: false });
- }
- };
-
- fetchMembers = (query?: string) => {
- this.setState({ loading: true });
- searchMembers({
- organization: this.props.organization.key,
- ps: PAGE_SIZE,
- q: query
- }).then(({ paging, users }) => {
- if (this.mounted) {
- this.setState({ loading: false, members: users, paging });
- }
- }, this.stopLoading);
- };
-
- fetchGroups = () => {
- searchUsersGroups({ organization: this.props.organization.key }).then(
- ({ groups }) => {
- if (this.mounted) {
- this.setState({ groups });
- }
- },
- () => {}
- );
- };
-
- handleSearchMembers = (query: string) => {
- this.setState({ query });
- this.fetchMembers(query || undefined); // empty string -> undefined
- };
-
- handleLoadMoreMembers = () => {
- const { paging, query } = this.state;
- if (!paging) {
- return;
- }
-
- this.setState({ loading: true });
- searchMembers({
- organization: this.props.organization.key,
- p: paging.pageIndex + 1,
- ps: PAGE_SIZE,
- q: query || undefined // empty string -> undefined
- }).then(({ paging, users }) => {
- if (this.mounted) {
- this.setState(({ members = [] }) => ({
- loading: false,
- members: [...members, ...users],
- paging
- }));
- }
- }, this.stopLoading);
- };
-
- handleAddMember = ({ login }: T.OrganizationMember) => {
- // TODO optimistic update
- addMember({ login, organization: this.props.organization.key }).then(
- member => {
- if (this.mounted) {
- this.setState(({ members, paging }) => ({
- members: members && [...members, member],
- paging: paging && { ...paging, total: paging.total + 1 }
- }));
- }
- },
- () => {}
- );
- };
-
- handleRemoveMember = ({ login }: T.OrganizationMember) => {
- // TODO optimistic update
- removeMember({ login, organization: this.props.organization.key }).then(
- () => {
- if (this.mounted) {
- this.setState(({ members, paging }) => ({
- members: members && members.filter(member => member.login !== login),
- paging: paging && { ...paging, total: paging.total - 1 }
- }));
- }
- },
- () => {}
- );
- };
-
- refreshMembers = () => {
- return searchMembers({
- organization: this.props.organization.key,
- ps: PAGE_SIZE,
- q: this.state.query || undefined
- }).then(({ paging, users }) => {
- if (this.mounted) {
- this.setState({ members: users, paging });
- }
- });
- };
-
- updateGroup = (
- login: string,
- updater: (member: T.OrganizationMember) => T.OrganizationMember
- ) => {
- this.setState(({ members }) => ({
- members: members && members.map(member => (member.login === login ? updater(member) : member))
- }));
- };
-
- updateMemberGroups = ({ login }: T.OrganizationMember, add: string[], remove: string[]) => {
- // TODO optimistic update
- const promises = [
- ...add.map(name =>
- addUserToGroup({ name, login, organization: this.props.organization.key })
- ),
- ...remove.map(name =>
- removeUserFromGroup({ name, login, organization: this.props.organization.key })
- )
- ];
- return Promise.all(promises).then(() => {
- if (this.mounted) {
- this.updateGroup(login, member => ({
- ...member,
- groupCount: (member.groupCount || 0) + add.length - remove.length
- }));
- }
- });
- };
-
- render() {
- const { currentUser, organization } = this.props;
- const { groups, loading, members, paging } = this.state;
- const hasMemberSync = organization.alm && organization.alm.membersSync;
- return (
- <div className="page page-limited">
- <Helmet defer={false} title={translate('organization.members.page')} />
- <Suggestions suggestions="organization_members" />
- <A11ySkipTarget anchor="members_main" />
- <MembersPageHeader
- handleAddMember={this.handleAddMember}
- loading={loading}
- members={members}
- organization={organization}
- refreshMembers={this.refreshMembers}
- />
- {members !== undefined && paging !== undefined && (
- <>
- <MembersListHeader
- handleSearch={this.handleSearchMembers}
- organization={organization}
- total={paging.total}
- />
- <MembersList
- currentUser={currentUser}
- members={members}
- organization={organization}
- organizationGroups={groups}
- removeMember={hasMemberSync ? undefined : this.handleRemoveMember}
- updateMemberGroups={this.updateMemberGroups}
- />
- {paging.total !== 0 && (
- <ListFooter
- count={members.length}
- loadMore={this.handleLoadMoreMembers}
- ready={!loading}
- total={paging.total}
- />
- )}
- </>
- )}
- </div>
- );
- }
-}
diff --git a/server/sonar-web/src/main/js/apps/organizationMembers/OrganizationMembersContainer.tsx b/server/sonar-web/src/main/js/apps/organizationMembers/OrganizationMembersContainer.tsx
deleted file mode 100644
index 7dfebf0b397..00000000000
--- a/server/sonar-web/src/main/js/apps/organizationMembers/OrganizationMembersContainer.tsx
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import { connect } from 'react-redux';
-import { withCurrentUser } from '../../components/hoc/withCurrentUser';
-import { getOrganizationByKey, Store } from '../../store/rootReducer';
-import OrganizationMembers from './OrganizationMembers';
-
-interface OwnProps {
- params: { organizationKey: string };
-}
-
-interface StateProps {
- organization: T.Organization;
-}
-
-const mapStateToProps = (state: Store, ownProps: OwnProps): StateProps => {
- return { organization: getOrganizationByKey(state, ownProps.params.organizationKey) };
-};
-
-export default withCurrentUser(connect(mapStateToProps)(OrganizationMembers));
diff --git a/server/sonar-web/src/main/js/apps/organizationMembers/RemoveMemberForm.tsx b/server/sonar-web/src/main/js/apps/organizationMembers/RemoveMemberForm.tsx
deleted file mode 100644
index ce93a356758..00000000000
--- a/server/sonar-web/src/main/js/apps/organizationMembers/RemoveMemberForm.tsx
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import * as React from 'react';
-import { ResetButtonLink, SubmitButton } from 'sonar-ui-common/components/controls/buttons';
-import Modal from 'sonar-ui-common/components/controls/Modal';
-import { translate, translateWithParameters } from 'sonar-ui-common/helpers/l10n';
-
-interface Props {
- onClose: () => void;
- member: T.OrganizationMember;
- organization: T.Organization;
- removeMember: (member: T.OrganizationMember) => void;
-}
-
-export default class RemoveMemberForm extends React.PureComponent<Props> {
- handleSubmit = (event: React.FormEvent<HTMLFormElement>) => {
- event.preventDefault();
- this.props.removeMember(this.props.member);
- this.props.onClose();
- };
-
- render() {
- const header = translate('users.remove');
- return (
- <Modal contentLabel={header} key="remove-member-modal" onRequestClose={this.props.onClose}>
- <header className="modal-head">
- <h2>{header}</h2>
- </header>
- <form onSubmit={this.handleSubmit}>
- <div className="modal-body">
- {translateWithParameters(
- 'organization.members.remove_x',
- this.props.member.name,
- this.props.organization.name
- )}
- </div>
- <footer className="modal-foot">
- <div>
- <SubmitButton autoFocus={true} className="button-red">
- {translate('remove')}
- </SubmitButton>
- <ResetButtonLink onClick={this.props.onClose}>{translate('cancel')}</ResetButtonLink>
- </div>
- </footer>
- </form>
- </Modal>
- );
- }
-}
diff --git a/server/sonar-web/src/main/js/apps/organizationMembers/SyncMemberForm.tsx b/server/sonar-web/src/main/js/apps/organizationMembers/SyncMemberForm.tsx
deleted file mode 100644
index 6e1f3a0e802..00000000000
--- a/server/sonar-web/src/main/js/apps/organizationMembers/SyncMemberForm.tsx
+++ /dev/null
@@ -1,175 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import * as React from 'react';
-import { connect } from 'react-redux';
-import { Link } from 'react-router';
-import { Button } from 'sonar-ui-common/components/controls/buttons';
-import ConfirmButton from 'sonar-ui-common/components/controls/ConfirmButton';
-import RadioCard from 'sonar-ui-common/components/controls/RadioCard';
-import { Alert } from 'sonar-ui-common/components/ui/Alert';
-import { translate, translateWithParameters } from 'sonar-ui-common/helpers/l10n';
-import { setOrganizationMemberSync, syncMembers } from '../../api/organizations';
-import { sanitizeAlmId } from '../../helpers/almIntegrations';
-import { fetchOrganization } from '../../store/rootActions';
-
-interface Props {
- buttonText: string;
- fetchOrganization: (key: string) => void;
- hasOtherMembers?: boolean;
- organization: T.Organization;
- refreshMembers: () => Promise<void>;
-}
-
-interface State {
- membersSync: boolean;
-}
-
-export class SyncMemberForm extends React.PureComponent<Props, State> {
- constructor(props: Props) {
- super(props);
- this.state = {
- membersSync: Boolean(props.organization.alm && props.organization.alm.membersSync)
- };
- }
-
- handleConfirm = () => {
- const { organization } = this.props;
- const { membersSync } = this.state;
-
- return setOrganizationMemberSync({
- organization: organization.key,
- enabled: membersSync
- }).then(() => {
- this.props.fetchOrganization(organization.key);
- if (membersSync) {
- return this.handleMemberSync();
- }
- });
- };
-
- handleManualClick = () => {
- this.setState({ membersSync: false });
- };
-
- handleAutoClick = () => {
- this.setState({ membersSync: true });
- };
-
- handleMemberSync = () => {
- return syncMembers(this.props.organization.key).then(this.props.refreshMembers);
- };
-
- renderModalDescription = () => {
- return (
- <p className="spacer-top">
- {translate('organization.members.management.description')}
- <Link
- className="spacer-left"
- target="_blank"
- to={{ pathname: '/documentation/organizations/manage-team/' }}>
- {translate('learn_more')}
- </Link>
- </p>
- );
- };
-
- renderModalBody = () => {
- const { membersSync } = this.state;
- const { hasOtherMembers, organization } = this.props;
- const almKey = organization.alm && sanitizeAlmId(organization.alm.key);
- const showWarning = hasOtherMembers && organization.alm && !organization.alm.membersSync;
- return (
- <div className="display-flex-stretch big-spacer-top">
- <RadioCard
- onClick={this.handleManualClick}
- selected={!membersSync}
- title={translate('organization.members.management.manual')}>
- <div className="spacer-left">
- <ul className="big-spacer-left note">
- <li className="spacer-bottom">
- {translate('organization.members.management.manual.add_members_manually')}
- </li>
- <li>{translate('organization.members.management.choose_members_permissions')}</li>
- </ul>
- </div>
- </RadioCard>
- <RadioCard
- onClick={this.handleAutoClick}
- selected={membersSync}
- title={translateWithParameters(
- 'organization.members.management.automatic',
- translate(almKey || '')
- )}>
- <div className="spacer-left">
- <ul className="big-spacer-left note">
- {almKey && (
- <>
- <li className="spacer-bottom">
- {translateWithParameters(
- 'organization.members.management.automatic.synchronized_from_x',
- translate('organization', almKey)
- )}
- </li>
- <li className="spacer-bottom">
- {translate(
- 'organization.members.management.automatic.members_changes_reflected',
- almKey
- )}
- </li>
- </>
- )}
- <li>{translate('organization.members.management.choose_members_permissions')}</li>
- </ul>
- </div>
- {almKey && showWarning && (
- <Alert className="big-spacer-top" variant="warning">
- {translateWithParameters(
- 'organization.members.management.automatic.warning_x',
- translate('organization', almKey)
- )}
- </Alert>
- )}
- </RadioCard>
- </div>
- );
- };
-
- render() {
- const { organization } = this.props;
- const orgMemberSync = Boolean(organization.alm && organization.alm.membersSync);
- return (
- <ConfirmButton
- cancelButtonText={translate('close')}
- confirmButtonText={translate('save')}
- confirmDisable={this.state.membersSync === orgMemberSync}
- modalBody={this.renderModalBody()}
- modalHeader={translate('organization.members.management.title')}
- modalHeaderDescription={this.renderModalDescription()}
- onConfirm={this.handleConfirm}
- size="medium">
- {({ onClick }) => <Button onClick={onClick}>{this.props.buttonText}</Button>}
- </ConfirmButton>
- );
- }
-}
-
-const mapDispatchToProps = { fetchOrganization };
-
-export default connect(null, mapDispatchToProps)(SyncMemberForm);
diff --git a/server/sonar-web/src/main/js/apps/organizationMembers/__tests__/AddMemberForm-test.tsx b/server/sonar-web/src/main/js/apps/organizationMembers/__tests__/AddMemberForm-test.tsx
deleted file mode 100644
index 1be6c70cd74..00000000000
--- a/server/sonar-web/src/main/js/apps/organizationMembers/__tests__/AddMemberForm-test.tsx
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import { shallow } from 'enzyme';
-import * as React from 'react';
-import { click, submit } from 'sonar-ui-common/helpers/testUtils';
-import { searchMembers } from '../../../api/organizations';
-import AddMemberForm from '../AddMemberForm';
-
-jest.mock('../../../api/organizations', () => ({
- searchMembers: jest.fn().mockResolvedValue({ paging: {}, users: [] })
-}));
-
-const memberLogins = ['admin'];
-
-it('should render and open the modal', () => {
- const wrapper = shallow(
- <AddMemberForm
- addMember={jest.fn()}
- memberLogins={memberLogins}
- organization={{ key: 'foo', name: 'Foo' }}
- />
- );
- expect(wrapper).toMatchSnapshot();
- wrapper.setState({ open: true });
- expect(wrapper).toMatchSnapshot();
-});
-
-it('should correctly handle user interactions', () => {
- const wrapper = shallow(
- <AddMemberForm
- addMember={jest.fn()}
- memberLogins={memberLogins}
- organization={{ key: 'foo', name: 'Foo' }}
- />
- );
- click(wrapper.find('Button'));
- expect(wrapper.state('open')).toBe(true);
- (wrapper.instance() as AddMemberForm).closeForm();
- expect(wrapper.state('open')).toBe(false);
-});
-
-it('should search users', () => {
- const wrapper = shallow(
- <AddMemberForm
- addMember={jest.fn()}
- memberLogins={memberLogins}
- organization={{ key: 'foo', name: 'Foo' }}
- />
- );
- click(wrapper.find('Button'));
-
- wrapper.find('UsersSelectSearch').prop<Function>('searchUsers')('foo', 100);
- expect(searchMembers).lastCalledWith({
- organization: 'foo',
- ps: 100,
- q: 'foo',
- selected: 'deselected'
- });
-
- wrapper.find('UsersSelectSearch').prop<Function>('searchUsers')('', 100);
- expect(searchMembers).lastCalledWith({
- organization: 'foo',
- ps: 100,
- selected: 'deselected'
- });
-});
-
-it('should select user', () => {
- const addMember = jest.fn();
- const user = { login: 'luke', name: 'Luke' };
- const wrapper = shallow(
- <AddMemberForm
- addMember={addMember}
- memberLogins={memberLogins}
- organization={{ key: 'foo', name: 'Foo' }}
- />
- );
- click(wrapper.find('Button'));
-
- wrapper.find('UsersSelectSearch').prop<Function>('handleValueChange')(user);
- submit(wrapper.find('form'));
- expect(addMember).toBeCalledWith(user);
-});
diff --git a/server/sonar-web/src/main/js/apps/organizationMembers/__tests__/ManageMemberGroupsForm-test.tsx b/server/sonar-web/src/main/js/apps/organizationMembers/__tests__/ManageMemberGroupsForm-test.tsx
deleted file mode 100644
index 7ce1733550c..00000000000
--- a/server/sonar-web/src/main/js/apps/organizationMembers/__tests__/ManageMemberGroupsForm-test.tsx
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import { shallow } from 'enzyme';
-import * as React from 'react';
-import ManageMemberGroupsForm from '../ManageMemberGroupsForm';
-
-const member = { login: 'admin', name: 'Admin Istrator', avatar: '', groupCount: 3 };
-const organization = { name: 'MyOrg', key: 'myorg' };
-const organizationGroups = [
- {
- id: 7,
- name: 'professionals',
- description: '',
- membersCount: 12
- },
- {
- id: 11,
- name: 'pull-request-analysers',
- description: 'Technical accounts',
- membersCount: 3
- },
- {
- id: 1,
- name: 'sonar-administrators',
- description: 'System administrators',
- membersCount: 17
- }
-];
-const userGroups = {
- '11': {
- default: false,
- id: 11,
- name: 'pull-request-analysers',
- description: 'Technical accounts',
- selected: true
- }
-};
-
-function getMountedForm(updateFunc = jest.fn().mockResolvedValue({})) {
- const wrapper = shallow<ManageMemberGroupsForm>(
- <ManageMemberGroupsForm
- member={member}
- onClose={jest.fn()}
- organization={organization}
- organizationGroups={organizationGroups}
- updateMemberGroups={updateFunc}
- />,
- { disableLifecycleMethods: true }
- );
- const instance = wrapper.instance();
- wrapper.setState({ loading: false, userGroups });
- return { wrapper, instance };
-}
-
-it('should render', () => {
- const wrapper = shallow(
- <ManageMemberGroupsForm
- member={member}
- onClose={jest.fn()}
- organization={organization}
- organizationGroups={organizationGroups}
- updateMemberGroups={jest.fn()}
- />
- );
- expect(wrapper).toMatchSnapshot();
- expect(wrapper.dive()).toMatchSnapshot();
-});
-
-it('should correctly select the groups', () => {
- const form = getMountedForm();
- expect(form.instance.isGroupSelected('11')).toBe(true);
- expect(form.instance.isGroupSelected('7')).toBe(false);
- form.instance.onCheck('11', false);
- form.instance.onCheck('7', true);
- expect(form.wrapper.state('userGroups')).toMatchSnapshot();
- expect(form.instance.isGroupSelected('11')).toBe(false);
- expect(form.instance.isGroupSelected('7')).toBe(true);
-});
-
-it('should correctly handle the submit event and close the modal', () => {
- const updateMemberGroups = jest.fn().mockResolvedValue({});
- const form = getMountedForm(updateMemberGroups);
- form.instance.onCheck('11', false);
- form.instance.onCheck('7', true);
- form.instance.handleSubmit();
- expect(updateMemberGroups.mock.calls).toMatchSnapshot();
- expect(form.wrapper.state()).toMatchSnapshot();
-});
diff --git a/server/sonar-web/src/main/js/apps/organizationMembers/__tests__/MembersList-test.tsx b/server/sonar-web/src/main/js/apps/organizationMembers/__tests__/MembersList-test.tsx
deleted file mode 100644
index 2522eb75984..00000000000
--- a/server/sonar-web/src/main/js/apps/organizationMembers/__tests__/MembersList-test.tsx
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import { shallow } from 'enzyme';
-import * as React from 'react';
-import { mockLoggedInUser, mockOrganization } from '../../../helpers/testMocks';
-import MembersList from '../MembersList';
-
-const members = [
- { login: 'admin', name: 'Admin Istrator', avatar: '', groupCount: 3 },
- { login: 'john', name: 'John Doe', avatar: '7daf6c79d4802916d83f6266e24850af', groupCount: 1 }
-];
-
-it('should render a list of members of an organization', () => {
- expect(shallowRender()).toMatchSnapshot();
-});
-
-it('should render "no results"', () => {
- expect(shallowRender({ members: [] })).toMatchSnapshot();
-});
-
-function shallowRender(props: Partial<MembersList['props']> = {}) {
- return shallow(
- <MembersList
- currentUser={mockLoggedInUser({ login: 'admin' })}
- members={members}
- organization={mockOrganization()}
- organizationGroups={[]}
- removeMember={jest.fn()}
- updateMemberGroups={jest.fn()}
- {...props}
- />
- );
-}
diff --git a/server/sonar-web/src/main/js/apps/organizationMembers/__tests__/MembersListHeader-test.tsx b/server/sonar-web/src/main/js/apps/organizationMembers/__tests__/MembersListHeader-test.tsx
deleted file mode 100644
index 0acad9c271e..00000000000
--- a/server/sonar-web/src/main/js/apps/organizationMembers/__tests__/MembersListHeader-test.tsx
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import { shallow } from 'enzyme';
-import * as React from 'react';
-import { mockOrganization, mockOrganizationWithAlm } from '../../../helpers/testMocks';
-import MembersListHeader, { Props } from '../MembersListHeader';
-
-it('should render without the total', () => {
- expect(shallowRender({ total: undefined })).toMatchSnapshot();
-});
-
-it('should render with the total', () => {
- expect(shallowRender()).toMatchSnapshot();
-});
-
-it('should render a help tooltip', () => {
- expect(
- shallowRender({ organization: mockOrganizationWithAlm({}, { membersSync: true }) }).find(
- 'HelpTooltip'
- )
- ).toMatchSnapshot();
- expect(
- shallowRender({
- organization: mockOrganizationWithAlm(
- {},
- { key: 'bitbucket', membersSync: true, url: 'https://bitbucket.com/foo' }
- )
- }).find('HelpTooltip')
- ).toMatchSnapshot();
-});
-
-function shallowRender(props: Partial<Props> = {}) {
- return shallow(
- <MembersListHeader
- handleSearch={jest.fn()}
- organization={mockOrganization()}
- total={8}
- {...props}
- />
- );
-}
diff --git a/server/sonar-web/src/main/js/apps/organizationMembers/__tests__/MembersListItem-test.tsx b/server/sonar-web/src/main/js/apps/organizationMembers/__tests__/MembersListItem-test.tsx
deleted file mode 100644
index bfa51e2c95b..00000000000
--- a/server/sonar-web/src/main/js/apps/organizationMembers/__tests__/MembersListItem-test.tsx
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import { shallow } from 'enzyme';
-import * as React from 'react';
-import { click } from 'sonar-ui-common/helpers/testUtils';
-import { mockOrganization, mockOrganizationWithAdminActions } from '../../../helpers/testMocks';
-import MembersListItem from '../MembersListItem';
-
-it('should not render actions and groups for non admin', () => {
- expect(shallowRender({ organization: mockOrganization() })).toMatchSnapshot();
-});
-
-it('should render actions and groups for admin', () => {
- expect(shallowRender()).toMatchSnapshot();
-});
-
-it('should show groups at 0 if the groupCount field is not defined (just added user)', () => {
- expect(
- shallowRender({
- member: { login: 'john', name: 'John Doe', avatar: '7daf6c79d4802916d83f6266e24850af' }
- })
- ).toMatchSnapshot();
-});
-
-it('should not display the remove member action', () => {
- expect(shallowRender({ removeMember: undefined }).find('ActionsDropdown')).toMatchSnapshot();
-});
-
-it('should open groups form', () => {
- const wrapper = shallowRender();
-
- click(wrapper.find('ActionsDropdownItem').first());
- expect(wrapper.find('ManageMemberGroupsForm').exists()).toBe(true);
-
- wrapper.find('ManageMemberGroupsForm').prop<Function>('onClose')();
- wrapper.update();
- expect(wrapper.find('ManageMemberGroupsForm').exists()).toBe(false);
-});
-
-it('should open remove member form', () => {
- const wrapper = shallowRender();
-
- click(wrapper.find('ActionsDropdownItem').last());
- expect(wrapper.find('RemoveMemberForm').exists()).toBe(true);
-
- wrapper.find('RemoveMemberForm').prop<Function>('onClose')();
- wrapper.update();
- expect(wrapper.find('RemoveMemberForm').exists()).toBe(false);
-});
-
-function shallowRender(props: Partial<MembersListItem['props']> = {}) {
- return shallow(
- <MembersListItem
- member={{ login: 'admin', name: 'Admin Istrator', avatar: '', groupCount: 3 }}
- organization={mockOrganizationWithAdminActions()}
- organizationGroups={[]}
- removeMember={jest.fn()}
- updateMemberGroups={jest.fn()}
- {...props}
- />
- );
-}
diff --git a/server/sonar-web/src/main/js/apps/organizationMembers/__tests__/MembersPageHeader-test.tsx b/server/sonar-web/src/main/js/apps/organizationMembers/__tests__/MembersPageHeader-test.tsx
deleted file mode 100644
index 4b72e23ee82..00000000000
--- a/server/sonar-web/src/main/js/apps/organizationMembers/__tests__/MembersPageHeader-test.tsx
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import { shallow } from 'enzyme';
-import * as React from 'react';
-import {
- mockOrganization,
- mockOrganizationWithAdminActions,
- mockOrganizationWithAlm
-} from '../../../helpers/testMocks';
-import MembersPageHeader, { Props } from '../MembersPageHeader';
-
-it('should render correctly', () => {
- expect(shallowRender({ loading: true })).toMatchSnapshot();
-});
-
-it('should render for admin', () => {
- expect(
- shallowRender({ organization: mockOrganization({ actions: { admin: true } }) })
- ).toMatchSnapshot();
-});
-
-it('should render for Bitbucket bound organization', () => {
- const organization = mockOrganizationWithAlm(mockOrganizationWithAdminActions(), {
- key: 'bitbucket'
- });
- expect(shallowRender({ organization })).toMatchSnapshot();
-});
-
-it('should render for GitHub bound organization without sync', () => {
- const organization = mockOrganizationWithAlm(mockOrganizationWithAdminActions());
- expect(shallowRender({ organization })).toMatchSnapshot();
-});
-
-it('should render for personal GitHub bound organization without sync', () => {
- const organization = mockOrganizationWithAlm(mockOrganizationWithAdminActions(), {
- personal: true
- });
- expect(shallowRender({ organization })).toMatchSnapshot();
-});
-
-it('should render for bound organization with sync', () => {
- const organization = mockOrganizationWithAlm(mockOrganizationWithAdminActions(), {
- membersSync: true
- });
- const wrapper = shallowRender({ organization });
- expect(wrapper.find('Connect(SyncMemberForm)').exists()).toBe(true);
- expect(wrapper.find('AddMemberForm').exists()).toBe(false);
- expect(wrapper.find('Alert').exists()).toBe(false);
-});
-
-function shallowRender(props: Partial<Props> = {}) {
- return shallow(
- <MembersPageHeader
- handleAddMember={jest.fn()}
- loading={false}
- members={[]}
- organization={mockOrganization()}
- refreshMembers={jest.fn()}
- {...props}
- />
- );
-}
diff --git a/server/sonar-web/src/main/js/apps/organizationMembers/__tests__/OrganizationMembers-test.tsx b/server/sonar-web/src/main/js/apps/organizationMembers/__tests__/OrganizationMembers-test.tsx
deleted file mode 100644
index 3865e9727be..00000000000
--- a/server/sonar-web/src/main/js/apps/organizationMembers/__tests__/OrganizationMembers-test.tsx
+++ /dev/null
@@ -1,180 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import { shallow } from 'enzyme';
-import * as React from 'react';
-import { waitAndUpdate } from 'sonar-ui-common/helpers/testUtils';
-import { addMember, removeMember, searchMembers } from '../../../api/organizations';
-import { addUserToGroup, removeUserFromGroup, searchUsersGroups } from '../../../api/user_groups';
-import {
- mockLoggedInUser,
- mockOrganization,
- mockOrganizationWithAdminActions,
- mockOrganizationWithAlm
-} from '../../../helpers/testMocks';
-import OrganizationMembers from '../OrganizationMembers';
-
-jest.mock('../../../api/organizations', () => ({
- addMember: jest.fn().mockResolvedValue({ login: 'bar', name: 'Bar', groupCount: 1 }),
- removeMember: jest.fn().mockResolvedValue(undefined),
- searchMembers: jest.fn().mockResolvedValue({
- paging: { pageIndex: 1, pageSize: 2, total: 3 },
- users: [
- { login: 'admin', name: 'Admin Istrator', avatar: '', groupCount: 3 },
- { login: 'john', name: 'John Doe', avatar: '7daf6c79d4802916d83f6266e24850af', groupCount: 1 }
- ]
- })
-}));
-
-jest.mock('../../../api/user_groups', () => ({
- addUserToGroup: jest.fn().mockResolvedValue(undefined),
- removeUserFromGroup: jest.fn().mockResolvedValue(undefined),
- searchUsersGroups: jest.fn().mockResolvedValue({
- paging: { pageIndex: 1, pageSize: 100, total: 2 },
- groups: [
- { id: 1, name: 'Members', description: '', membersCount: 2, default: true },
- { id: 2, name: 'Watchers', description: '', membersCount: 0, default: false }
- ]
- })
-}));
-
-beforeEach(() => {
- jest.clearAllMocks();
-});
-
-it('should fetch members and render for non-admin', async () => {
- const wrapper = shallowRender({ organization: mockOrganization() });
- expect(wrapper).toMatchSnapshot();
-
- await waitAndUpdate(wrapper);
- expect(wrapper).toMatchSnapshot();
- expect(searchMembers).toBeCalledWith({ organization: 'foo', ps: 50, q: undefined });
-});
-
-it('should fetch members and groups for admin', async () => {
- const wrapper = shallowRender();
- await waitAndUpdate(wrapper);
- expect(searchMembers).toBeCalledWith({ organization: 'foo', ps: 50, q: undefined });
- expect(searchUsersGroups).toBeCalledWith({ organization: 'foo' });
-});
-
-it('should search users', async () => {
- const wrapper = shallowRender();
- await waitAndUpdate(wrapper);
- wrapper.find('MembersListHeader').prop<Function>('handleSearch')('user');
- expect(searchMembers).lastCalledWith({ organization: 'foo', ps: 50, q: 'user' });
-});
-
-it('should load more members', async () => {
- const wrapper = shallowRender();
- await waitAndUpdate(wrapper);
- wrapper.find('ListFooter').prop<Function>('loadMore')();
- expect(searchMembers).lastCalledWith({ organization: 'foo', p: 2, ps: 50, q: undefined });
-});
-
-it('should refresh members', async () => {
- const paging = { pageIndex: 1, pageSize: 5, total: 3 };
- const users = [
- { login: 'admin', name: 'Admin Istrator', avatar: '', groupCount: 3 },
- { login: 'john', name: 'John Doe', avatar: '7daf6c79d4802916d83f6266e24850af', groupCount: 1 },
- { login: 'stan', name: 'Stan Marsh', avatar: '', groupCount: 7 }
- ];
-
- const wrapper = shallowRender();
- await waitAndUpdate(wrapper);
-
- (searchMembers as jest.Mock).mockResolvedValueOnce({
- paging,
- users
- });
-
- await wrapper.instance().refreshMembers();
- expect(searchMembers).toBeCalled();
- expect(wrapper.state('members')).toEqual(users);
- expect(wrapper.state('paging')).toEqual(paging);
-});
-
-it('should add new member', async () => {
- const wrapper = shallowRender();
- await waitAndUpdate(wrapper);
- wrapper.find('MembersPageHeader').prop<Function>('handleAddMember')({ login: 'bar' });
- await waitAndUpdate(wrapper);
- expect(
- wrapper
- .find('MembersList')
- .prop<T.OrganizationMember[]>('members')
- .find(m => m.login === 'bar')
- ).toBeDefined();
- expect(wrapper.find('ListFooter').prop('total')).toEqual(4);
- expect(addMember).toBeCalledWith({ login: 'bar', organization: 'foo' });
-});
-
-it('should remove member', async () => {
- const wrapper = shallowRender();
- await waitAndUpdate(wrapper);
- wrapper.find('MembersList').prop<Function>('removeMember')({ login: 'john' });
- await waitAndUpdate(wrapper);
- expect(
- wrapper
- .find('MembersList')
- .prop<T.OrganizationMember[]>('members')
- .find(m => m.login === 'john')
- ).toBeUndefined();
- expect(wrapper.find('ListFooter').prop('total')).toEqual(2);
- expect(removeMember).toBeCalledWith({ login: 'john', organization: 'foo' });
-});
-
-it('should update groups', async () => {
- const wrapper = shallowRender();
- await waitAndUpdate(wrapper);
- wrapper.find('MembersList').prop<Function>('updateMemberGroups')(
- { login: 'john' },
- ['cats', 'dogs'], // add to
- ['birds'] // remove from
- );
- await waitAndUpdate(wrapper);
- const john = wrapper
- .find('MembersList')
- .prop<T.OrganizationMember[]>('members')
- .find(m => m.login === 'john');
- expect(john && john.groupCount).toBe(2);
- expect(addUserToGroup).toHaveBeenCalledTimes(2);
- expect(addUserToGroup).toBeCalledWith({ login: 'john', name: 'cats', organization: 'foo' });
- expect(addUserToGroup).toBeCalledWith({ login: 'john', name: 'dogs', organization: 'foo' });
- expect(removeUserFromGroup).toHaveBeenCalledTimes(1);
- expect(removeUserFromGroup).toBeCalledWith({ login: 'john', name: 'birds', organization: 'foo' });
-});
-
-it('should not allow to remove members when in sync mode', async () => {
- const wrapper = shallowRender({
- organization: mockOrganizationWithAlm(mockOrganizationWithAdminActions(), { membersSync: true })
- });
- await waitAndUpdate(wrapper);
- expect(wrapper.find('MembersList').prop('removeMember')).toBeUndefined();
-});
-
-function shallowRender(props: Partial<OrganizationMembers['props']> = {}) {
- return shallow<OrganizationMembers>(
- <OrganizationMembers
- currentUser={mockLoggedInUser()}
- organization={mockOrganizationWithAdminActions()}
- {...props}
- />
- );
-}
diff --git a/server/sonar-web/src/main/js/apps/organizationMembers/__tests__/RemoveMemberForm-test.tsx b/server/sonar-web/src/main/js/apps/organizationMembers/__tests__/RemoveMemberForm-test.tsx
deleted file mode 100644
index 657b6797190..00000000000
--- a/server/sonar-web/src/main/js/apps/organizationMembers/__tests__/RemoveMemberForm-test.tsx
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import { shallow } from 'enzyme';
-import * as React from 'react';
-import { mockEvent } from '../../../helpers/testMocks';
-import RemoveMemberForm from '../RemoveMemberForm';
-
-const member = { login: 'admin', name: 'Admin Istrator', avatar: '', groupCount: 3 };
-const organization = { key: 'myorg', name: 'MyOrg' };
-
-it('should render', () => {
- const wrapper = shallow(
- <RemoveMemberForm
- member={member}
- onClose={jest.fn()}
- organization={organization}
- removeMember={jest.fn()}
- />
- );
- expect(wrapper).toMatchSnapshot();
-});
-
-it('should correctly handle user interactions', () => {
- const removeMember = jest.fn();
- const wrapper = shallow<RemoveMemberForm>(
- <RemoveMemberForm
- member={member}
- onClose={jest.fn()}
- organization={organization}
- removeMember={removeMember}
- />
- );
- wrapper.instance().handleSubmit(mockEvent());
- expect(removeMember).toBeCalledWith({
- avatar: '',
- groupCount: 3,
- login: 'admin',
- name: 'Admin Istrator'
- });
-});
diff --git a/server/sonar-web/src/main/js/apps/organizationMembers/__tests__/SyncMemberForm-test.tsx b/server/sonar-web/src/main/js/apps/organizationMembers/__tests__/SyncMemberForm-test.tsx
deleted file mode 100644
index e7e8f814b1b..00000000000
--- a/server/sonar-web/src/main/js/apps/organizationMembers/__tests__/SyncMemberForm-test.tsx
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import { shallow } from 'enzyme';
-import * as React from 'react';
-import { waitAndUpdate } from 'sonar-ui-common/helpers/testUtils';
-import { setOrganizationMemberSync, syncMembers } from '../../../api/organizations';
-import { mockOrganizationWithAlm } from '../../../helpers/testMocks';
-import { SyncMemberForm } from '../SyncMemberForm';
-
-jest.mock('../../../api/organizations', () => ({
- setOrganizationMemberSync: jest.fn().mockResolvedValue(undefined),
- syncMembers: jest.fn().mockResolvedValue(undefined)
-}));
-
-beforeEach(() => {
- jest.clearAllMocks();
-});
-
-it('should allow to switch to automatic mode', async () => {
- const fetchOrganization = jest.fn();
- const refreshMembers = jest.fn().mockResolvedValue({});
- const wrapper = shallowRender({ fetchOrganization, refreshMembers });
- expect(wrapper).toMatchSnapshot();
-
- wrapper.setState({ membersSync: true });
- wrapper.find('ConfirmButton').prop<Function>('onConfirm')();
- expect(setOrganizationMemberSync).toHaveBeenCalledWith({ organization: 'foo', enabled: true });
-
- await waitAndUpdate(wrapper);
- expect(fetchOrganization).toHaveBeenCalledWith('foo');
- expect(syncMembers).toHaveBeenCalledWith('foo');
- expect(refreshMembers).toBeCalled();
-});
-
-it('should allow to switch to manual mode', async () => {
- const fetchOrganization = jest.fn();
- const wrapper = shallowRender({
- fetchOrganization,
- organization: mockOrganizationWithAlm({}, { membersSync: true })
- });
- expect(wrapper).toMatchSnapshot();
-
- wrapper.setState({ membersSync: false });
- wrapper.find('ConfirmButton').prop<Function>('onConfirm')();
- expect(setOrganizationMemberSync).toHaveBeenCalledWith({ organization: 'foo', enabled: false });
-
- await waitAndUpdate(wrapper);
- expect(fetchOrganization).toHaveBeenCalledWith('foo');
- expect(syncMembers).not.toHaveBeenCalled();
-});
-
-function shallowRender(props: Partial<SyncMemberForm['props']> = {}) {
- return shallow<SyncMemberForm>(
- <SyncMemberForm
- buttonText="configure"
- fetchOrganization={jest.fn()}
- hasOtherMembers={true}
- organization={mockOrganizationWithAlm()}
- refreshMembers={jest.fn().mockResolvedValue({})}
- {...props}
- />
- );
-}
diff --git a/server/sonar-web/src/main/js/apps/organizationMembers/__tests__/__snapshots__/AddMemberForm-test.tsx.snap b/server/sonar-web/src/main/js/apps/organizationMembers/__tests__/__snapshots__/AddMemberForm-test.tsx.snap
deleted file mode 100644
index 5eafb110cf2..00000000000
--- a/server/sonar-web/src/main/js/apps/organizationMembers/__tests__/__snapshots__/AddMemberForm-test.tsx.snap
+++ /dev/null
@@ -1,77 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render and open the modal 1`] = `
-<Fragment>
- <Button
- key="add-member-button"
- onClick={[Function]}
- >
- organization.members.add
- </Button>
-</Fragment>
-`;
-
-exports[`should render and open the modal 2`] = `
-<Fragment>
- <Button
- key="add-member-button"
- onClick={[Function]}
- >
- organization.members.add
- </Button>
- <Modal
- contentLabel="users.add"
- key="add-member-modal"
- onRequestClose={[Function]}
- >
- <header
- className="modal-head"
- >
- <h2>
- users.add
- </h2>
- </header>
- <form
- onSubmit={[Function]}
- >
- <div
- className="modal-body"
- >
- <div
- className="modal-field"
- >
- <label>
- users.search_description
- </label>
- <UsersSelectSearch
- autoFocus={true}
- excludedUsers={
- Array [
- "admin",
- ]
- }
- handleValueChange={[Function]}
- searchUsers={[Function]}
- />
- </div>
- </div>
- <footer
- className="modal-foot"
- >
- <div>
- <SubmitButton
- disabled={true}
- >
- organization.members.add_to_members
- </SubmitButton>
- <ResetButtonLink
- onClick={[Function]}
- >
- cancel
- </ResetButtonLink>
- </div>
- </footer>
- </form>
- </Modal>
-</Fragment>
-`;
diff --git a/server/sonar-web/src/main/js/apps/organizationMembers/__tests__/__snapshots__/ManageMemberGroupsForm-test.tsx.snap b/server/sonar-web/src/main/js/apps/organizationMembers/__tests__/__snapshots__/ManageMemberGroupsForm-test.tsx.snap
deleted file mode 100644
index d83c2bbd6f9..00000000000
--- a/server/sonar-web/src/main/js/apps/organizationMembers/__tests__/__snapshots__/ManageMemberGroupsForm-test.tsx.snap
+++ /dev/null
@@ -1,115 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should correctly handle the submit event and close the modal 1`] = `
-Array [
- Array [
- Object {
- "avatar": "",
- "groupCount": 3,
- "login": "admin",
- "name": "Admin Istrator",
- },
- Array [
- "7",
- ],
- Array [
- "11",
- ],
- ],
-]
-`;
-
-exports[`should correctly handle the submit event and close the modal 2`] = `
-Object {
- "loading": false,
- "userGroups": Object {
- "11": Object {
- "default": false,
- "description": "Technical accounts",
- "id": 11,
- "name": "pull-request-analysers",
- "selected": true,
- "status": "remove",
- },
- "7": Object {
- "status": "add",
- },
- },
-}
-`;
-
-exports[`should correctly select the groups 1`] = `
-Object {
- "11": Object {
- "default": false,
- "description": "Technical accounts",
- "id": 11,
- "name": "pull-request-analysers",
- "selected": true,
- "status": "remove",
- },
- "7": Object {
- "status": "add",
- },
-}
-`;
-
-exports[`should render 1`] = `
-<SimpleModal
- header="organization.members.manage_groups"
- onClose={[MockFunction]}
- onSubmit={[Function]}
->
- <Component />
-</SimpleModal>
-`;
-
-exports[`should render 2`] = `
-<Modal
- contentLabel="organization.members.manage_groups"
- onRequestClose={[MockFunction]}
->
- <form
- onSubmit={[Function]}
- >
- <header
- className="modal-head"
- >
- <h2>
- organization.members.manage_groups
- </h2>
- </header>
- <div
- className="modal-body modal-container"
- >
- <p>
- <strong>
- organization.members.members_groups.Admin Istrator
- </strong>
- </p>
- <DeferredSpinner
- className="spacer-top"
- />
- </div>
- <footer
- className="modal-foot"
- >
- <DeferredSpinner
- className="spacer-right"
- loading={false}
- />
- <SubmitButton
- disabled={true}
- >
- save
- </SubmitButton>
- <ResetButtonLink
- disabled={false}
- onClick={[Function]}
- >
- cancel
- </ResetButtonLink>
- </footer>
- </form>
-</Modal>
-`;
diff --git a/server/sonar-web/src/main/js/apps/organizationMembers/__tests__/__snapshots__/MembersList-test.tsx.snap b/server/sonar-web/src/main/js/apps/organizationMembers/__tests__/__snapshots__/MembersList-test.tsx.snap
deleted file mode 100644
index a99cabd208d..00000000000
--- a/server/sonar-web/src/main/js/apps/organizationMembers/__tests__/__snapshots__/MembersList-test.tsx.snap
+++ /dev/null
@@ -1,61 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render "no results" 1`] = `
-<div
- className="note"
->
- no_results
-</div>
-`;
-
-exports[`should render a list of members of an organization 1`] = `
-<div
- className="boxed-group boxed-group-inner"
->
- <table
- className="data zebra"
- >
- <tbody>
- <MembersListItem
- key="admin"
- member={
- Object {
- "avatar": "",
- "groupCount": 3,
- "login": "admin",
- "name": "Admin Istrator",
- }
- }
- organization={
- Object {
- "key": "foo",
- "name": "Foo",
- }
- }
- organizationGroups={Array []}
- updateMemberGroups={[MockFunction]}
- />
- <MembersListItem
- key="john"
- member={
- Object {
- "avatar": "7daf6c79d4802916d83f6266e24850af",
- "groupCount": 1,
- "login": "john",
- "name": "John Doe",
- }
- }
- organization={
- Object {
- "key": "foo",
- "name": "Foo",
- }
- }
- organizationGroups={Array []}
- removeMember={[MockFunction]}
- updateMemberGroups={[MockFunction]}
- />
- </tbody>
- </table>
-</div>
-`;
diff --git a/server/sonar-web/src/main/js/apps/organizationMembers/__tests__/__snapshots__/MembersListHeader-test.tsx.snap b/server/sonar-web/src/main/js/apps/organizationMembers/__tests__/__snapshots__/MembersListHeader-test.tsx.snap
deleted file mode 100644
index 713c2e01c14..00000000000
--- a/server/sonar-web/src/main/js/apps/organizationMembers/__tests__/__snapshots__/MembersListHeader-test.tsx.snap
+++ /dev/null
@@ -1,84 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render a help tooltip 1`] = `
-<HelpTooltip
- className="spacer-left"
- overlay={
- <div
- className="abs-width-300 markdown cut-margins"
- >
- <p>
- organization.members.auto_sync_total_help.github
- </p>
- <hr />
- <p>
- <a
- href="https://github.com/orgs/foo/people"
- rel="noopener noreferrer"
- target="_blank"
- >
- organization.members.see_all_members_on_x.github
- </a>
- </p>
- </div>
- }
-/>
-`;
-
-exports[`should render a help tooltip 2`] = `
-<HelpTooltip
- className="spacer-left"
- overlay={
- <div
- className="abs-width-300 markdown cut-margins"
- >
- <p>
- organization.members.auto_sync_total_help.bitbucket
- </p>
- <hr />
- <p>
- <a
- href="https://bitbucket.com/foo/profile/members"
- rel="noopener noreferrer"
- target="_blank"
- >
- organization.members.see_all_members_on_x.bitbucket
- </a>
- </p>
- </div>
- }
-/>
-`;
-
-exports[`should render with the total 1`] = `
-<div
- className="panel panel-vertical bordered-bottom spacer-bottom"
->
- <SearchBox
- minLength={2}
- onChange={[MockFunction]}
- placeholder="search.search_for_members"
- />
- <span
- className="pull-right little-spacer-top"
- >
- <strong>
- 8
- </strong>
-
- organization.members.members
- </span>
-</div>
-`;
-
-exports[`should render without the total 1`] = `
-<div
- className="panel panel-vertical bordered-bottom spacer-bottom"
->
- <SearchBox
- minLength={2}
- onChange={[MockFunction]}
- placeholder="search.search_for_members"
- />
-</div>
-`;
diff --git a/server/sonar-web/src/main/js/apps/organizationMembers/__tests__/__snapshots__/MembersListItem-test.tsx.snap b/server/sonar-web/src/main/js/apps/organizationMembers/__tests__/__snapshots__/MembersListItem-test.tsx.snap
deleted file mode 100644
index 414c9f4f30e..00000000000
--- a/server/sonar-web/src/main/js/apps/organizationMembers/__tests__/__snapshots__/MembersListItem-test.tsx.snap
+++ /dev/null
@@ -1,135 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should not display the remove member action 1`] = `
-<ActionsDropdown>
- <ActionsDropdownItem
- onClick={[Function]}
- >
- organization.members.manage_groups
- </ActionsDropdownItem>
-</ActionsDropdown>
-`;
-
-exports[`should not render actions and groups for non admin 1`] = `
-<tr>
- <td
- className="thin nowrap"
- >
- <Connect(Avatar)
- hash=""
- name="Admin Istrator"
- size={36}
- />
- </td>
- <td
- className="nowrap text-middle"
- >
- <strong>
- Admin Istrator
- </strong>
- <span
- className="note little-spacer-left"
- >
- admin
- </span>
- </td>
-</tr>
-`;
-
-exports[`should render actions and groups for admin 1`] = `
-<tr>
- <td
- className="thin nowrap"
- >
- <Connect(Avatar)
- hash=""
- name="Admin Istrator"
- size={36}
- />
- </td>
- <td
- className="nowrap text-middle"
- >
- <strong>
- Admin Istrator
- </strong>
- <span
- className="note little-spacer-left"
- >
- admin
- </span>
- </td>
- <td
- className="text-right text-middle"
- >
- organization.members.x_groups.3
- </td>
- <td
- className="nowrap text-middle text-right"
- >
- <ActionsDropdown>
- <ActionsDropdownItem
- onClick={[Function]}
- >
- organization.members.manage_groups
- </ActionsDropdownItem>
- <ActionsDropdownDivider />
- <ActionsDropdownItem
- destructive={true}
- onClick={[Function]}
- >
- organization.members.remove
- </ActionsDropdownItem>
- </ActionsDropdown>
- </td>
-</tr>
-`;
-
-exports[`should show groups at 0 if the groupCount field is not defined (just added user) 1`] = `
-<tr>
- <td
- className="thin nowrap"
- >
- <Connect(Avatar)
- hash="7daf6c79d4802916d83f6266e24850af"
- name="John Doe"
- size={36}
- />
- </td>
- <td
- className="nowrap text-middle"
- >
- <strong>
- John Doe
- </strong>
- <span
- className="note little-spacer-left"
- >
- john
- </span>
- </td>
- <td
- className="text-right text-middle"
- >
- organization.members.x_groups.0
- </td>
- <td
- className="nowrap text-middle text-right"
- >
- <ActionsDropdown>
- <ActionsDropdownItem
- onClick={[Function]}
- >
- organization.members.manage_groups
- </ActionsDropdownItem>
- <ActionsDropdownDivider />
- <ActionsDropdownItem
- destructive={true}
- onClick={[Function]}
- >
- organization.members.remove
- </ActionsDropdownItem>
- </ActionsDropdown>
- </td>
-</tr>
-`;
diff --git a/server/sonar-web/src/main/js/apps/organizationMembers/__tests__/__snapshots__/MembersPageHeader-test.tsx.snap b/server/sonar-web/src/main/js/apps/organizationMembers/__tests__/__snapshots__/MembersPageHeader-test.tsx.snap
deleted file mode 100644
index 1430d03089e..00000000000
--- a/server/sonar-web/src/main/js/apps/organizationMembers/__tests__/__snapshots__/MembersPageHeader-test.tsx.snap
+++ /dev/null
@@ -1,330 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render correctly 1`] = `
-<header
- className="page-header"
->
- <h1
- className="page-title"
- >
- organization.members.page
- <DeferredSpinner
- className="little-spacer-left"
- loading={true}
- />
- </h1>
- <div
- className="page-description"
- >
- <FormattedMessage
- defaultMessage="organization.members.page.description"
- id="organization.members.page.description"
- values={
- Object {
- "link": <Link
- onlyActiveOnIndex={false}
- style={Object {}}
- target="_blank"
- to="/documentation/organizations/manage-team/"
- >
- organization.members.manage_a_team
- </Link>,
- }
- }
- />
- </div>
-</header>
-`;
-
-exports[`should render for Bitbucket bound organization 1`] = `
-<header
- className="page-header"
->
- <h1
- className="page-title"
- >
- organization.members.page
- <DeferredSpinner
- className="little-spacer-left"
- loading={false}
- />
- </h1>
- <div
- className="page-actions text-right"
- >
- <div
- className="display-inline-block spacer-left spacer-bottom"
- >
- <AddMemberForm
- addMember={[MockFunction]}
- memberLogins={Array []}
- organization={
- Object {
- "actions": Object {
- "admin": true,
- },
- "alm": Object {
- "key": "bitbucket",
- "membersSync": false,
- "personal": false,
- "url": "https://github.com/foo",
- },
- "key": "foo",
- "name": "Foo",
- }
- }
- />
- <DocTooltip
- className="spacer-left"
- doc={Promise {}}
- />
- </div>
- </div>
- <div
- className="page-description"
- >
- <FormattedMessage
- defaultMessage="organization.members.page.description"
- id="organization.members.page.description"
- values={
- Object {
- "link": <Link
- onlyActiveOnIndex={false}
- style={Object {}}
- target="_blank"
- to="/documentation/organizations/manage-team/"
- >
- organization.members.manage_a_team
- </Link>,
- }
- }
- />
- </div>
-</header>
-`;
-
-exports[`should render for GitHub bound organization without sync 1`] = `
-<header
- className="page-header"
->
- <h1
- className="page-title"
- >
- organization.members.page
- <DeferredSpinner
- className="little-spacer-left"
- loading={false}
- />
- </h1>
- <div
- className="page-actions text-right"
- >
- <div
- className="display-inline-block spacer-left spacer-bottom"
- >
- <AddMemberForm
- addMember={[MockFunction]}
- memberLogins={Array []}
- organization={
- Object {
- "actions": Object {
- "admin": true,
- },
- "alm": Object {
- "key": "github",
- "membersSync": false,
- "personal": false,
- "url": "https://github.com/foo",
- },
- "key": "foo",
- "name": "Foo",
- }
- }
- />
- <DocTooltip
- className="spacer-left"
- doc={Promise {}}
- />
- </div>
- </div>
- <div
- className="page-description"
- >
- <FormattedMessage
- defaultMessage="organization.members.page.description"
- id="organization.members.page.description"
- values={
- Object {
- "link": <Link
- onlyActiveOnIndex={false}
- style={Object {}}
- target="_blank"
- to="/documentation/organizations/manage-team/"
- >
- organization.members.manage_a_team
- </Link>,
- }
- }
- />
- <Alert
- className="spacer-top"
- display="inline"
- variant="info"
- >
- organization.members.auto_sync_members_from_org_x.organization.github
- <span
- className="spacer-left"
- >
- <Connect(SyncMemberForm)
- buttonText="configure"
- hasOtherMembers={false}
- organization={
- Object {
- "actions": Object {
- "admin": true,
- },
- "alm": Object {
- "key": "github",
- "membersSync": false,
- "personal": false,
- "url": "https://github.com/foo",
- },
- "key": "foo",
- "name": "Foo",
- }
- }
- refreshMembers={[MockFunction]}
- />
- </span>
- </Alert>
- </div>
-</header>
-`;
-
-exports[`should render for admin 1`] = `
-<header
- className="page-header"
->
- <h1
- className="page-title"
- >
- organization.members.page
- <DeferredSpinner
- className="little-spacer-left"
- loading={false}
- />
- </h1>
- <div
- className="page-actions text-right"
- >
- <div
- className="display-inline-block spacer-left spacer-bottom"
- >
- <AddMemberForm
- addMember={[MockFunction]}
- memberLogins={Array []}
- organization={
- Object {
- "actions": Object {
- "admin": true,
- },
- "key": "foo",
- "name": "Foo",
- }
- }
- />
- <DocTooltip
- className="spacer-left"
- doc={Promise {}}
- />
- </div>
- </div>
- <div
- className="page-description"
- >
- <FormattedMessage
- defaultMessage="organization.members.page.description"
- id="organization.members.page.description"
- values={
- Object {
- "link": <Link
- onlyActiveOnIndex={false}
- style={Object {}}
- target="_blank"
- to="/documentation/organizations/manage-team/"
- >
- organization.members.manage_a_team
- </Link>,
- }
- }
- />
- </div>
-</header>
-`;
-
-exports[`should render for personal GitHub bound organization without sync 1`] = `
-<header
- className="page-header"
->
- <h1
- className="page-title"
- >
- organization.members.page
- <DeferredSpinner
- className="little-spacer-left"
- loading={false}
- />
- </h1>
- <div
- className="page-actions text-right"
- >
- <div
- className="display-inline-block spacer-left spacer-bottom"
- >
- <AddMemberForm
- addMember={[MockFunction]}
- memberLogins={Array []}
- organization={
- Object {
- "actions": Object {
- "admin": true,
- },
- "alm": Object {
- "key": "github",
- "membersSync": false,
- "personal": true,
- "url": "https://github.com/foo",
- },
- "key": "foo",
- "name": "Foo",
- }
- }
- />
- <DocTooltip
- className="spacer-left"
- doc={Promise {}}
- />
- </div>
- </div>
- <div
- className="page-description"
- >
- <FormattedMessage
- defaultMessage="organization.members.page.description"
- id="organization.members.page.description"
- values={
- Object {
- "link": <Link
- onlyActiveOnIndex={false}
- style={Object {}}
- target="_blank"
- to="/documentation/organizations/manage-team/"
- >
- organization.members.manage_a_team
- </Link>,
- }
- }
- />
- </div>
-</header>
-`;
diff --git a/server/sonar-web/src/main/js/apps/organizationMembers/__tests__/__snapshots__/OrganizationMembers-test.tsx.snap b/server/sonar-web/src/main/js/apps/organizationMembers/__tests__/__snapshots__/OrganizationMembers-test.tsx.snap
deleted file mode 100644
index 23fbb81a067..00000000000
--- a/server/sonar-web/src/main/js/apps/organizationMembers/__tests__/__snapshots__/OrganizationMembers-test.tsx.snap
+++ /dev/null
@@ -1,127 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should fetch members and render for non-admin 1`] = `
-<div
- className="page page-limited"
->
- <Helmet
- defer={false}
- encodeSpecialCharacters={true}
- title="organization.members.page"
- />
- <Suggestions
- suggestions="organization_members"
- />
- <A11ySkipTarget
- anchor="members_main"
- />
- <MembersPageHeader
- handleAddMember={[Function]}
- loading={true}
- organization={
- Object {
- "key": "foo",
- "name": "Foo",
- }
- }
- refreshMembers={[Function]}
- />
-</div>
-`;
-
-exports[`should fetch members and render for non-admin 2`] = `
-<div
- className="page page-limited"
->
- <Helmet
- defer={false}
- encodeSpecialCharacters={true}
- title="organization.members.page"
- />
- <Suggestions
- suggestions="organization_members"
- />
- <A11ySkipTarget
- anchor="members_main"
- />
- <MembersPageHeader
- handleAddMember={[Function]}
- loading={false}
- members={
- Array [
- Object {
- "avatar": "",
- "groupCount": 3,
- "login": "admin",
- "name": "Admin Istrator",
- },
- Object {
- "avatar": "7daf6c79d4802916d83f6266e24850af",
- "groupCount": 1,
- "login": "john",
- "name": "John Doe",
- },
- ]
- }
- organization={
- Object {
- "key": "foo",
- "name": "Foo",
- }
- }
- refreshMembers={[Function]}
- />
- <MembersListHeader
- handleSearch={[Function]}
- organization={
- Object {
- "key": "foo",
- "name": "Foo",
- }
- }
- total={3}
- />
- <MembersList
- currentUser={
- Object {
- "groups": Array [],
- "isLoggedIn": true,
- "login": "luke",
- "name": "Skywalker",
- "scmAccounts": Array [],
- }
- }
- members={
- Array [
- Object {
- "avatar": "",
- "groupCount": 3,
- "login": "admin",
- "name": "Admin Istrator",
- },
- Object {
- "avatar": "7daf6c79d4802916d83f6266e24850af",
- "groupCount": 1,
- "login": "john",
- "name": "John Doe",
- },
- ]
- }
- organization={
- Object {
- "key": "foo",
- "name": "Foo",
- }
- }
- organizationGroups={Array []}
- removeMember={[Function]}
- updateMemberGroups={[Function]}
- />
- <ListFooter
- count={2}
- loadMore={[Function]}
- ready={true}
- total={3}
- />
-</div>
-`;
diff --git a/server/sonar-web/src/main/js/apps/organizationMembers/__tests__/__snapshots__/RemoveMemberForm-test.tsx.snap b/server/sonar-web/src/main/js/apps/organizationMembers/__tests__/__snapshots__/RemoveMemberForm-test.tsx.snap
deleted file mode 100644
index 44022d1568c..00000000000
--- a/server/sonar-web/src/main/js/apps/organizationMembers/__tests__/__snapshots__/RemoveMemberForm-test.tsx.snap
+++ /dev/null
@@ -1,43 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render 1`] = `
-<Modal
- contentLabel="users.remove"
- key="remove-member-modal"
- onRequestClose={[MockFunction]}
->
- <header
- className="modal-head"
- >
- <h2>
- users.remove
- </h2>
- </header>
- <form
- onSubmit={[Function]}
- >
- <div
- className="modal-body"
- >
- organization.members.remove_x.Admin Istrator.MyOrg
- </div>
- <footer
- className="modal-foot"
- >
- <div>
- <SubmitButton
- autoFocus={true}
- className="button-red"
- >
- remove
- </SubmitButton>
- <ResetButtonLink
- onClick={[MockFunction]}
- >
- cancel
- </ResetButtonLink>
- </div>
- </footer>
- </form>
-</Modal>
-`;
diff --git a/server/sonar-web/src/main/js/apps/organizationMembers/__tests__/__snapshots__/SyncMemberForm-test.tsx.snap b/server/sonar-web/src/main/js/apps/organizationMembers/__tests__/__snapshots__/SyncMemberForm-test.tsx.snap
deleted file mode 100644
index 66187c5588d..00000000000
--- a/server/sonar-web/src/main/js/apps/organizationMembers/__tests__/__snapshots__/SyncMemberForm-test.tsx.snap
+++ /dev/null
@@ -1,187 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should allow to switch to automatic mode 1`] = `
-<ConfirmButton
- cancelButtonText="close"
- confirmButtonText="save"
- confirmDisable={true}
- modalBody={
- <div
- className="display-flex-stretch big-spacer-top"
- >
- <RadioCard
- onClick={[Function]}
- selected={true}
- title="organization.members.management.manual"
- >
- <div
- className="spacer-left"
- >
- <ul
- className="big-spacer-left note"
- >
- <li
- className="spacer-bottom"
- >
- organization.members.management.manual.add_members_manually
- </li>
- <li>
- organization.members.management.choose_members_permissions
- </li>
- </ul>
- </div>
- </RadioCard>
- <RadioCard
- onClick={[Function]}
- selected={false}
- title="organization.members.management.automatic.github"
- >
- <div
- className="spacer-left"
- >
- <ul
- className="big-spacer-left note"
- >
- <React.Fragment>
- <li
- className="spacer-bottom"
- >
- organization.members.management.automatic.synchronized_from_x.organization.github
- </li>
- <li
- className="spacer-bottom"
- >
- organization.members.management.automatic.members_changes_reflected.github
- </li>
- </React.Fragment>
- <li>
- organization.members.management.choose_members_permissions
- </li>
- </ul>
- </div>
- <Alert
- className="big-spacer-top"
- variant="warning"
- >
- organization.members.management.automatic.warning_x.organization.github
- </Alert>
- </RadioCard>
- </div>
- }
- modalHeader="organization.members.management.title"
- modalHeaderDescription={
- <p
- className="spacer-top"
- >
- organization.members.management.description
- <Link
- className="spacer-left"
- onlyActiveOnIndex={false}
- style={Object {}}
- target="_blank"
- to={
- Object {
- "pathname": "/documentation/organizations/manage-team/",
- }
- }
- >
- learn_more
- </Link>
- </p>
- }
- onConfirm={[Function]}
- size="medium"
->
- <Component />
-</ConfirmButton>
-`;
-
-exports[`should allow to switch to manual mode 1`] = `
-<ConfirmButton
- cancelButtonText="close"
- confirmButtonText="save"
- confirmDisable={true}
- modalBody={
- <div
- className="display-flex-stretch big-spacer-top"
- >
- <RadioCard
- onClick={[Function]}
- selected={false}
- title="organization.members.management.manual"
- >
- <div
- className="spacer-left"
- >
- <ul
- className="big-spacer-left note"
- >
- <li
- className="spacer-bottom"
- >
- organization.members.management.manual.add_members_manually
- </li>
- <li>
- organization.members.management.choose_members_permissions
- </li>
- </ul>
- </div>
- </RadioCard>
- <RadioCard
- onClick={[Function]}
- selected={true}
- title="organization.members.management.automatic.github"
- >
- <div
- className="spacer-left"
- >
- <ul
- className="big-spacer-left note"
- >
- <React.Fragment>
- <li
- className="spacer-bottom"
- >
- organization.members.management.automatic.synchronized_from_x.organization.github
- </li>
- <li
- className="spacer-bottom"
- >
- organization.members.management.automatic.members_changes_reflected.github
- </li>
- </React.Fragment>
- <li>
- organization.members.management.choose_members_permissions
- </li>
- </ul>
- </div>
- </RadioCard>
- </div>
- }
- modalHeader="organization.members.management.title"
- modalHeaderDescription={
- <p
- className="spacer-top"
- >
- organization.members.management.description
- <Link
- className="spacer-left"
- onlyActiveOnIndex={false}
- style={Object {}}
- target="_blank"
- to={
- Object {
- "pathname": "/documentation/organizations/manage-team/",
- }
- }
- >
- learn_more
- </Link>
- </p>
- }
- onConfirm={[Function]}
- size="medium"
->
- <Component />
-</ConfirmButton>
-`;
diff --git a/server/sonar-web/src/main/js/apps/organizations/__tests__/actions-test.ts b/server/sonar-web/src/main/js/apps/organizations/__tests__/actions-test.ts
deleted file mode 100644
index e12ef944753..00000000000
--- a/server/sonar-web/src/main/js/apps/organizations/__tests__/actions-test.ts
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import { deleteOrganization, updateOrganization } from '../../../api/organizations';
-import { mockOrganization } from '../../../helpers/testMocks';
-import * as actions from '../actions';
-
-jest.mock('../../../api/organizations', () => ({
- deleteOrganization: jest.fn().mockResolvedValue({}),
- updateOrganization: jest.fn().mockResolvedValue({})
-}));
-
-const dispatch = jest.fn();
-
-beforeEach(() => {
- jest.clearAllMocks();
-});
-
-describe('#updateOrganization', () => {
- it('should update and dispatch', async () => {
- const org = mockOrganization();
- const { key, ...changes } = org;
- const promise = actions.updateOrganization(key, changes)(dispatch);
-
- expect(updateOrganization).toHaveBeenCalledWith(key, changes);
- await promise;
- expect(dispatch).toHaveBeenCalledWith({ changes, key, type: 'UPDATE_ORGANIZATION' });
- });
-});
-
-describe('#deleteOrganization', () => {
- it('should delete and dispatch', async () => {
- const key = 'foo';
- const promise = actions.deleteOrganization(key)(dispatch);
-
- expect(deleteOrganization).toHaveBeenCalledWith(key);
- await promise;
- expect(dispatch).toHaveBeenCalledWith({ key, type: 'DELETE_ORGANIZATION' });
- });
-});
diff --git a/server/sonar-web/src/main/js/apps/organizations/actions.ts b/server/sonar-web/src/main/js/apps/organizations/actions.ts
deleted file mode 100644
index 5ce6c84a8d0..00000000000
--- a/server/sonar-web/src/main/js/apps/organizations/actions.ts
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import { Dispatch } from 'redux';
-import { translate } from 'sonar-ui-common/helpers/l10n';
-import * as api from '../../api/organizations';
-import { addGlobalSuccessMessage } from '../../store/globalMessages';
-import * as actions from '../../store/organizations';
-
-export function updateOrganization(key: string, changes: T.OrganizationBase) {
- return (dispatch: Dispatch<any>) => {
- return api.updateOrganization(key, changes).then(() => {
- dispatch(actions.updateOrganization(key, changes));
- dispatch(addGlobalSuccessMessage(translate('organization.updated')));
- });
- };
-}
-
-export function deleteOrganization(key: string) {
- return (dispatch: Dispatch<any>) => {
- return api.deleteOrganization(key).then(() => {
- dispatch(actions.deleteOrganization(key));
- });
- };
-}
diff --git a/server/sonar-web/src/main/js/apps/organizations/components/OrganizationAccessContainer.tsx b/server/sonar-web/src/main/js/apps/organizations/components/OrganizationAccessContainer.tsx
deleted file mode 100644
index 378b3c06357..00000000000
--- a/server/sonar-web/src/main/js/apps/organizations/components/OrganizationAccessContainer.tsx
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import * as React from 'react';
-import { connect } from 'react-redux';
-import { RouterState } from 'react-router';
-import handleRequiredAuthorization from '../../../app/utils/handleRequiredAuthorization';
-import { isLoggedIn } from '../../../helpers/users';
-import { getCurrentUser, getOrganizationByKey, Store } from '../../../store/rootReducer';
-
-interface StateToProps {
- currentUser: T.CurrentUser;
- organization?: T.Organization;
-}
-
-interface OwnProps extends RouterState {
- children: JSX.Element;
-}
-
-interface Props extends StateToProps, Pick<OwnProps, 'children' | 'location'> {
- hasAccess: (props: Props) => boolean;
-}
-
-export class OrganizationAccess extends React.PureComponent<Props> {
- componentDidMount() {
- this.checkPermissions();
- }
-
- componentDidUpdate() {
- this.checkPermissions();
- }
-
- checkPermissions = () => {
- if (!this.props.hasAccess(this.props)) {
- handleRequiredAuthorization();
- }
- };
-
- render() {
- if (!this.props.hasAccess(this.props)) {
- return null;
- }
- return React.cloneElement(this.props.children, {
- location: this.props.location,
- organization: this.props.organization
- });
- }
-}
-
-const mapStateToProps = (state: Store, ownProps: OwnProps) => ({
- currentUser: getCurrentUser(state),
- organization: getOrganizationByKey(state, ownProps.params.organizationKey)
-});
-
-const OrganizationAccessContainer = connect(mapStateToProps)(OrganizationAccess);
-
-export function hasAdminAccess({
- currentUser,
- organization
-}: Pick<StateToProps, 'currentUser' | 'organization'>) {
- return Boolean(
- isLoggedIn(currentUser) && organization && organization.actions && organization.actions.admin
- );
-}
-
-export default function OrganizationAdminAccess(props: OwnProps) {
- return <OrganizationAccessContainer hasAccess={hasAdminAccess} {...props} />;
-}
diff --git a/server/sonar-web/src/main/js/apps/organizations/components/OrganizationBind.tsx b/server/sonar-web/src/main/js/apps/organizations/components/OrganizationBind.tsx
deleted file mode 100644
index 60f9b64d8a9..00000000000
--- a/server/sonar-web/src/main/js/apps/organizations/components/OrganizationBind.tsx
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import * as React from 'react';
-import IdentityProviderLink from 'sonar-ui-common/components/controls/IdentityProviderLink';
-import { translate, translateWithParameters } from 'sonar-ui-common/helpers/l10n';
-import { save } from 'sonar-ui-common/helpers/storage';
-import { getBaseUrl } from 'sonar-ui-common/helpers/urls';
-import { getAlmAppInfo } from '../../../api/alm-integration';
-import { sanitizeAlmId } from '../../../helpers/almIntegrations';
-import {
- BIND_ORGANIZATION_KEY,
- BIND_ORGANIZATION_REDIRECT_TO_ORG_TIMESTAMP
-} from '../../create/organization/utils';
-
-interface Props {
- currentUser: T.LoggedInUser;
- organization: T.Organization;
-}
-
-interface State {
- almApplication?: T.AlmApplication;
-}
-
-export default class OrganizationBind extends React.PureComponent<Props, State> {
- mounted = false;
- state: State = {};
-
- componentDidMount() {
- this.mounted = true;
- this.fetchAlmApplication();
- }
-
- componentWillUnmount() {
- this.mounted = false;
- }
-
- fetchAlmApplication = () => {
- return getAlmAppInfo().then(({ application }) => {
- if (this.mounted) {
- this.setState({ almApplication: application });
- }
- });
- };
-
- handleInstallAppClick = () => {
- save(BIND_ORGANIZATION_KEY, this.props.organization.key);
- save(BIND_ORGANIZATION_REDIRECT_TO_ORG_TIMESTAMP, Date.now().toString());
- };
-
- render() {
- const { currentUser, organization } = this.props;
-
- const { almApplication } = this.state;
-
- const almKey = sanitizeAlmId(currentUser.externalProvider || '');
- const orgAlmKey = organization.alm ? sanitizeAlmId(organization.alm.key) : '';
- return (
- <div className="boxed-group boxed-group-inner">
- <h2 className="boxed-title">
- {translateWithParameters('organization.bind_to_x', translate(almKey))}
- </h2>
- {organization.alm ? (
- <>
- <span>{translate('organization.bound')}</span>
- <a
- className="link-no-underline big-spacer-left"
- href={organization.alm.url}
- rel="noopener noreferrer"
- target="_blank">
- <img
- alt={translate(orgAlmKey)}
- className="text-text-top little-spacer-right"
- height={16}
- src={`${getBaseUrl()}/images/sonarcloud/${orgAlmKey}.svg`}
- width={16}
- />
- {translateWithParameters('organization.see_on_x', translate(orgAlmKey))}
- </a>
- </>
- ) : (
- <>
- <p className="spacer-bottom">
- {translateWithParameters('organization.binding_with_x_easy_sync', translate(almKey))}
- </p>
- <p className="big-spacer-bottom">
- {translateWithParameters(
- 'organization.app_will_be_installed_on_x',
- translate(almKey)
- )}
- </p>
- {almApplication && (
- <IdentityProviderLink
- backgroundColor={almApplication.backgroundColor}
- className="display-inline-block"
- iconPath={almApplication.iconPath}
- name={almApplication.name}
- onClick={this.handleInstallAppClick}
- small={true}
- url={almApplication.installationUrl}>
- {translate(
- 'onboarding.import_organization.choose_the_organization_button',
- almApplication.key
- )}
- </IdentityProviderLink>
- )}
- </>
- )}
- </div>
- );
- }
-}
diff --git a/server/sonar-web/src/main/js/apps/organizations/components/OrganizationContainer.tsx b/server/sonar-web/src/main/js/apps/organizations/components/OrganizationContainer.tsx
deleted file mode 100644
index eb33a4efc5d..00000000000
--- a/server/sonar-web/src/main/js/apps/organizations/components/OrganizationContainer.tsx
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import * as React from 'react';
-import { connect } from 'react-redux';
-import { RouterState } from 'react-router';
-import { getCurrentUser, getOrganizationByKey, Store } from '../../../store/rootReducer';
-
-interface StateToProps {
- organization?: T.Organization;
- currentUser: T.CurrentUser;
-}
-
-interface OwnProps extends RouterState {
- children: JSX.Element;
-}
-
-interface Props extends StateToProps, Pick<OwnProps, 'children' | 'location'> {}
-
-class OrganizationContainer extends React.PureComponent<Props> {
- render() {
- return React.cloneElement(this.props.children, {
- location: this.props.location,
- currentUser: this.props.currentUser,
- organization: this.props.organization
- });
- }
-}
-
-const mapStateToProps = (state: Store, ownProps: OwnProps) => ({
- organization: getOrganizationByKey(state, ownProps.params.organizationKey),
- currentUser: getCurrentUser(state)
-});
-
-export default connect(mapStateToProps)(OrganizationContainer);
diff --git a/server/sonar-web/src/main/js/apps/organizations/components/OrganizationDelete.tsx b/server/sonar-web/src/main/js/apps/organizations/components/OrganizationDelete.tsx
deleted file mode 100644
index 89abf5f7e17..00000000000
--- a/server/sonar-web/src/main/js/apps/organizations/components/OrganizationDelete.tsx
+++ /dev/null
@@ -1,166 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import * as React from 'react';
-import { connect } from 'react-redux';
-import { Button } from 'sonar-ui-common/components/controls/buttons';
-import ConfirmButton from 'sonar-ui-common/components/controls/ConfirmButton';
-import { Alert } from 'sonar-ui-common/components/ui/Alert';
-import { translate, translateWithParameters } from 'sonar-ui-common/helpers/l10n';
-import { getOrganizationBilling } from '../../../api/organizations';
-import addGlobalSuccessMessage from '../../../app/utils/addGlobalSuccessMessage';
-import InstanceMessage from '../../../components/common/InstanceMessage';
-import { Router, withRouter } from '../../../components/hoc/withRouter';
-import { isSonarCloud } from '../../../helpers/system';
-import { deleteOrganization } from '../actions';
-
-interface DispatchToProps {
- deleteOrganization: (key: string) => Promise<void>;
-}
-
-interface OwnProps {
- organization: Pick<T.Organization, 'key' | 'name'>;
- router: Pick<Router, 'replace'>;
-}
-
-type Props = OwnProps & DispatchToProps;
-
-interface State {
- hasPaidPlan?: boolean;
- verify: string;
-}
-
-export class OrganizationDelete extends React.PureComponent<Props, State> {
- mounted = false;
- state: State = { verify: '' };
-
- componentDidMount() {
- this.mounted = true;
- this.fetchOrganizationPlanInfo();
- }
-
- componentWillUnmount() {
- this.mounted = false;
- }
-
- fetchOrganizationPlanInfo = () => {
- if (isSonarCloud()) {
- getOrganizationBilling(this.props.organization.key).then(
- billingInfo => {
- if (this.mounted) {
- this.setState({
- hasPaidPlan: billingInfo.subscription.status !== 'inactive'
- });
- }
- },
- () => {
- if (this.mounted) {
- this.setState({ hasPaidPlan: false });
- }
- }
- );
- }
- };
-
- handleInput = (event: React.ChangeEvent<HTMLInputElement>) => {
- this.setState({ verify: event.currentTarget.value });
- };
-
- isVerified = () => {
- return this.state.verify.toLowerCase() === this.props.organization.name.toLowerCase();
- };
-
- onDelete = () => {
- const { organization } = this.props;
- return this.props.deleteOrganization(organization.key).then(() => {
- if (this.state.hasPaidPlan) {
- this.props.router.replace({
- pathname: '/feedback/downgrade',
- state: {
- confirmationMessage: translateWithParameters(
- 'organization.deleted_x',
- organization.name
- ),
- organization,
- title: translate('billing.downgrade.reason.title_deleted')
- }
- });
- } else {
- addGlobalSuccessMessage(translate('organization.deleted'));
- this.props.router.replace('/');
- }
- });
- };
-
- render() {
- const { hasPaidPlan } = this.state;
- return (
- <div className="boxed-group boxed-group-inner">
- <h2 className="boxed-title">{translate('organization.delete')}</h2>
- <p className="big-spacer-bottom width-50">
- <InstanceMessage message={translate('organization.delete.description')} />
- </p>
- <ConfirmButton
- confirmButtonText={translate('delete')}
- confirmDisable={!this.isVerified()}
- isDestructive={true}
- modalBody={
- <div>
- {hasPaidPlan && (
- <Alert variant="warning">
- {translate('organization.delete.sonarcloud.paid_plan_info')}
- </Alert>
- )}
- <p>{translate('organization.delete.question')}</p>
- <div className="spacer-top">
- <label htmlFor="downgrade-organization-name">
- {translate('billing.downgrade.modal.type_to_proceed')}
- </label>
- <div className="little-spacer-top">
- <input
- autoFocus={true}
- className="input-super-large"
- id="downgrade-organization-name"
- onChange={this.handleInput}
- type="text"
- value={this.state.verify}
- />
- </div>
- </div>
- </div>
- }
- modalHeader={translateWithParameters(
- 'organization.delete_x',
- this.props.organization.name
- )}
- onConfirm={this.onDelete}>
- {({ onClick }) => (
- <Button className="js-custom-measure-delete button-red" onClick={onClick}>
- {translate('delete')}
- </Button>
- )}
- </ConfirmButton>
- </div>
- );
- }
-}
-
-const mapDispatchToProps: DispatchToProps = { deleteOrganization: deleteOrganization as any };
-
-export default withRouter(connect(null, mapDispatchToProps)(OrganizationDelete));
diff --git a/server/sonar-web/src/main/js/apps/organizations/components/OrganizationEdit.tsx b/server/sonar-web/src/main/js/apps/organizations/components/OrganizationEdit.tsx
deleted file mode 100644
index da74e304893..00000000000
--- a/server/sonar-web/src/main/js/apps/organizations/components/OrganizationEdit.tsx
+++ /dev/null
@@ -1,223 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import { debounce } from 'lodash';
-import * as React from 'react';
-import { Helmet } from 'react-helmet-async';
-import { connect } from 'react-redux';
-import { SubmitButton } from 'sonar-ui-common/components/controls/buttons';
-import { translate } from 'sonar-ui-common/helpers/l10n';
-import OrganizationAvatar from '../../../components/common/OrganizationAvatar';
-import { whenLoggedIn } from '../../../components/hoc/whenLoggedIn';
-import { hasAdvancedALMIntegration } from '../../../helpers/almIntegrations';
-import { updateOrganization } from '../actions';
-import OrganizationBind from './OrganizationBind';
-import OrganizationDelete from './OrganizationDelete';
-
-interface DispatchProps {
- updateOrganization: (organization: string, changes: T.OrganizationBase) => Promise<any>;
-}
-
-interface OwnProps {
- currentUser: T.LoggedInUser;
- organization: T.Organization;
-}
-
-type Props = OwnProps & DispatchProps;
-
-interface State {
- loading: boolean;
- avatar: string;
- avatarImage: string;
- description: string;
- name: string;
- url: string;
-}
-
-export class OrganizationEdit extends React.PureComponent<Props, State> {
- mounted = false;
-
- constructor(props: Props) {
- super(props);
- this.state = {
- loading: false,
- avatar: props.organization.avatar || '',
- avatarImage: props.organization.avatar || '',
- description: props.organization.description || '',
- name: props.organization.name,
- url: props.organization.url || ''
- };
- this.changeAvatarImage = debounce(this.changeAvatarImage, 500);
- }
-
- componentDidMount() {
- this.mounted = true;
- }
-
- componentWillUnmount() {
- this.mounted = false;
- }
-
- handleAvatarInputChange = (event: React.ChangeEvent<HTMLInputElement>) => {
- const { value } = event.target;
- this.setState({ avatar: value });
- this.changeAvatarImage(value);
- };
-
- changeAvatarImage = (value: string) => {
- this.setState({ avatarImage: value });
- };
-
- handleSubmit = (event: React.FormEvent<HTMLFormElement>) => {
- event.preventDefault();
- const changes = {
- avatar: this.state.avatar,
- description: this.state.description,
- name: this.state.name,
- url: this.state.url
- };
- this.setState({ loading: true });
- this.props
- .updateOrganization(this.props.organization.key, changes)
- .then(this.stopLoading, this.stopLoading);
- };
-
- stopLoading = () => {
- if (this.mounted) {
- this.setState({ loading: false });
- }
- };
-
- render() {
- const { currentUser, organization } = this.props;
- const title = translate('organization.settings');
-
- const showBinding = hasAdvancedALMIntegration(currentUser);
- const showDelete = organization.actions && organization.actions.delete;
-
- return (
- <div className="page page-limited">
- <Helmet defer={false} title={title} />
-
- <header className="page-header">
- <h1 className="page-title">{title}</h1>
- </header>
-
- <div className="boxed-group boxed-group-inner">
- <h2 className="boxed-title">{translate('organization.details')}</h2>
- <form onSubmit={this.handleSubmit}>
- <div className="form-field">
- <label htmlFor="organization-name">
- {translate('organization.name')}
- <em className="mandatory">*</em>
- </label>
- <input
- className="input-super-large"
- disabled={this.state.loading}
- id="organization-name"
- maxLength={255}
- name="name"
- onChange={e => this.setState({ name: e.target.value })}
- required={true}
- type="text"
- value={this.state.name}
- />
- <div className="form-field-description">
- {translate('organization.name.description')}
- </div>
- </div>
- <div className="form-field">
- <label htmlFor="organization-avatar">{translate('organization.avatar')}</label>
- <input
- className="input-super-large"
- disabled={this.state.loading}
- id="organization-avatar"
- maxLength={256}
- name="avatar"
- onChange={this.handleAvatarInputChange}
- placeholder={translate('onboarding.create_organization.avatar.placeholder')}
- type="text"
- value={this.state.avatar}
- />
- <div className="form-field-description">
- {translate('organization.avatar.description')}
- </div>
- {(this.state.avatarImage || this.state.name) && (
- <div className="spacer-top">
- <div className="little-spacer-bottom">
- {translate('organization.avatar.preview')}
- {':'}
- </div>
- <OrganizationAvatar
- organization={{
- avatar: this.state.avatarImage || undefined,
- name: this.state.name || ''
- }}
- />
- </div>
- )}
- </div>
- <div className="form-field">
- <label htmlFor="organization-description">{translate('description')}</label>
- <textarea
- className="input-super-large"
- disabled={this.state.loading}
- id="organization-description"
- maxLength={256}
- name="description"
- onChange={e => this.setState({ description: e.target.value })}
- rows={3}
- value={this.state.description}
- />
- <div className="form-field-description">
- {translate('organization.description.description')}
- </div>
- </div>
- <div className="form-field">
- <label htmlFor="organization-url">{translate('organization.url')}</label>
- <input
- className="input-super-large"
- disabled={this.state.loading}
- id="organization-url"
- maxLength={256}
- name="url"
- onChange={e => this.setState({ url: e.target.value })}
- type="text"
- value={this.state.url}
- />
- <div className="form-field-description">
- {translate('organization.url.description')}
- </div>
- </div>
- <SubmitButton disabled={this.state.loading}>{translate('save')}</SubmitButton>
- {this.state.loading && <i className="spinner spacer-left" />}
- </form>
- </div>
-
- {showBinding && <OrganizationBind currentUser={currentUser} organization={organization} />}
-
- {showDelete && <OrganizationDelete organization={organization} />}
- </div>
- );
- }
-}
-
-const mapDispatchToProps = { updateOrganization: updateOrganization as any };
-
-export default connect(null, mapDispatchToProps)(whenLoggedIn(OrganizationEdit));
diff --git a/server/sonar-web/src/main/js/apps/organizations/components/OrganizationEmpty.css b/server/sonar-web/src/main/js/apps/organizations/components/OrganizationEmpty.css
deleted file mode 100644
index 69466316b93..00000000000
--- a/server/sonar-web/src/main/js/apps/organizations/components/OrganizationEmpty.css
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-.organization-empty {
- margin: 100px auto 0;
- width: 472px;
-}
diff --git a/server/sonar-web/src/main/js/apps/organizations/components/OrganizationEmpty.tsx b/server/sonar-web/src/main/js/apps/organizations/components/OrganizationEmpty.tsx
deleted file mode 100644
index 6e639e557bf..00000000000
--- a/server/sonar-web/src/main/js/apps/organizations/components/OrganizationEmpty.tsx
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import * as React from 'react';
-import { Button } from 'sonar-ui-common/components/controls/buttons';
-import OnboardingAddMembersIcon from 'sonar-ui-common/components/icons/OnboardingAddMembersIcon';
-import { translate } from 'sonar-ui-common/helpers/l10n';
-import { Router, withRouter } from '../../../components/hoc/withRouter';
-import './OrganizationEmpty.css';
-
-interface Props {
- organization: T.Organization;
- router: Pick<Router, 'push'>;
-}
-
-export class OrganizationEmpty extends React.PureComponent<Props> {
- handleAddMembersClick = () => {
- const { organization } = this.props;
- this.props.router.push(`/organizations/${organization.key}/members`);
- };
-
- render() {
- const { organization } = this.props;
- const memberSyncActivated = organization.alm && organization.alm.membersSync;
-
- return (
- <div className="organization-empty">
- <h3 className="text-center">{translate('onboarding.create_organization.ready')}</h3>
- <div className="display-flex-space-around huge-spacer-top">
- {!memberSyncActivated && (
- <Button className="button-huge" onClick={this.handleAddMembersClick}>
- <OnboardingAddMembersIcon />
- <p className="medium spacer-top">{translate('organization.members.add.multiple')}</p>
- </Button>
- )}
- </div>
- </div>
- );
- }
-}
-
-export default withRouter(OrganizationEmpty);
diff --git a/server/sonar-web/src/main/js/apps/organizations/components/OrganizationGroupCheckbox.tsx b/server/sonar-web/src/main/js/apps/organizations/components/OrganizationGroupCheckbox.tsx
deleted file mode 100644
index 73cc251b8d2..00000000000
--- a/server/sonar-web/src/main/js/apps/organizations/components/OrganizationGroupCheckbox.tsx
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import * as classNames from 'classnames';
-import * as React from 'react';
-import Checkbox from 'sonar-ui-common/components/controls/Checkbox';
-
-interface Props {
- group: T.Group;
- checked: boolean;
- onCheck: (name: string, checked: boolean) => void;
-}
-
-export default class OrganizationGroupCheckbox extends React.PureComponent<Props> {
- onCheck = (checked: boolean) => {
- const { group } = this.props;
- if (!group.default) {
- this.props.onCheck(group.name, checked);
- }
- };
-
- toggleCheck = () => {
- this.onCheck(!this.props.checked);
- };
-
- render() {
- const { group } = this.props;
- return (
- <li
- className={classNames('capitalize list-item-checkable-link', { disabled: group.default })}
- onClick={this.toggleCheck}>
- <Checkbox checked={this.props.checked} onCheck={this.onCheck} /> {group.name}
- </li>
- );
- }
-}
diff --git a/server/sonar-web/src/main/js/apps/organizations/components/OrganizationPage.tsx b/server/sonar-web/src/main/js/apps/organizations/components/OrganizationPage.tsx
deleted file mode 100644
index 6e97d53198c..00000000000
--- a/server/sonar-web/src/main/js/apps/organizations/components/OrganizationPage.tsx
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import { Location } from 'history';
-import * as React from 'react';
-import { Helmet } from 'react-helmet-async';
-import { connect } from 'react-redux';
-import Suggestions from '../../../app/components/embed-docs-modal/Suggestions';
-import NotFound from '../../../app/components/NotFound';
-import { fetchOrganization } from '../../../store/rootActions';
-import {
- getCurrentUser,
- getMyOrganizations,
- getOrganizationByKey,
- Store
-} from '../../../store/rootReducer';
-import OrganizationNavigation from '../navigation/OrganizationNavigation';
-
-interface OwnProps {
- children?: React.ReactNode;
- location: Location;
- params: { organizationKey: string };
-}
-
-interface StateProps {
- currentUser: T.CurrentUser;
- organization?: T.Organization;
- userOrganizations: T.Organization[];
-}
-
-interface DispatchToProps {
- fetchOrganization: (organizationKey: string) => Promise<void>;
-}
-
-type Props = OwnProps & StateProps & DispatchToProps;
-
-interface State {
- loading: boolean;
-}
-
-export class OrganizationPage extends React.PureComponent<Props, State> {
- mounted = false;
- state: State = { loading: true };
-
- componentDidMount() {
- this.mounted = true;
- this.updateOrganization(this.props.params.organizationKey);
- }
-
- componentWillReceiveProps(nextProps: Props) {
- if (nextProps.params.organizationKey !== this.props.params.organizationKey) {
- this.updateOrganization(nextProps.params.organizationKey);
- }
- }
-
- componentWillUnmount() {
- this.mounted = false;
- }
-
- stopLoading = () => {
- if (this.mounted) {
- this.setState({ loading: false });
- }
- };
-
- updateOrganization = (organizationKey: string) => {
- this.setState({ loading: true });
- this.props.fetchOrganization(organizationKey).then(this.stopLoading, this.stopLoading);
- };
-
- render() {
- const { organization } = this.props;
-
- if (!organization || !organization.actions || organization.actions.admin == null) {
- if (this.state.loading) {
- return null;
- } else {
- return <NotFound withContainer={false} />;
- }
- }
-
- return (
- <div>
- <Helmet
- defaultTitle={organization.name}
- defer={false}
- titleTemplate={`%s - ${organization.name}`}
- />
- <Suggestions suggestions="organization_space" />
- <OrganizationNavigation
- currentUser={this.props.currentUser}
- location={this.props.location}
- organization={organization}
- userOrganizations={this.props.userOrganizations}
- />
- {this.props.children}
- </div>
- );
- }
-}
-
-const mapStateToProps = (state: Store, ownProps: OwnProps) => ({
- currentUser: getCurrentUser(state),
- organization: getOrganizationByKey(state, ownProps.params.organizationKey),
- userOrganizations: getMyOrganizations(state)
-});
-
-const mapDispatchToProps = { fetchOrganization: fetchOrganization as any };
-
-export default connect(mapStateToProps, mapDispatchToProps)(OrganizationPage);
diff --git a/server/sonar-web/src/main/js/apps/organizations/components/OrganizationProjects.tsx b/server/sonar-web/src/main/js/apps/organizations/components/OrganizationProjects.tsx
deleted file mode 100644
index c53f19f768d..00000000000
--- a/server/sonar-web/src/main/js/apps/organizations/components/OrganizationProjects.tsx
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import * as React from 'react';
-import Suggestions from '../../../app/components/embed-docs-modal/Suggestions';
-import AllProjectsContainer from '../../projects/components/AllProjectsContainer';
-
-interface Props {
- location: { pathname: string; query: T.Dict<string> };
- organization: T.Organization;
-}
-
-export default function OrganizationProjects(props: Props) {
- return (
- <>
- <AllProjectsContainer isFavorite={false} organization={props.organization} />
- <Suggestions suggestions="organization_projects" />
- </>
- );
-}
diff --git a/server/sonar-web/src/main/js/apps/organizations/components/__tests__/OrganizationAccessContainer-test.tsx b/server/sonar-web/src/main/js/apps/organizations/components/__tests__/OrganizationAccessContainer-test.tsx
deleted file mode 100644
index 2854c474a80..00000000000
--- a/server/sonar-web/src/main/js/apps/organizations/components/__tests__/OrganizationAccessContainer-test.tsx
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import { shallow } from 'enzyme';
-import { Location } from 'history';
-import * as React from 'react';
-import { hasAdminAccess, OrganizationAccess } from '../OrganizationAccessContainer';
-
-jest.mock('../../../../app/utils/handleRequiredAuthorization', () => ({ default: jest.fn() }));
-
-const locationMock = {} as Location;
-
-const currentUser = {
- isLoggedIn: false
-};
-
-const loggedInUser = {
- isLoggedIn: true,
- login: 'luke',
- name: 'Skywalker',
- showOnboardingTutorial: false
-};
-
-const organization: T.Organization = {
- actions: { admin: false },
- key: 'foo',
- name: 'Foo',
- projectVisibility: 'public'
-};
-
-const adminOrganization: T.Organization = { ...organization, actions: { admin: true } };
-
-describe('component', () => {
- it('should render children', () => {
- expect(
- shallow(
- <OrganizationAccess
- currentUser={loggedInUser}
- hasAccess={() => true}
- location={locationMock}
- organization={adminOrganization}>
- <div>hello</div>
- </OrganizationAccess>
- )
- ).toMatchSnapshot();
- });
-
- it('should not render anything', () => {
- expect(
- shallow(
- <OrganizationAccess
- currentUser={loggedInUser}
- hasAccess={() => false}
- location={locationMock}
- organization={adminOrganization}>
- <div>hello</div>
- </OrganizationAccess>
- ).type()
- ).toBeNull();
- });
-});
-
-describe('access functions', () => {
- it('should correctly handle access to admin only space', () => {
- expect(hasAdminAccess({ currentUser: loggedInUser, organization: adminOrganization })).toBe(
- true
- );
- expect(hasAdminAccess({ currentUser, organization: adminOrganization })).toBe(false);
- expect(hasAdminAccess({ currentUser: loggedInUser, organization })).toBe(false);
- });
-});
diff --git a/server/sonar-web/src/main/js/apps/organizations/components/__tests__/OrganizationBind-test.tsx b/server/sonar-web/src/main/js/apps/organizations/components/__tests__/OrganizationBind-test.tsx
deleted file mode 100644
index 0d84f412338..00000000000
--- a/server/sonar-web/src/main/js/apps/organizations/components/__tests__/OrganizationBind-test.tsx
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import { shallow } from 'enzyme';
-import * as React from 'react';
-import { save } from 'sonar-ui-common/helpers/storage';
-import { getAlmAppInfo } from '../../../../api/alm-integration';
-import {
- mockAlmApplication,
- mockLoggedInUser,
- mockOrganization
-} from '../../../../helpers/testMocks';
-import {
- BIND_ORGANIZATION_KEY,
- BIND_ORGANIZATION_REDIRECT_TO_ORG_TIMESTAMP
-} from '../../../create/organization/utils';
-import OrganizationBind from '../OrganizationBind';
-
-jest.mock('../../../../api/alm-integration', () => ({
- getAlmAppInfo: jest.fn(() => Promise.resolve({ application: mockAlmApplication() }))
-}));
-
-jest.mock('sonar-ui-common/helpers/storage', () => ({
- save: jest.fn()
-}));
-
-jest.mock('../../../../helpers/system', () => ({ isSonarCloud: jest.fn() }));
-
-beforeEach(() => {
- (getAlmAppInfo as jest.Mock<any>).mockClear();
-});
-
-it('should render correctly', () => {
- expect(shallowRender()).toMatchSnapshot();
-});
-
-it('should save state when handling Install App click', () => {
- const orgKey = '56346';
- shallowRender({ organization: mockOrganization({ key: orgKey }) })
- .instance()
- .handleInstallAppClick();
-
- expect(save).toBeCalledTimes(2);
- expect(save).nthCalledWith(1, BIND_ORGANIZATION_KEY, orgKey);
- const secondCallArguments = (save as jest.Mock<any>).mock.calls[1];
- expect(secondCallArguments[0]).toBe(BIND_ORGANIZATION_REDIRECT_TO_ORG_TIMESTAMP);
-});
-
-function shallowRender(props: Partial<OrganizationBind['props']> = {}) {
- return shallow<OrganizationBind>(
- <OrganizationBind
- currentUser={mockLoggedInUser()}
- organization={mockOrganization()}
- {...props}
- />
- );
-}
diff --git a/server/sonar-web/src/main/js/apps/organizations/components/__tests__/OrganizationDelete-test.tsx b/server/sonar-web/src/main/js/apps/organizations/components/__tests__/OrganizationDelete-test.tsx
deleted file mode 100644
index 3fc08d7c461..00000000000
--- a/server/sonar-web/src/main/js/apps/organizations/components/__tests__/OrganizationDelete-test.tsx
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import { shallow } from 'enzyme';
-import * as React from 'react';
-import { waitAndUpdate } from 'sonar-ui-common/helpers/testUtils';
-import { getOrganizationBilling } from '../../../../api/organizations';
-import { isSonarCloud } from '../../../../helpers/system';
-import { OrganizationDelete } from '../OrganizationDelete';
-
-jest.mock('../../../../api/organizations', () => ({
- getOrganizationBilling: jest.fn(() =>
- Promise.resolve({ nclocCount: 1000, subscription: { status: 'active', trial: true } })
- )
-}));
-
-jest.mock('../../../../helpers/system', () => ({ isSonarCloud: jest.fn() }));
-
-beforeEach(() => {
- (getOrganizationBilling as jest.Mock<any>).mockClear();
-});
-
-it('smoke test', () => {
- expect(getWrapper()).toMatchSnapshot();
-});
-
-it('should redirect the page', async () => {
- (isSonarCloud as jest.Mock).mockImplementation(() => false);
- const deleteOrganization = jest.fn(() => Promise.resolve());
- const replace = jest.fn();
- const wrapper = getWrapper({ deleteOrganization, router: { replace } });
- (wrapper.instance() as OrganizationDelete).onDelete();
- await waitAndUpdate(wrapper);
- expect(deleteOrganization).toHaveBeenCalledWith('foo');
- expect(replace).toHaveBeenCalledWith('/');
-});
-
-it('should show a info message for paying organization', async () => {
- (isSonarCloud as jest.Mock).mockImplementation(() => true);
- const wrapper = getWrapper({});
- await waitAndUpdate(wrapper);
- expect(getOrganizationBilling).toHaveBeenCalledWith('foo');
- expect(wrapper).toMatchSnapshot();
-});
-
-function getWrapper(props: Partial<OrganizationDelete['props']> = {}) {
- return shallow(
- <OrganizationDelete
- deleteOrganization={jest.fn(() => Promise.resolve())}
- organization={{ key: 'foo', name: 'Foo' }}
- router={{ replace: jest.fn() }}
- {...props}
- />
- );
-}
diff --git a/server/sonar-web/src/main/js/apps/organizations/components/__tests__/OrganizationEdit-test.tsx b/server/sonar-web/src/main/js/apps/organizations/components/__tests__/OrganizationEdit-test.tsx
deleted file mode 100644
index f7abfe2a723..00000000000
--- a/server/sonar-web/src/main/js/apps/organizations/components/__tests__/OrganizationEdit-test.tsx
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import { shallow } from 'enzyme';
-import * as React from 'react';
-import { mockLoggedInUser } from '../../../../helpers/testMocks';
-import { OrganizationEdit } from '../OrganizationEdit';
-
-it('smoke test', () => {
- const organization = { key: 'foo', name: 'Foo' };
- const wrapper = shallow(
- <OrganizationEdit
- currentUser={mockLoggedInUser()}
- organization={organization}
- updateOrganization={jest.fn()}
- />
- );
- expect(wrapper).toMatchSnapshot();
-
- wrapper.setState({
- avatar: 'foo-avatar',
- avatarImage: 'foo-avatar-image',
- description: 'foo-description',
- name: 'New Foo',
- url: 'foo-url'
- });
- expect(wrapper).toMatchSnapshot();
-
- wrapper.setState({ loading: true });
- expect(wrapper).toMatchSnapshot();
-});
diff --git a/server/sonar-web/src/main/js/apps/organizations/components/__tests__/OrganizationEmpty-test.tsx b/server/sonar-web/src/main/js/apps/organizations/components/__tests__/OrganizationEmpty-test.tsx
deleted file mode 100644
index 37757840977..00000000000
--- a/server/sonar-web/src/main/js/apps/organizations/components/__tests__/OrganizationEmpty-test.tsx
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import { shallow } from 'enzyme';
-import * as React from 'react';
-import { click } from 'sonar-ui-common/helpers/testUtils';
-import {
- mockOrganization,
- mockOrganizationWithAlm,
- mockRouter
-} from '../../../../helpers/testMocks';
-import { OrganizationEmpty } from '../OrganizationEmpty';
-
-const organization: T.Organization = mockOrganization();
-
-it('should render', () => {
- expect(shallowRender()).toMatchSnapshot();
-});
-
-it('should add members', () => {
- const push = jest.fn();
- const wrapper = shallowRender({ router: mockRouter({ push }) });
- click(wrapper.find('Button').last());
- expect(push).toBeCalledWith('/organizations/foo/members');
-});
-
-it('should hide add members button when member sync activated', () => {
- expect(
- shallowRender({ organization: mockOrganizationWithAlm({}, { membersSync: true }) })
- ).toMatchSnapshot();
-});
-
-function shallowRender(props: Partial<OrganizationEmpty['props']> = {}) {
- return shallow(
- <OrganizationEmpty organization={organization} router={mockRouter()} {...props} />
- );
-}
diff --git a/server/sonar-web/src/main/js/apps/organizations/components/__tests__/OrganizationGroupCheckbox-test.tsx b/server/sonar-web/src/main/js/apps/organizations/components/__tests__/OrganizationGroupCheckbox-test.tsx
deleted file mode 100644
index b59ae17fac4..00000000000
--- a/server/sonar-web/src/main/js/apps/organizations/components/__tests__/OrganizationGroupCheckbox-test.tsx
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import { shallow } from 'enzyme';
-import * as React from 'react';
-import OrganizationGroupCheckbox from '../OrganizationGroupCheckbox';
-
-const group = {
- id: 7,
- name: 'professionals',
- description: '',
- membersCount: 12,
- default: false
-};
-
-it('should render unchecked', () => {
- const wrapper = shallow(
- <OrganizationGroupCheckbox checked={false} group={group} onCheck={jest.fn()} />
- );
- expect(wrapper).toMatchSnapshot();
-});
-
-it('should be able to toggle check', () => {
- const onCheck = jest.fn().mockImplementation((_group, checked) => wrapper.setProps({ checked }));
- const wrapper = shallow(
- <OrganizationGroupCheckbox checked={true} group={group} onCheck={onCheck} />
- );
- expect(wrapper).toMatchSnapshot();
- (wrapper.instance() as OrganizationGroupCheckbox).toggleCheck();
- expect(onCheck.mock.calls).toMatchSnapshot();
- expect(wrapper).toMatchSnapshot();
-});
-
-it('should disabled default groups', () => {
- const onCheck = jest.fn().mockImplementation((_group, checked) => wrapper.setProps({ checked }));
- const wrapper = shallow(
- <OrganizationGroupCheckbox
- checked={true}
- group={{ ...group, default: true }}
- onCheck={onCheck}
- />
- );
- expect(wrapper).toMatchSnapshot();
- (wrapper.instance() as OrganizationGroupCheckbox).toggleCheck();
- expect(onCheck.mock.calls.length).toBe(0);
-});
diff --git a/server/sonar-web/src/main/js/apps/organizations/components/__tests__/OrganizationPage-test.tsx b/server/sonar-web/src/main/js/apps/organizations/components/__tests__/OrganizationPage-test.tsx
deleted file mode 100644
index ce6fa7061e3..00000000000
--- a/server/sonar-web/src/main/js/apps/organizations/components/__tests__/OrganizationPage-test.tsx
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import { shallow } from 'enzyme';
-import { Location } from 'history';
-import * as React from 'react';
-import { OrganizationPage } from '../OrganizationPage';
-
-const fetchOrganization = jest.fn().mockResolvedValue(undefined);
-
-beforeEach(() => {
- fetchOrganization.mockClear();
-});
-
-it('smoke test', () => {
- const wrapper = getWrapper();
- expect(wrapper.type()).toBeNull();
-
- const organization = { actions: { admin: false }, key: 'foo', name: 'Foo', isDefault: false };
- wrapper.setProps({ organization });
- expect(wrapper).toMatchSnapshot();
-});
-
-it('not found', () => {
- const wrapper = getWrapper();
- wrapper.setState({ loading: false });
- expect(wrapper).toMatchSnapshot();
-});
-
-it('should correctly update when the organization changes', () => {
- const wrapper = getWrapper();
- wrapper.setProps({ params: { organizationKey: 'bar' } });
- expect(fetchOrganization).toHaveBeenCalledTimes(2);
- expect(fetchOrganization.mock.calls).toMatchSnapshot();
-});
-
-function getWrapper(props = {}) {
- return shallow(
- <OrganizationPage
- currentUser={{ isLoggedIn: false }}
- fetchOrganization={fetchOrganization}
- location={{ pathname: 'foo' } as Location}
- params={{ organizationKey: 'foo' }}
- userOrganizations={[]}
- {...props}>
- <div>hello</div>
- </OrganizationPage>
- );
-}
diff --git a/server/sonar-web/src/main/js/apps/organizations/components/__tests__/__snapshots__/OrganizationAccessContainer-test.tsx.snap b/server/sonar-web/src/main/js/apps/organizations/components/__tests__/__snapshots__/OrganizationAccessContainer-test.tsx.snap
deleted file mode 100644
index ae075289ee9..00000000000
--- a/server/sonar-web/src/main/js/apps/organizations/components/__tests__/__snapshots__/OrganizationAccessContainer-test.tsx.snap
+++ /dev/null
@@ -1,19 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`component should render children 1`] = `
-<div
- location={Object {}}
- organization={
- Object {
- "actions": Object {
- "admin": true,
- },
- "key": "foo",
- "name": "Foo",
- "projectVisibility": "public",
- }
- }
->
- hello
-</div>
-`;
diff --git a/server/sonar-web/src/main/js/apps/organizations/components/__tests__/__snapshots__/OrganizationBind-test.tsx.snap b/server/sonar-web/src/main/js/apps/organizations/components/__tests__/__snapshots__/OrganizationBind-test.tsx.snap
deleted file mode 100644
index 69821637e05..00000000000
--- a/server/sonar-web/src/main/js/apps/organizations/components/__tests__/__snapshots__/OrganizationBind-test.tsx.snap
+++ /dev/null
@@ -1,23 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render correctly 1`] = `
-<div
- className="boxed-group boxed-group-inner"
->
- <h2
- className="boxed-title"
- >
- organization.bind_to_x.
- </h2>
- <p
- className="spacer-bottom"
- >
- organization.binding_with_x_easy_sync.
- </p>
- <p
- className="big-spacer-bottom"
- >
- organization.app_will_be_installed_on_x.
- </p>
-</div>
-`;
diff --git a/server/sonar-web/src/main/js/apps/organizations/components/__tests__/__snapshots__/OrganizationDelete-test.tsx.snap b/server/sonar-web/src/main/js/apps/organizations/components/__tests__/__snapshots__/OrganizationDelete-test.tsx.snap
deleted file mode 100644
index c2dee60e8f3..00000000000
--- a/server/sonar-web/src/main/js/apps/organizations/components/__tests__/__snapshots__/OrganizationDelete-test.tsx.snap
+++ /dev/null
@@ -1,118 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should show a info message for paying organization 1`] = `
-<div
- className="boxed-group boxed-group-inner"
->
- <h2
- className="boxed-title"
- >
- organization.delete
- </h2>
- <p
- className="big-spacer-bottom width-50"
- >
- <InstanceMessage
- message="organization.delete.description"
- />
- </p>
- <ConfirmButton
- confirmButtonText="delete"
- confirmDisable={true}
- isDestructive={true}
- modalBody={
- <div>
- <Alert
- variant="warning"
- >
- organization.delete.sonarcloud.paid_plan_info
- </Alert>
- <p>
- organization.delete.question
- </p>
- <div
- className="spacer-top"
- >
- <label
- htmlFor="downgrade-organization-name"
- >
- billing.downgrade.modal.type_to_proceed
- </label>
- <div
- className="little-spacer-top"
- >
- <input
- autoFocus={true}
- className="input-super-large"
- id="downgrade-organization-name"
- onChange={[Function]}
- type="text"
- value=""
- />
- </div>
- </div>
- </div>
- }
- modalHeader="organization.delete_x.Foo"
- onConfirm={[Function]}
- >
- <Component />
- </ConfirmButton>
-</div>
-`;
-
-exports[`smoke test 1`] = `
-<div
- className="boxed-group boxed-group-inner"
->
- <h2
- className="boxed-title"
- >
- organization.delete
- </h2>
- <p
- className="big-spacer-bottom width-50"
- >
- <InstanceMessage
- message="organization.delete.description"
- />
- </p>
- <ConfirmButton
- confirmButtonText="delete"
- confirmDisable={true}
- isDestructive={true}
- modalBody={
- <div>
- <p>
- organization.delete.question
- </p>
- <div
- className="spacer-top"
- >
- <label
- htmlFor="downgrade-organization-name"
- >
- billing.downgrade.modal.type_to_proceed
- </label>
- <div
- className="little-spacer-top"
- >
- <input
- autoFocus={true}
- className="input-super-large"
- id="downgrade-organization-name"
- onChange={[Function]}
- type="text"
- value=""
- />
- </div>
- </div>
- </div>
- }
- modalHeader="organization.delete_x.Foo"
- onConfirm={[Function]}
- >
- <Component />
- </ConfirmButton>
-</div>
-`;
diff --git a/server/sonar-web/src/main/js/apps/organizations/components/__tests__/__snapshots__/OrganizationEdit-test.tsx.snap b/server/sonar-web/src/main/js/apps/organizations/components/__tests__/__snapshots__/OrganizationEdit-test.tsx.snap
deleted file mode 100644
index fbb063779aa..00000000000
--- a/server/sonar-web/src/main/js/apps/organizations/components/__tests__/__snapshots__/OrganizationEdit-test.tsx.snap
+++ /dev/null
@@ -1,484 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`smoke test 1`] = `
-<div
- className="page page-limited"
->
- <Helmet
- defer={false}
- encodeSpecialCharacters={true}
- title="organization.settings"
- />
- <header
- className="page-header"
- >
- <h1
- className="page-title"
- >
- organization.settings
- </h1>
- </header>
- <div
- className="boxed-group boxed-group-inner"
- >
- <h2
- className="boxed-title"
- >
- organization.details
- </h2>
- <form
- onSubmit={[Function]}
- >
- <div
- className="form-field"
- >
- <label
- htmlFor="organization-name"
- >
- organization.name
- <em
- className="mandatory"
- >
- *
- </em>
- </label>
- <input
- className="input-super-large"
- disabled={false}
- id="organization-name"
- maxLength={255}
- name="name"
- onChange={[Function]}
- required={true}
- type="text"
- value="Foo"
- />
- <div
- className="form-field-description"
- >
- organization.name.description
- </div>
- </div>
- <div
- className="form-field"
- >
- <label
- htmlFor="organization-avatar"
- >
- organization.avatar
- </label>
- <input
- className="input-super-large"
- disabled={false}
- id="organization-avatar"
- maxLength={256}
- name="avatar"
- onChange={[Function]}
- placeholder="onboarding.create_organization.avatar.placeholder"
- type="text"
- value=""
- />
- <div
- className="form-field-description"
- >
- organization.avatar.description
- </div>
- <div
- className="spacer-top"
- >
- <div
- className="little-spacer-bottom"
- >
- organization.avatar.preview
- :
- </div>
- <OrganizationAvatar
- organization={
- Object {
- "avatar": undefined,
- "name": "Foo",
- }
- }
- />
- </div>
- </div>
- <div
- className="form-field"
- >
- <label
- htmlFor="organization-description"
- >
- description
- </label>
- <textarea
- className="input-super-large"
- disabled={false}
- id="organization-description"
- maxLength={256}
- name="description"
- onChange={[Function]}
- rows={3}
- value=""
- />
- <div
- className="form-field-description"
- >
- organization.description.description
- </div>
- </div>
- <div
- className="form-field"
- >
- <label
- htmlFor="organization-url"
- >
- organization.url
- </label>
- <input
- className="input-super-large"
- disabled={false}
- id="organization-url"
- maxLength={256}
- name="url"
- onChange={[Function]}
- type="text"
- value=""
- />
- <div
- className="form-field-description"
- >
- organization.url.description
- </div>
- </div>
- <SubmitButton
- disabled={false}
- >
- save
- </SubmitButton>
- </form>
- </div>
-</div>
-`;
-
-exports[`smoke test 2`] = `
-<div
- className="page page-limited"
->
- <Helmet
- defer={false}
- encodeSpecialCharacters={true}
- title="organization.settings"
- />
- <header
- className="page-header"
- >
- <h1
- className="page-title"
- >
- organization.settings
- </h1>
- </header>
- <div
- className="boxed-group boxed-group-inner"
- >
- <h2
- className="boxed-title"
- >
- organization.details
- </h2>
- <form
- onSubmit={[Function]}
- >
- <div
- className="form-field"
- >
- <label
- htmlFor="organization-name"
- >
- organization.name
- <em
- className="mandatory"
- >
- *
- </em>
- </label>
- <input
- className="input-super-large"
- disabled={false}
- id="organization-name"
- maxLength={255}
- name="name"
- onChange={[Function]}
- required={true}
- type="text"
- value="New Foo"
- />
- <div
- className="form-field-description"
- >
- organization.name.description
- </div>
- </div>
- <div
- className="form-field"
- >
- <label
- htmlFor="organization-avatar"
- >
- organization.avatar
- </label>
- <input
- className="input-super-large"
- disabled={false}
- id="organization-avatar"
- maxLength={256}
- name="avatar"
- onChange={[Function]}
- placeholder="onboarding.create_organization.avatar.placeholder"
- type="text"
- value="foo-avatar"
- />
- <div
- className="form-field-description"
- >
- organization.avatar.description
- </div>
- <div
- className="spacer-top"
- >
- <div
- className="little-spacer-bottom"
- >
- organization.avatar.preview
- :
- </div>
- <OrganizationAvatar
- organization={
- Object {
- "avatar": "foo-avatar-image",
- "name": "New Foo",
- }
- }
- />
- </div>
- </div>
- <div
- className="form-field"
- >
- <label
- htmlFor="organization-description"
- >
- description
- </label>
- <textarea
- className="input-super-large"
- disabled={false}
- id="organization-description"
- maxLength={256}
- name="description"
- onChange={[Function]}
- rows={3}
- value="foo-description"
- />
- <div
- className="form-field-description"
- >
- organization.description.description
- </div>
- </div>
- <div
- className="form-field"
- >
- <label
- htmlFor="organization-url"
- >
- organization.url
- </label>
- <input
- className="input-super-large"
- disabled={false}
- id="organization-url"
- maxLength={256}
- name="url"
- onChange={[Function]}
- type="text"
- value="foo-url"
- />
- <div
- className="form-field-description"
- >
- organization.url.description
- </div>
- </div>
- <SubmitButton
- disabled={false}
- >
- save
- </SubmitButton>
- </form>
- </div>
-</div>
-`;
-
-exports[`smoke test 3`] = `
-<div
- className="page page-limited"
->
- <Helmet
- defer={false}
- encodeSpecialCharacters={true}
- title="organization.settings"
- />
- <header
- className="page-header"
- >
- <h1
- className="page-title"
- >
- organization.settings
- </h1>
- </header>
- <div
- className="boxed-group boxed-group-inner"
- >
- <h2
- className="boxed-title"
- >
- organization.details
- </h2>
- <form
- onSubmit={[Function]}
- >
- <div
- className="form-field"
- >
- <label
- htmlFor="organization-name"
- >
- organization.name
- <em
- className="mandatory"
- >
- *
- </em>
- </label>
- <input
- className="input-super-large"
- disabled={true}
- id="organization-name"
- maxLength={255}
- name="name"
- onChange={[Function]}
- required={true}
- type="text"
- value="New Foo"
- />
- <div
- className="form-field-description"
- >
- organization.name.description
- </div>
- </div>
- <div
- className="form-field"
- >
- <label
- htmlFor="organization-avatar"
- >
- organization.avatar
- </label>
- <input
- className="input-super-large"
- disabled={true}
- id="organization-avatar"
- maxLength={256}
- name="avatar"
- onChange={[Function]}
- placeholder="onboarding.create_organization.avatar.placeholder"
- type="text"
- value="foo-avatar"
- />
- <div
- className="form-field-description"
- >
- organization.avatar.description
- </div>
- <div
- className="spacer-top"
- >
- <div
- className="little-spacer-bottom"
- >
- organization.avatar.preview
- :
- </div>
- <OrganizationAvatar
- organization={
- Object {
- "avatar": "foo-avatar-image",
- "name": "New Foo",
- }
- }
- />
- </div>
- </div>
- <div
- className="form-field"
- >
- <label
- htmlFor="organization-description"
- >
- description
- </label>
- <textarea
- className="input-super-large"
- disabled={true}
- id="organization-description"
- maxLength={256}
- name="description"
- onChange={[Function]}
- rows={3}
- value="foo-description"
- />
- <div
- className="form-field-description"
- >
- organization.description.description
- </div>
- </div>
- <div
- className="form-field"
- >
- <label
- htmlFor="organization-url"
- >
- organization.url
- </label>
- <input
- className="input-super-large"
- disabled={true}
- id="organization-url"
- maxLength={256}
- name="url"
- onChange={[Function]}
- type="text"
- value="foo-url"
- />
- <div
- className="form-field-description"
- >
- organization.url.description
- </div>
- </div>
- <SubmitButton
- disabled={true}
- >
- save
- </SubmitButton>
- <i
- className="spinner spacer-left"
- />
- </form>
- </div>
-</div>
-`;
diff --git a/server/sonar-web/src/main/js/apps/organizations/components/__tests__/__snapshots__/OrganizationEmpty-test.tsx.snap b/server/sonar-web/src/main/js/apps/organizations/components/__tests__/__snapshots__/OrganizationEmpty-test.tsx.snap
deleted file mode 100644
index 446b6447e13..00000000000
--- a/server/sonar-web/src/main/js/apps/organizations/components/__tests__/__snapshots__/OrganizationEmpty-test.tsx.snap
+++ /dev/null
@@ -1,43 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should hide add members button when member sync activated 1`] = `
-<div
- className="organization-empty"
->
- <h3
- className="text-center"
- >
- onboarding.create_organization.ready
- </h3>
- <div
- className="display-flex-space-around huge-spacer-top"
- />
-</div>
-`;
-
-exports[`should render 1`] = `
-<div
- className="organization-empty"
->
- <h3
- className="text-center"
- >
- onboarding.create_organization.ready
- </h3>
- <div
- className="display-flex-space-around huge-spacer-top"
- >
- <Button
- className="button-huge"
- onClick={[Function]}
- >
- <OnboardingAddMembersIcon />
- <p
- className="medium spacer-top"
- >
- organization.members.add.multiple
- </p>
- </Button>
- </div>
-</div>
-`;
diff --git a/server/sonar-web/src/main/js/apps/organizations/components/__tests__/__snapshots__/OrganizationGroupCheckbox-test.tsx.snap b/server/sonar-web/src/main/js/apps/organizations/components/__tests__/__snapshots__/OrganizationGroupCheckbox-test.tsx.snap
deleted file mode 100644
index e97cc7b40c0..00000000000
--- a/server/sonar-web/src/main/js/apps/organizations/components/__tests__/__snapshots__/OrganizationGroupCheckbox-test.tsx.snap
+++ /dev/null
@@ -1,70 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should be able to toggle check 1`] = `
-<li
- className="capitalize list-item-checkable-link"
- onClick={[Function]}
->
- <Checkbox
- checked={true}
- onCheck={[Function]}
- thirdState={false}
- />
-
- professionals
-</li>
-`;
-
-exports[`should be able to toggle check 2`] = `
-Array [
- Array [
- "professionals",
- false,
- ],
-]
-`;
-
-exports[`should be able to toggle check 3`] = `
-<li
- className="capitalize list-item-checkable-link"
- onClick={[Function]}
->
- <Checkbox
- checked={false}
- onCheck={[Function]}
- thirdState={false}
- />
-
- professionals
-</li>
-`;
-
-exports[`should disabled default groups 1`] = `
-<li
- className="capitalize list-item-checkable-link disabled"
- onClick={[Function]}
->
- <Checkbox
- checked={true}
- onCheck={[Function]}
- thirdState={false}
- />
-
- professionals
-</li>
-`;
-
-exports[`should render unchecked 1`] = `
-<li
- className="capitalize list-item-checkable-link"
- onClick={[Function]}
->
- <Checkbox
- checked={false}
- onCheck={[Function]}
- thirdState={false}
- />
-
- professionals
-</li>
-`;
diff --git a/server/sonar-web/src/main/js/apps/organizations/components/__tests__/__snapshots__/OrganizationPage-test.tsx.snap b/server/sonar-web/src/main/js/apps/organizations/components/__tests__/__snapshots__/OrganizationPage-test.tsx.snap
deleted file mode 100644
index df00c8a8a01..00000000000
--- a/server/sonar-web/src/main/js/apps/organizations/components/__tests__/__snapshots__/OrganizationPage-test.tsx.snap
+++ /dev/null
@@ -1,58 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`not found 1`] = `
-<NotFound
- withContainer={false}
-/>
-`;
-
-exports[`should correctly update when the organization changes 1`] = `
-Array [
- Array [
- "foo",
- ],
- Array [
- "bar",
- ],
-]
-`;
-
-exports[`smoke test 1`] = `
-<div>
- <Helmet
- defaultTitle="Foo"
- defer={false}
- encodeSpecialCharacters={true}
- titleTemplate="%s - Foo"
- />
- <Suggestions
- suggestions="organization_space"
- />
- <OrganizationNavigation
- currentUser={
- Object {
- "isLoggedIn": false,
- }
- }
- location={
- Object {
- "pathname": "foo",
- }
- }
- organization={
- Object {
- "actions": Object {
- "admin": false,
- },
- "isDefault": false,
- "key": "foo",
- "name": "Foo",
- }
- }
- userOrganizations={Array []}
- />
- <div>
- hello
- </div>
-</div>
-`;
diff --git a/server/sonar-web/src/main/js/apps/organizations/navigation/OrganizationNavigation.tsx b/server/sonar-web/src/main/js/apps/organizations/navigation/OrganizationNavigation.tsx
deleted file mode 100644
index 64059954432..00000000000
--- a/server/sonar-web/src/main/js/apps/organizations/navigation/OrganizationNavigation.tsx
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import * as React from 'react';
-import ContextNavBar from 'sonar-ui-common/components/ui/ContextNavBar';
-import { rawSizes } from '../../../app/theme';
-import OrganizationNavigationHeader from './OrganizationNavigationHeader';
-import OrganizationNavigationMenuContainer from './OrganizationNavigationMenuContainer';
-import OrganizationNavigationMeta from './OrganizationNavigationMeta';
-
-interface Props {
- currentUser: T.CurrentUser;
- location: { pathname: string };
- organization: T.Organization;
- userOrganizations: T.Organization[];
-}
-
-export default function OrganizationNavigation({
- currentUser,
- location,
- organization,
- userOrganizations
-}: Props) {
- return (
- <ContextNavBar height={rawSizes.contextNavHeightRaw} id="context-navigation">
- <div className="navbar-context-justified">
- <OrganizationNavigationHeader
- currentUser={currentUser}
- organization={organization}
- organizations={userOrganizations}
- />
- <OrganizationNavigationMeta
- currentUser={currentUser}
- organization={organization}
- userOrganizations={userOrganizations}
- />
- </div>
- <OrganizationNavigationMenuContainer location={location} organization={organization} />
- </ContextNavBar>
- );
-}
diff --git a/server/sonar-web/src/main/js/apps/organizations/navigation/OrganizationNavigationAdministration.tsx b/server/sonar-web/src/main/js/apps/organizations/navigation/OrganizationNavigationAdministration.tsx
deleted file mode 100644
index de85692ddb8..00000000000
--- a/server/sonar-web/src/main/js/apps/organizations/navigation/OrganizationNavigationAdministration.tsx
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import * as classNames from 'classnames';
-import * as React from 'react';
-import { Link } from 'react-router';
-import Dropdown from 'sonar-ui-common/components/controls/Dropdown';
-import DropdownIcon from 'sonar-ui-common/components/icons/DropdownIcon';
-import { translate } from 'sonar-ui-common/helpers/l10n';
-
-interface Props {
- location: { pathname: string };
- organization: T.Organization;
-}
-
-const ADMIN_PATHS = [
- 'edit',
- 'groups',
- 'permissions',
- 'permission_templates',
- 'projects_management',
- 'webhooks'
-];
-
-export default function OrganizationNavigationAdministration({ location, organization }: Props) {
- const { adminPages = [] } = organization;
- const adminPathsWithExtensions = adminPages.map(e => `extension/${e.key}`).concat(ADMIN_PATHS);
- const adminActive = adminPathsWithExtensions.some(path =>
- location.pathname.endsWith(`organizations/${organization.key}/${path}`)
- );
-
- return (
- <Dropdown
- overlay={
- <ul className="menu">
- <li>
- <Link activeClassName="active" to={`/organizations/${organization.key}/edit`}>
- {translate('organization.settings')}
- </Link>
- </li>
- {adminPages.map(extension => (
- <li key={extension.key}>
- <Link
- activeClassName="active"
- to={`/organizations/${organization.key}/extension/${extension.key}`}>
- {extension.name}
- </Link>
- </li>
- ))}
- <li>
- <Link activeClassName="active" to={`/organizations/${organization.key}/groups`}>
- {translate('user_groups.page')}
- </Link>
- </li>
- <li>
- <Link activeClassName="active" to={`/organizations/${organization.key}/permissions`}>
- {translate('permissions.page')}
- </Link>
- </li>
- <li>
- <Link
- activeClassName="active"
- to={`/organizations/${organization.key}/permission_templates`}>
- {translate('permission_templates')}
- </Link>
- </li>
- <li>
- <Link
- activeClassName="active"
- to={`/organizations/${organization.key}/projects_management`}>
- {translate('projects_management')}
- </Link>
- </li>
- <li>
- <Link activeClassName="active" to={`/organizations/${organization.key}/webhooks`}>
- {translate('webhooks.page')}
- </Link>
- </li>
- </ul>
- }
- tagName="li">
- <a
- className={classNames('dropdown-toggle', { active: adminActive })}
- href="#"
- id="organization-navigation-admin">
- {translate('layout.settings')}
- <DropdownIcon className="little-spacer-left" />
- </a>
- </Dropdown>
- );
-}
diff --git a/server/sonar-web/src/main/js/apps/organizations/navigation/OrganizationNavigationExtensions.tsx b/server/sonar-web/src/main/js/apps/organizations/navigation/OrganizationNavigationExtensions.tsx
deleted file mode 100644
index ec22ccc6ca8..00000000000
--- a/server/sonar-web/src/main/js/apps/organizations/navigation/OrganizationNavigationExtensions.tsx
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import * as classNames from 'classnames';
-import * as React from 'react';
-import { Link } from 'react-router';
-import Dropdown from 'sonar-ui-common/components/controls/Dropdown';
-import DropdownIcon from 'sonar-ui-common/components/icons/DropdownIcon';
-import { translate } from 'sonar-ui-common/helpers/l10n';
-
-interface Props {
- location: { pathname: string };
- organization: T.Organization;
-}
-
-export default function OrganizationNavigationExtensions({ location, organization }: Props) {
- const extensions = organization.pages || [];
- if (extensions.length === 0) {
- return null;
- }
- const active = extensions.some(
- extension =>
- location.pathname === `/organizations/${organization.key}/extension/${extension.key}`
- );
-
- return (
- <Dropdown
- overlay={
- <ul className="menu">
- {extensions.map(extension => (
- <li key={extension.key}>
- <Link
- activeClassName="active"
- to={`/organizations/${organization.key}/extension/${extension.key}`}>
- {extension.name}
- </Link>
- </li>
- ))}
- </ul>
- }
- tagName="li">
- <a
- className={classNames('dropdown-toggle', { active })}
- href="#"
- id="organization-navigation-more">
- {translate('more')}
- <DropdownIcon className="little-spacer-left" />
- </a>
- </Dropdown>
- );
-}
diff --git a/server/sonar-web/src/main/js/apps/organizations/navigation/OrganizationNavigationHeader.tsx b/server/sonar-web/src/main/js/apps/organizations/navigation/OrganizationNavigationHeader.tsx
deleted file mode 100644
index b3f05a89636..00000000000
--- a/server/sonar-web/src/main/js/apps/organizations/navigation/OrganizationNavigationHeader.tsx
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import { sortBy } from 'lodash';
-import * as React from 'react';
-import { Link } from 'react-router';
-import Dropdown from 'sonar-ui-common/components/controls/Dropdown';
-import Tooltip from 'sonar-ui-common/components/controls/Tooltip';
-import DropdownIcon from 'sonar-ui-common/components/icons/DropdownIcon';
-import { translate, translateWithParameters } from 'sonar-ui-common/helpers/l10n';
-import { getBaseUrl } from 'sonar-ui-common/helpers/urls';
-import OrganizationAvatar from '../../../components/common/OrganizationAvatar';
-import OrganizationListItem from '../../../components/ui/OrganizationListItem';
-import {
- getUserAlmKey,
- hasAdvancedALMIntegration,
- sanitizeAlmId
-} from '../../../helpers/almIntegrations';
-
-export interface Props {
- currentUser: T.CurrentUser;
- organization: T.Organization;
- organizations: T.Organization[];
-}
-
-export default function OrganizationNavigationHeader({
- currentUser,
- organization,
- organizations
-}: Props) {
- const other = organizations.filter(o => o.key !== organization.key);
- const isAdmin = organization.actions && organization.actions.admin;
-
- let almKey;
- let tooltipContent;
- let tooltipIconSrc;
- if (organization.alm) {
- almKey = sanitizeAlmId(organization.alm.key);
- tooltipContent = (
- <>
- <p>{translateWithParameters('organization.bound_to_x', translate(almKey))}</p>
- <hr className="spacer-top spacer-bottom" />
- <a href={organization.alm.url} rel="noopener noreferrer" target="_blank">
- {translateWithParameters('organization.see_on_x', translate(almKey))}
- </a>
- </>
- );
- tooltipIconSrc = `${getBaseUrl()}/images/sonarcloud/${almKey}.svg`;
- } else if (hasAdvancedALMIntegration(currentUser)) {
- almKey = getUserAlmKey(currentUser) || '';
- tooltipContent = (
- <>
- <p>{translateWithParameters('organization.not_bound_to_x', translate(almKey))}</p>
- {isAdmin && (
- <>
- <hr className="spacer-top spacer-bottom" />
- <Link to={`/organizations/${organization.key}/edit`}>
- {translate('organization.go_to_settings_to_bind')}
- </Link>
- </>
- )}
- </>
- );
- tooltipIconSrc = `${getBaseUrl()}/images/sonarcloud/${almKey}-unbound.svg`;
- }
-
- return (
- <header className="navbar-context-header">
- <OrganizationAvatar organization={organization} />
- {other.length ? (
- <Dropdown
- className="display-inline-block"
- overlay={
- <ul className="menu">
- {sortBy(other, org => org.name.toLowerCase()).map(organization => (
- <OrganizationListItem key={organization.key} organization={organization} />
- ))}
- </ul>
- }>
- <a
- className="display-inline-flex-center spacer-left link-base-color link-no-underline"
- href="#">
- {organization.name}
- <DropdownIcon className="little-spacer-left" />
- </a>
- </Dropdown>
- ) : (
- <span className="spacer-left">{organization.name}</span>
- )}
- {almKey && (
- <Tooltip mouseLeaveDelay={0.25} overlay={tooltipContent}>
- <img
- alt={translate(almKey)}
- className="text-middle spacer-left"
- height={16}
- src={tooltipIconSrc}
- width={16}
- />
- </Tooltip>
- )}
- {organization.description != null && (
- <div className="navbar-context-description">
- <p className="text-limited text-top" title={organization.description}>
- {organization.description}
- </p>
- </div>
- )}
- </header>
- );
-}
diff --git a/server/sonar-web/src/main/js/apps/organizations/navigation/OrganizationNavigationMenuContainer.tsx b/server/sonar-web/src/main/js/apps/organizations/navigation/OrganizationNavigationMenuContainer.tsx
deleted file mode 100644
index 796c7af8302..00000000000
--- a/server/sonar-web/src/main/js/apps/organizations/navigation/OrganizationNavigationMenuContainer.tsx
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import * as React from 'react';
-import { connect } from 'react-redux';
-import { Link } from 'react-router';
-import NavBarTabs from 'sonar-ui-common/components/ui/NavBarTabs';
-import { translate } from 'sonar-ui-common/helpers/l10n';
-import { hasPrivateAccess, isCurrentUserMemberOf } from '../../../helpers/organizations';
-import { getQualityGatesUrl } from '../../../helpers/urls';
-import { getCurrentUser, getMyOrganizations, Store } from '../../../store/rootReducer';
-import OrganizationNavigationAdministration from './OrganizationNavigationAdministration';
-import OrganizationNavigationExtensions from './OrganizationNavigationExtensions';
-
-interface StateToProps {
- currentUser: T.CurrentUser;
- userOrganizations: T.Organization[];
-}
-
-interface OwnProps {
- location: { pathname: string };
- organization: T.Organization;
-}
-
-type Props = OwnProps & StateToProps;
-
-export function OrganizationNavigationMenu({
- currentUser,
- location,
- organization,
- userOrganizations
-}: Props) {
- const hasPrivateRights = hasPrivateAccess(currentUser, organization, userOrganizations);
- const { actions = {} } = organization;
- return (
- <NavBarTabs className="navbar-context-tabs">
- <li>
- <Link activeClassName="active" to={`/organizations/${organization.key}/projects`}>
- {translate('projects.page')}
- </Link>
- </li>
- <li>
- <Link
- activeClassName="active"
- to={{
- pathname: `/organizations/${organization.key}/issues`,
- query: { resolved: 'false' }
- }}>
- {translate('issues.page')}
- </Link>
- </li>
- {hasPrivateRights && (
- <li>
- <Link activeClassName="active" to={`/organizations/${organization.key}/quality_profiles`}>
- {translate('quality_profiles.page')}
- </Link>
- </li>
- )}
- <li>
- <Link activeClassName="active" to={`/organizations/${organization.key}/rules`}>
- {translate('coding_rules.page')}
- </Link>
- </li>
- {hasPrivateRights && (
- <li>
- <Link activeClassName="active" to={getQualityGatesUrl(organization.key)}>
- {translate('quality_gates.page')}
- </Link>
- </li>
- )}
- {isCurrentUserMemberOf(currentUser, organization, userOrganizations) && (
- <li>
- <Link activeClassName="active" to={`/organizations/${organization.key}/members`}>
- {translate('organization.members.page')}
- </Link>
- </li>
- )}
- <OrganizationNavigationExtensions location={location} organization={organization} />
- {actions.admin && (
- <OrganizationNavigationAdministration location={location} organization={organization} />
- )}
- </NavBarTabs>
- );
-}
-
-const mapStateToProps = (state: Store) => ({
- currentUser: getCurrentUser(state),
- userOrganizations: getMyOrganizations(state)
-});
-
-export default connect(mapStateToProps)(OrganizationNavigationMenu);
diff --git a/server/sonar-web/src/main/js/apps/organizations/navigation/OrganizationNavigationMeta.tsx b/server/sonar-web/src/main/js/apps/organizations/navigation/OrganizationNavigationMeta.tsx
deleted file mode 100644
index a6b877cdc1d..00000000000
--- a/server/sonar-web/src/main/js/apps/organizations/navigation/OrganizationNavigationMeta.tsx
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import * as React from 'react';
-import { translate } from 'sonar-ui-common/helpers/l10n';
-import HomePageSelect from '../../../components/controls/HomePageSelect';
-import DocTooltip from '../../../components/docs/DocTooltip';
-import { hasPrivateAccess, isPaidOrganization } from '../../../helpers/organizations';
-import { isSonarCloud } from '../../../helpers/system';
-
-interface Props {
- currentUser: T.CurrentUser;
- organization: T.Organization;
- userOrganizations: T.Organization[];
-}
-
-export default function OrganizationNavigationMeta({
- currentUser,
- organization,
- userOrganizations
-}: Props) {
- const onSonarCloud = isSonarCloud();
- return (
- <div className="navbar-context-meta">
- {organization.url != null && (
- <a
- className="spacer-right text-limited"
- href={organization.url}
- rel="nofollow"
- title={organization.url}>
- {organization.url}
- </a>
- )}
- {onSonarCloud &&
- isPaidOrganization(organization) &&
- hasPrivateAccess(currentUser, organization, userOrganizations) && (
- <DocTooltip
- className="spacer-right"
- doc={import(
- /* webpackMode: "eager" */ 'Docs/tooltips/organizations/subscription-paid-plan.md'
- )}>
- <div className="badge">{translate('organization.paid_plan.badge')}</div>
- </DocTooltip>
- )}
- <div className="text-muted">
- <strong>{translate('organization.key')}:</strong> {organization.key}
- </div>
- {onSonarCloud && (
- <div className="navbar-context-meta-secondary">
- <HomePageSelect currentPage={{ type: 'ORGANIZATION', organization: organization.key }} />
- </div>
- )}
- </div>
- );
-}
diff --git a/server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/OrganizationNavigation-test.tsx b/server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/OrganizationNavigation-test.tsx
deleted file mode 100644
index ec2bf5e6303..00000000000
--- a/server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/OrganizationNavigation-test.tsx
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import { shallow } from 'enzyme';
-import * as React from 'react';
-import OrganizationNavigation from '../OrganizationNavigation';
-
-it('render', () => {
- expect(
- shallow(
- <OrganizationNavigation
- currentUser={{ isLoggedIn: false }}
- location={{ pathname: '/organizations/foo' }}
- organization={{
- key: 'foo',
- name: 'Foo',
- projectVisibility: 'public'
- }}
- userOrganizations={[]}
- />
- )
- ).toMatchSnapshot();
-});
diff --git a/server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/OrganizationNavigationAdministration-test.tsx b/server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/OrganizationNavigationAdministration-test.tsx
deleted file mode 100644
index d30527f99cb..00000000000
--- a/server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/OrganizationNavigationAdministration-test.tsx
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import { shallow } from 'enzyme';
-import * as React from 'react';
-import OrganizationNavigationAdministration from '../OrganizationNavigationAdministration';
-
-it('renders', () => {
- const wrapper = shallow(
- <OrganizationNavigationAdministration
- location={{ pathname: '' }}
- organization={{
- key: 'foo',
- name: 'Foo',
- projectVisibility: 'public'
- }}
- />
- );
- expect(wrapper.find('Dropdown')).toMatchSnapshot();
-});
diff --git a/server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/OrganizationNavigationHeader-test.tsx b/server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/OrganizationNavigationHeader-test.tsx
deleted file mode 100644
index fd23910634d..00000000000
--- a/server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/OrganizationNavigationHeader-test.tsx
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import { shallow } from 'enzyme';
-import * as React from 'react';
-import {
- mockCurrentUser,
- mockLoggedInUser,
- mockOrganizationWithAlm
-} from '../../../../helpers/testMocks';
-import OrganizationNavigationHeader, { Props } from '../OrganizationNavigationHeader';
-
-it('renders', () => {
- expect(shallowRender()).toMatchSnapshot();
-});
-
-it('renders with alm integration', () => {
- expect(
- shallowRender({ organization: mockOrganizationWithAlm({ projectVisibility: 'public' }) })
- ).toMatchSnapshot();
-});
-
-it('renders for external user w/o alm integration', () => {
- expect(
- shallowRender({ currentUser: mockLoggedInUser({ externalProvider: 'github' }) })
- ).toMatchSnapshot();
-});
-
-it('renders with the organization tooltip for an admin user of an organization', () => {
- expect(
- shallowRender({
- currentUser: mockLoggedInUser({
- externalProvider: 'github'
- }),
- organization: {
- actions: { admin: true },
- key: 'org1',
- name: 'org1',
- projectVisibility: 'public'
- }
- }).find('Tooltip')
- ).toMatchSnapshot();
-});
-
-it('renders without the organization tooltip for a non-admin user of an organization', () => {
- expect(
- shallowRender({
- currentUser: mockLoggedInUser({
- externalProvider: 'github'
- }),
- organization: {
- actions: { admin: false },
- key: 'org1',
- name: 'org1',
- projectVisibility: 'public'
- }
- }).find('Tooltip')
- ).toMatchSnapshot();
-});
-
-it('renders dropdown', () => {
- const organizations: T.Organization[] = [
- { actions: { admin: true }, key: 'org1', name: 'org1', projectVisibility: 'public' },
- { actions: { admin: false }, key: 'org2', name: 'org2', projectVisibility: 'public' }
- ];
- const wrapper = shallowRender({
- organizations
- });
- expect(wrapper.find('Dropdown')).toMatchSnapshot();
-});
-
-function shallowRender(props: Partial<Props> = {}) {
- return shallow(
- <OrganizationNavigationHeader
- currentUser={mockCurrentUser()}
- organization={{
- key: 'foo',
- name: 'Foo',
- projectVisibility: 'public'
- }}
- organizations={[]}
- {...props}
- />
- );
-}
diff --git a/server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/OrganizationNavigationMenuContainer-test.tsx b/server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/OrganizationNavigationMenuContainer-test.tsx
deleted file mode 100644
index ec811e5ff0c..00000000000
--- a/server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/OrganizationNavigationMenuContainer-test.tsx
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import { shallow } from 'enzyme';
-import * as React from 'react';
-import { hasPrivateAccess, isCurrentUserMemberOf } from '../../../../helpers/organizations';
-import { OrganizationNavigationMenu } from '../OrganizationNavigationMenuContainer';
-
-jest.mock('../../../../helpers/organizations', () => ({
- isCurrentUserMemberOf: jest.fn().mockReturnValue(true),
- hasPrivateAccess: jest.fn().mockReturnValue(true)
-}));
-
-const organization: T.Organization = {
- key: 'foo',
- name: 'Foo',
- projectVisibility: 'public'
-};
-
-const loggedInUser = {
- isLoggedIn: true,
- login: 'luke',
- name: 'Skywalker',
- showOnboardingTutorial: false
-};
-
-beforeEach(() => {
- (isCurrentUserMemberOf as jest.Mock<any>).mockClear();
- (hasPrivateAccess as jest.Mock<any>).mockClear();
-});
-
-it('renders', () => {
- expect(
- shallow(
- <OrganizationNavigationMenu
- currentUser={loggedInUser}
- location={{ pathname: '' }}
- organization={organization}
- userOrganizations={[organization]}
- />
- )
- ).toMatchSnapshot();
-});
-
-it('renders for admin', () => {
- expect(
- shallow(
- <OrganizationNavigationMenu
- currentUser={loggedInUser}
- location={{ pathname: '' }}
- organization={{ ...organization, actions: { admin: true } }}
- userOrganizations={[organization]}
- />
- )
- ).toMatchSnapshot();
-});
diff --git a/server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/OrganizationNavigationMeta-test.tsx b/server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/OrganizationNavigationMeta-test.tsx
deleted file mode 100644
index 851f649cf75..00000000000
--- a/server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/OrganizationNavigationMeta-test.tsx
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import { shallow } from 'enzyme';
-import * as React from 'react';
-import OrganizationNavigationMeta from '../OrganizationNavigationMeta';
-
-jest.mock('../../../../helpers/system', () => ({ isSonarCloud: () => true }));
-
-const organization: T.Organization = { key: 'foo', name: 'Foo', subscription: 'FREE' };
-
-it('renders', () => {
- expect(
- shallow(
- <OrganizationNavigationMeta
- currentUser={{ isLoggedIn: false }}
- organization={organization}
- userOrganizations={[]}
- />
- )
- ).toMatchSnapshot();
-});
-
-it('renders with private badge', () => {
- expect(
- shallow(
- <OrganizationNavigationMeta
- currentUser={{ isLoggedIn: true }}
- organization={{ ...organization, subscription: 'PAID' }}
- userOrganizations={[organization]}
- />
- )
- .find('DocTooltip')
- .exists()
- ).toBe(true);
-});
diff --git a/server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/__snapshots__/OrganizationNavigation-test.tsx.snap b/server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/__snapshots__/OrganizationNavigation-test.tsx.snap
deleted file mode 100644
index 1db61a2ee48..00000000000
--- a/server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/__snapshots__/OrganizationNavigation-test.tsx.snap
+++ /dev/null
@@ -1,57 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`render 1`] = `
-<ContextNavBar
- height={72}
- id="context-navigation"
->
- <div
- className="navbar-context-justified"
- >
- <OrganizationNavigationHeader
- currentUser={
- Object {
- "isLoggedIn": false,
- }
- }
- organization={
- Object {
- "key": "foo",
- "name": "Foo",
- "projectVisibility": "public",
- }
- }
- organizations={Array []}
- />
- <OrganizationNavigationMeta
- currentUser={
- Object {
- "isLoggedIn": false,
- }
- }
- organization={
- Object {
- "key": "foo",
- "name": "Foo",
- "projectVisibility": "public",
- }
- }
- userOrganizations={Array []}
- />
- </div>
- <Connect(OrganizationNavigationMenu)
- location={
- Object {
- "pathname": "/organizations/foo",
- }
- }
- organization={
- Object {
- "key": "foo",
- "name": "Foo",
- "projectVisibility": "public",
- }
- }
- />
-</ContextNavBar>
-`;
diff --git a/server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/__snapshots__/OrganizationNavigationAdministration-test.tsx.snap b/server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/__snapshots__/OrganizationNavigationAdministration-test.tsx.snap
deleted file mode 100644
index da8dbbc2c87..00000000000
--- a/server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/__snapshots__/OrganizationNavigationAdministration-test.tsx.snap
+++ /dev/null
@@ -1,84 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`renders 1`] = `
-<Dropdown
- overlay={
- <ul
- className="menu"
- >
- <li>
- <Link
- activeClassName="active"
- onlyActiveOnIndex={false}
- style={Object {}}
- to="/organizations/foo/edit"
- >
- organization.settings
- </Link>
- </li>
- <li>
- <Link
- activeClassName="active"
- onlyActiveOnIndex={false}
- style={Object {}}
- to="/organizations/foo/groups"
- >
- user_groups.page
- </Link>
- </li>
- <li>
- <Link
- activeClassName="active"
- onlyActiveOnIndex={false}
- style={Object {}}
- to="/organizations/foo/permissions"
- >
- permissions.page
- </Link>
- </li>
- <li>
- <Link
- activeClassName="active"
- onlyActiveOnIndex={false}
- style={Object {}}
- to="/organizations/foo/permission_templates"
- >
- permission_templates
- </Link>
- </li>
- <li>
- <Link
- activeClassName="active"
- onlyActiveOnIndex={false}
- style={Object {}}
- to="/organizations/foo/projects_management"
- >
- projects_management
- </Link>
- </li>
- <li>
- <Link
- activeClassName="active"
- onlyActiveOnIndex={false}
- style={Object {}}
- to="/organizations/foo/webhooks"
- >
- webhooks.page
- </Link>
- </li>
- </ul>
- }
- tagName="li"
->
- <a
- className="dropdown-toggle"
- href="#"
- id="organization-navigation-admin"
- >
- layout.settings
- <DropdownIcon
- className="little-spacer-left"
- />
- </a>
-</Dropdown>
-`;
diff --git a/server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/__snapshots__/OrganizationNavigationHeader-test.tsx.snap b/server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/__snapshots__/OrganizationNavigationHeader-test.tsx.snap
deleted file mode 100644
index 0394cb0be1d..00000000000
--- a/server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/__snapshots__/OrganizationNavigationHeader-test.tsx.snap
+++ /dev/null
@@ -1,216 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`renders 1`] = `
-<header
- className="navbar-context-header"
->
- <OrganizationAvatar
- organization={
- Object {
- "key": "foo",
- "name": "Foo",
- "projectVisibility": "public",
- }
- }
- />
- <span
- className="spacer-left"
- >
- Foo
- </span>
-</header>
-`;
-
-exports[`renders dropdown 1`] = `
-<Dropdown
- className="display-inline-block"
- overlay={
- <ul
- className="menu"
- >
- <OrganizationListItem
- organization={
- Object {
- "actions": Object {
- "admin": true,
- },
- "key": "org1",
- "name": "org1",
- "projectVisibility": "public",
- }
- }
- />
- <OrganizationListItem
- organization={
- Object {
- "actions": Object {
- "admin": false,
- },
- "key": "org2",
- "name": "org2",
- "projectVisibility": "public",
- }
- }
- />
- </ul>
- }
->
- <a
- className="display-inline-flex-center spacer-left link-base-color link-no-underline"
- href="#"
- >
- Foo
- <DropdownIcon
- className="little-spacer-left"
- />
- </a>
-</Dropdown>
-`;
-
-exports[`renders for external user w/o alm integration 1`] = `
-<header
- className="navbar-context-header"
->
- <OrganizationAvatar
- organization={
- Object {
- "key": "foo",
- "name": "Foo",
- "projectVisibility": "public",
- }
- }
- />
- <span
- className="spacer-left"
- >
- Foo
- </span>
- <Tooltip
- mouseLeaveDelay={0.25}
- overlay={
- <React.Fragment>
- <p>
- organization.not_bound_to_x.github
- </p>
- </React.Fragment>
- }
- >
- <img
- alt="github"
- className="text-middle spacer-left"
- height={16}
- src="/images/sonarcloud/github-unbound.svg"
- width={16}
- />
- </Tooltip>
-</header>
-`;
-
-exports[`renders with alm integration 1`] = `
-<header
- className="navbar-context-header"
->
- <OrganizationAvatar
- organization={
- Object {
- "alm": Object {
- "key": "github",
- "membersSync": false,
- "personal": false,
- "url": "https://github.com/foo",
- },
- "key": "foo",
- "name": "Foo",
- "projectVisibility": "public",
- }
- }
- />
- <span
- className="spacer-left"
- >
- Foo
- </span>
- <Tooltip
- mouseLeaveDelay={0.25}
- overlay={
- <React.Fragment>
- <p>
- organization.bound_to_x.github
- </p>
- <hr
- className="spacer-top spacer-bottom"
- />
- <a
- href="https://github.com/foo"
- rel="noopener noreferrer"
- target="_blank"
- >
- organization.see_on_x.github
- </a>
- </React.Fragment>
- }
- >
- <img
- alt="github"
- className="text-middle spacer-left"
- height={16}
- src="/images/sonarcloud/github.svg"
- width={16}
- />
- </Tooltip>
-</header>
-`;
-
-exports[`renders with the organization tooltip for an admin user of an organization 1`] = `
-<Tooltip
- mouseLeaveDelay={0.25}
- overlay={
- <React.Fragment>
- <p>
- organization.not_bound_to_x.github
- </p>
- <React.Fragment>
- <hr
- className="spacer-top spacer-bottom"
- />
- <Link
- onlyActiveOnIndex={false}
- style={Object {}}
- to="/organizations/org1/edit"
- >
- organization.go_to_settings_to_bind
- </Link>
- </React.Fragment>
- </React.Fragment>
- }
->
- <img
- alt="github"
- className="text-middle spacer-left"
- height={16}
- src="/images/sonarcloud/github-unbound.svg"
- width={16}
- />
-</Tooltip>
-`;
-
-exports[`renders without the organization tooltip for a non-admin user of an organization 1`] = `
-<Tooltip
- mouseLeaveDelay={0.25}
- overlay={
- <React.Fragment>
- <p>
- organization.not_bound_to_x.github
- </p>
- </React.Fragment>
- }
->
- <img
- alt="github"
- className="text-middle spacer-left"
- height={16}
- src="/images/sonarcloud/github-unbound.svg"
- width={16}
- />
-</Tooltip>
-`;
diff --git a/server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/__snapshots__/OrganizationNavigationMenuContainer-test.tsx.snap b/server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/__snapshots__/OrganizationNavigationMenuContainer-test.tsx.snap
deleted file mode 100644
index 46f062c94ae..00000000000
--- a/server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/__snapshots__/OrganizationNavigationMenuContainer-test.tsx.snap
+++ /dev/null
@@ -1,205 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`renders 1`] = `
-<NavBarTabs
- className="navbar-context-tabs"
->
- <li>
- <Link
- activeClassName="active"
- onlyActiveOnIndex={false}
- style={Object {}}
- to="/organizations/foo/projects"
- >
- projects.page
- </Link>
- </li>
- <li>
- <Link
- activeClassName="active"
- onlyActiveOnIndex={false}
- style={Object {}}
- to={
- Object {
- "pathname": "/organizations/foo/issues",
- "query": Object {
- "resolved": "false",
- },
- }
- }
- >
- issues.page
- </Link>
- </li>
- <li>
- <Link
- activeClassName="active"
- onlyActiveOnIndex={false}
- style={Object {}}
- to="/organizations/foo/quality_profiles"
- >
- quality_profiles.page
- </Link>
- </li>
- <li>
- <Link
- activeClassName="active"
- onlyActiveOnIndex={false}
- style={Object {}}
- to="/organizations/foo/rules"
- >
- coding_rules.page
- </Link>
- </li>
- <li>
- <Link
- activeClassName="active"
- onlyActiveOnIndex={false}
- style={Object {}}
- to={
- Object {
- "pathname": "/organizations/foo/quality_gates",
- }
- }
- >
- quality_gates.page
- </Link>
- </li>
- <li>
- <Link
- activeClassName="active"
- onlyActiveOnIndex={false}
- style={Object {}}
- to="/organizations/foo/members"
- >
- organization.members.page
- </Link>
- </li>
- <OrganizationNavigationExtensions
- location={
- Object {
- "pathname": "",
- }
- }
- organization={
- Object {
- "key": "foo",
- "name": "Foo",
- "projectVisibility": "public",
- }
- }
- />
-</NavBarTabs>
-`;
-
-exports[`renders for admin 1`] = `
-<NavBarTabs
- className="navbar-context-tabs"
->
- <li>
- <Link
- activeClassName="active"
- onlyActiveOnIndex={false}
- style={Object {}}
- to="/organizations/foo/projects"
- >
- projects.page
- </Link>
- </li>
- <li>
- <Link
- activeClassName="active"
- onlyActiveOnIndex={false}
- style={Object {}}
- to={
- Object {
- "pathname": "/organizations/foo/issues",
- "query": Object {
- "resolved": "false",
- },
- }
- }
- >
- issues.page
- </Link>
- </li>
- <li>
- <Link
- activeClassName="active"
- onlyActiveOnIndex={false}
- style={Object {}}
- to="/organizations/foo/quality_profiles"
- >
- quality_profiles.page
- </Link>
- </li>
- <li>
- <Link
- activeClassName="active"
- onlyActiveOnIndex={false}
- style={Object {}}
- to="/organizations/foo/rules"
- >
- coding_rules.page
- </Link>
- </li>
- <li>
- <Link
- activeClassName="active"
- onlyActiveOnIndex={false}
- style={Object {}}
- to={
- Object {
- "pathname": "/organizations/foo/quality_gates",
- }
- }
- >
- quality_gates.page
- </Link>
- </li>
- <li>
- <Link
- activeClassName="active"
- onlyActiveOnIndex={false}
- style={Object {}}
- to="/organizations/foo/members"
- >
- organization.members.page
- </Link>
- </li>
- <OrganizationNavigationExtensions
- location={
- Object {
- "pathname": "",
- }
- }
- organization={
- Object {
- "actions": Object {
- "admin": true,
- },
- "key": "foo",
- "name": "Foo",
- "projectVisibility": "public",
- }
- }
- />
- <OrganizationNavigationAdministration
- location={
- Object {
- "pathname": "",
- }
- }
- organization={
- Object {
- "actions": Object {
- "admin": true,
- },
- "key": "foo",
- "name": "Foo",
- "projectVisibility": "public",
- }
- }
- />
-</NavBarTabs>
-`;
diff --git a/server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/__snapshots__/OrganizationNavigationMeta-test.tsx.snap b/server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/__snapshots__/OrganizationNavigationMeta-test.tsx.snap
deleted file mode 100644
index f70dd859642..00000000000
--- a/server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/__snapshots__/OrganizationNavigationMeta-test.tsx.snap
+++ /dev/null
@@ -1,30 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`renders 1`] = `
-<div
- className="navbar-context-meta"
->
- <div
- className="text-muted"
- >
- <strong>
- organization.key
- :
- </strong>
-
- foo
- </div>
- <div
- className="navbar-context-meta-secondary"
- >
- <Connect(HomePageSelect)
- currentPage={
- Object {
- "organization": "foo",
- "type": "ORGANIZATION",
- }
- }
- />
- </div>
-</div>
-`;
diff --git a/server/sonar-web/src/main/js/apps/organizations/routes.ts b/server/sonar-web/src/main/js/apps/organizations/routes.ts
deleted file mode 100644
index 1efff137c9f..00000000000
--- a/server/sonar-web/src/main/js/apps/organizations/routes.ts
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import { RedirectFunction, RouterState } from 'react-router';
-import { lazyLoadComponent } from 'sonar-ui-common/components/lazyLoadComponent';
-import codingRulesRoutes from '../coding-rules/routes';
-import qualityGatesRoutes from '../quality-gates/routes';
-import qualityProfilesRoutes from '../quality-profiles/routes';
-import webhooksRoutes from '../webhooks/routes';
-
-const OrganizationContainer = lazyLoadComponent(() => import('./components/OrganizationContainer'));
-
-const routes = [
- {
- path: ':organizationKey',
- component: lazyLoadComponent(() => import('./components/OrganizationPage')),
- childRoutes: [
- {
- indexRoute: {
- onEnter(nextState: RouterState, replace: RedirectFunction) {
- const { params } = nextState;
- replace(`/organizations/${params.organizationKey}/projects`);
- }
- }
- },
- {
- path: 'projects',
- component: OrganizationContainer,
- childRoutes: [
- {
- indexRoute: {
- component: lazyLoadComponent(() => import('./components/OrganizationProjects'))
- }
- }
- ]
- },
- {
- path: 'issues',
- component: OrganizationContainer,
- childRoutes: [
- {
- indexRoute: {
- component: lazyLoadComponent(() => import('../issues/components/AppContainer'))
- }
- }
- ]
- },
- {
- path: 'rules',
- component: OrganizationContainer,
- childRoutes: codingRulesRoutes
- },
- {
- path: 'members',
- component: lazyLoadComponent(() =>
- import('../organizationMembers/OrganizationMembersContainer')
- )
- },
- {
- path: 'quality_profiles',
- childRoutes: qualityProfilesRoutes
- },
- {
- path: 'quality_gates',
- component: OrganizationContainer,
- childRoutes: qualityGatesRoutes
- },
- {
- component: lazyLoadComponent(() => import('./components/OrganizationAccessContainer')),
- childRoutes: [
- {
- path: 'edit',
- component: lazyLoadComponent(() => import('./components/OrganizationEdit'))
- },
- {
- path: 'groups',
- component: lazyLoadComponent(() => import('../groups/components/App'))
- },
- {
- path: 'permissions',
- component: lazyLoadComponent(() => import('../permissions/global/components/App'))
- },
- {
- path: 'permission_templates',
- component: lazyLoadComponent(() => import('../permission-templates/components/App'))
- },
- {
- path: 'projects_management',
- component: lazyLoadComponent(() => import('../projectsManagement/AppContainer'))
- },
- { path: 'webhooks', childRoutes: webhooksRoutes },
- {
- path: 'extension/:pluginKey/:extensionKey',
- component: lazyLoadComponent(() =>
- import('../../app/components/extensions/OrganizationPageExtension')
- )
- }
- ]
- }
- ]
- }
-];
-
-export default routes;
diff --git a/server/sonar-web/src/main/js/apps/overview/branches/MeasuresPanelIssueMeasureRow.tsx b/server/sonar-web/src/main/js/apps/overview/branches/MeasuresPanelIssueMeasureRow.tsx
index a1c1d291cd1..965132f2536 100644
--- a/server/sonar-web/src/main/js/apps/overview/branches/MeasuresPanelIssueMeasureRow.tsx
+++ b/server/sonar-web/src/main/js/apps/overview/branches/MeasuresPanelIssueMeasureRow.tsx
@@ -18,6 +18,7 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import * as React from 'react';
+import { translate } from 'sonar-ui-common/helpers/l10n';
import { BranchLike } from '../../../types/branch-like';
import { ComponentQualifier } from '../../../types/component';
import { IssueType } from '../../../types/issues';
@@ -68,9 +69,9 @@ export default function MeasuresPanelIssueMeasureRow(props: MeasuresPanelIssueMe
<IssueLabel
branchLike={branchLike}
component={component}
- docTooltip={
+ helpTooltip={
type === IssueType.SecurityHotspot
- ? import(/* webpackMode: "eager" */ 'Docs/tooltips/metrics/security-hotspots.md')
+ ? translate('metric.security_hotspots.full_description')
: undefined
}
measures={measures}
diff --git a/server/sonar-web/src/main/js/apps/overview/branches/QualityGatePanel.tsx b/server/sonar-web/src/main/js/apps/overview/branches/QualityGatePanel.tsx
index a6397861005..790c6cde485 100644
--- a/server/sonar-web/src/main/js/apps/overview/branches/QualityGatePanel.tsx
+++ b/server/sonar-web/src/main/js/apps/overview/branches/QualityGatePanel.tsx
@@ -23,7 +23,6 @@ import HelpTooltip from 'sonar-ui-common/components/controls/HelpTooltip';
import { Alert } from 'sonar-ui-common/components/ui/Alert';
import DeferredSpinner from 'sonar-ui-common/components/ui/DeferredSpinner';
import { translate, translateWithParameters } from 'sonar-ui-common/helpers/l10n';
-import DocTooltip from '../../../components/docs/DocTooltip';
import { QualityGateStatus } from '../../../types/quality-gates';
import QualityGatePanelSection from './QualityGatePanelSection';
@@ -57,11 +56,13 @@ export function QualityGatePanel(props: QualityGatePanelProps) {
<div className="overview-panel" data-test="overview__quality-gate-panel">
<h2 className="overview-panel-title display-inline-flex-center">
{translate('overview.quality_gate')}{' '}
- <DocTooltip
+ <HelpTooltip
className="little-spacer-left"
- doc={import(
- /* webpackMode: "eager" */ 'Docs/tooltips/quality-gates/project-homepage-quality-gate.md'
- )}
+ overlay={
+ <div className="big-padded-top big-padded-bottom">
+ {translate('overview.quality_gate.help')}
+ </div>
+ }
/>
</h2>
diff --git a/server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/MeasuresPanelIssueMeasureRow-test.tsx.snap b/server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/MeasuresPanelIssueMeasureRow-test.tsx.snap
index 39b67ec8b20..14229e28720 100644
--- a/server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/MeasuresPanelIssueMeasureRow-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/MeasuresPanelIssueMeasureRow-test.tsx.snap
@@ -927,7 +927,7 @@ exports[`should render correctly for projects: Hotspot 1`] = `
"tags": Array [],
}
}
- docTooltip={Promise {}}
+ helpTooltip="metric.security_hotspots.full_description"
measures={
Array [
Object {
diff --git a/server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/QualityGatePanel-test.tsx.snap b/server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/QualityGatePanel-test.tsx.snap
index 1e720788806..e9ae25c6488 100644
--- a/server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/QualityGatePanel-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/QualityGatePanel-test.tsx.snap
@@ -10,9 +10,15 @@ exports[`should render correctly for applications 1`] = `
>
overview.quality_gate
- <DocTooltip
+ <HelpTooltip
className="little-spacer-left"
- doc={Promise {}}
+ overlay={
+ <div
+ className="big-padded-top big-padded-bottom"
+ >
+ overview.quality_gate.help
+ </div>
+ }
/>
</h2>
<div
@@ -191,9 +197,15 @@ exports[`should render correctly for applications 2`] = `
>
overview.quality_gate
- <DocTooltip
+ <HelpTooltip
className="little-spacer-left"
- doc={Promise {}}
+ overlay={
+ <div
+ className="big-padded-top big-padded-bottom"
+ >
+ overview.quality_gate.help
+ </div>
+ }
/>
</h2>
<div
@@ -325,9 +337,15 @@ exports[`should render correctly for projects 1`] = `
>
overview.quality_gate
- <DocTooltip
+ <HelpTooltip
className="little-spacer-left"
- doc={Promise {}}
+ overlay={
+ <div
+ className="big-padded-top big-padded-bottom"
+ >
+ overview.quality_gate.help
+ </div>
+ }
/>
</h2>
<div
@@ -424,9 +442,15 @@ exports[`should render correctly for projects 2`] = `
>
overview.quality_gate
- <DocTooltip
+ <HelpTooltip
className="little-spacer-left"
- doc={Promise {}}
+ overlay={
+ <div
+ className="big-padded-top big-padded-bottom"
+ >
+ overview.quality_gate.help
+ </div>
+ }
/>
</h2>
<div
@@ -460,9 +484,15 @@ exports[`should render correctly for projects 3`] = `
>
overview.quality_gate
- <DocTooltip
+ <HelpTooltip
className="little-spacer-left"
- doc={Promise {}}
+ overlay={
+ <div
+ className="big-padded-top big-padded-bottom"
+ >
+ overview.quality_gate.help
+ </div>
+ }
/>
</h2>
<Alert
diff --git a/server/sonar-web/src/main/js/apps/overview/components/IssueLabel.tsx b/server/sonar-web/src/main/js/apps/overview/components/IssueLabel.tsx
index f2c86205aa6..efe265073f9 100644
--- a/server/sonar-web/src/main/js/apps/overview/components/IssueLabel.tsx
+++ b/server/sonar-web/src/main/js/apps/overview/components/IssueLabel.tsx
@@ -19,9 +19,9 @@
*/
import * as React from 'react';
import { Link } from 'react-router';
+import HelpTooltip from 'sonar-ui-common/components/controls/HelpTooltip';
import { translate } from 'sonar-ui-common/helpers/l10n';
import { formatMeasure, localizeMetric } from 'sonar-ui-common/helpers/measures';
-import DocTooltip from '../../../components/docs/DocTooltip';
import { getLeakValue } from '../../../components/measure/utils';
import { getBranchLikeQuery } from '../../../helpers/branch-like';
import { findMeasure } from '../../../helpers/measures';
@@ -33,14 +33,14 @@ import { getIssueIconClass, getIssueMetricKey } from '../utils';
export interface IssueLabelProps {
branchLike?: BranchLike;
component: T.Component;
- docTooltip?: Promise<{ default: string }>;
+ helpTooltip?: string;
measures: T.MeasureEnhanced[];
type: IssueType;
useDiffMetric?: boolean;
}
export function IssueLabel(props: IssueLabelProps) {
- const { branchLike, component, docTooltip, measures, type, useDiffMetric = false } = props;
+ const { branchLike, component, helpTooltip, measures, type, useDiffMetric = false } = props;
const metric = getIssueMetricKey(type, useDiffMetric);
const measure = findMeasure(measures, metric);
const iconClass = getIssueIconClass(type);
@@ -74,7 +74,7 @@ export function IssueLabel(props: IssueLabelProps) {
)}
{React.createElement(iconClass, { className: 'big-spacer-left little-spacer-right' })}
{localizeMetric(metric)}
- {docTooltip && <DocTooltip className="little-spacer-left" doc={docTooltip} />}
+ {helpTooltip && <HelpTooltip className="little-spacer-left" overlay={helpTooltip} />}
</>
);
}
diff --git a/server/sonar-web/src/main/js/apps/overview/components/__tests__/IssueLabel-test.tsx b/server/sonar-web/src/main/js/apps/overview/components/__tests__/IssueLabel-test.tsx
index 40f07a5621c..fb9e2f09513 100644
--- a/server/sonar-web/src/main/js/apps/overview/components/__tests__/IssueLabel-test.tsx
+++ b/server/sonar-web/src/main/js/apps/overview/components/__tests__/IssueLabel-test.tsx
@@ -55,7 +55,7 @@ it('should render correctly for vulnerabilities', () => {
});
it('should render correctly for hotspots', () => {
- const docTooltip = Promise.resolve({ default: 'tooltip text' });
+ const helpTooltip = 'tooltip text';
const type = IssueType.SecurityHotspot;
const measures = [
mockMeasureEnhanced({ metric: mockMetric({ key: MetricKey.security_hotspots }) }),
@@ -63,14 +63,14 @@ it('should render correctly for hotspots', () => {
];
expect(
shallowRender({
- docTooltip,
+ helpTooltip,
measures,
type
})
).toMatchSnapshot();
expect(
shallowRender({
- docTooltip,
+ helpTooltip,
measures,
type,
useDiffMetric: true
diff --git a/server/sonar-web/src/main/js/apps/overview/components/__tests__/__snapshots__/IssueLabel-test.tsx.snap b/server/sonar-web/src/main/js/apps/overview/components/__tests__/__snapshots__/IssueLabel-test.tsx.snap
index 39ca9c58551..7a16e77ae4e 100644
--- a/server/sonar-web/src/main/js/apps/overview/components/__tests__/__snapshots__/IssueLabel-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/overview/components/__tests__/__snapshots__/IssueLabel-test.tsx.snap
@@ -139,9 +139,9 @@ exports[`should render correctly for hotspots 1`] = `
className="big-spacer-left little-spacer-right"
/>
metric.security_hotspots.name
- <DocTooltip
+ <HelpTooltip
className="little-spacer-left"
- doc={Promise {}}
+ overlay="tooltip text"
/>
</Fragment>
`;
@@ -173,9 +173,9 @@ exports[`should render correctly for hotspots 2`] = `
className="big-spacer-left little-spacer-right"
/>
metric.new_security_hotspots.name
- <DocTooltip
+ <HelpTooltip
className="little-spacer-left"
- doc={Promise {}}
+ overlay="tooltip text"
/>
</Fragment>
`;
diff --git a/server/sonar-web/src/main/js/apps/overview/pullRequests/PullRequestOverview.tsx b/server/sonar-web/src/main/js/apps/overview/pullRequests/PullRequestOverview.tsx
index df49eb32417..a1133a223f9 100644
--- a/server/sonar-web/src/main/js/apps/overview/pullRequests/PullRequestOverview.tsx
+++ b/server/sonar-web/src/main/js/apps/overview/pullRequests/PullRequestOverview.tsx
@@ -26,7 +26,6 @@ import { Alert } from 'sonar-ui-common/components/ui/Alert';
import { translate } from 'sonar-ui-common/helpers/l10n';
import { isDefined } from 'sonar-ui-common/helpers/types';
import { getMeasuresWithMetrics } from '../../../api/measures';
-import DocTooltip from '../../../components/docs/DocTooltip';
import { getBranchLikeQuery } from '../../../helpers/branch-like';
import { enhanceConditionWithMeasure, enhanceMeasuresWithMetrics } from '../../../helpers/measures';
import { fetchBranchStatus } from '../../../store/rootActions';
@@ -186,13 +185,15 @@ export class PullRequestOverview extends React.PureComponent<Props, State> {
)}
<div className="display-flex-row">
<div className="big-spacer-right">
- <h2 className="overview-panel-title spacer-bottom small">
+ <h2 className="overview-panel-title spacer-bottom small display-inline-flex-center">
{translate('overview.quality_gate')}
- <DocTooltip
- className="spacer-left"
- doc={import(
- /* webpackMode: "eager" */ 'Docs/tooltips/quality-gates/project-homepage-quality-gate.md'
- )}
+ <HelpTooltip
+ className="little-spacer-left"
+ overlay={
+ <div className="big-padded-top big-padded-bottom">
+ {translate('overview.quality_gate.help')}
+ </div>
+ }
/>
</h2>
<LargeQualityGateBadge component={component} level={status} />
diff --git a/server/sonar-web/src/main/js/apps/overview/pullRequests/__tests__/__snapshots__/PullRequestOverview-test.tsx.snap b/server/sonar-web/src/main/js/apps/overview/pullRequests/__tests__/__snapshots__/PullRequestOverview-test.tsx.snap
index 1ba05b2bde0..1d0e382c8ba 100644
--- a/server/sonar-web/src/main/js/apps/overview/pullRequests/__tests__/__snapshots__/PullRequestOverview-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/overview/pullRequests/__tests__/__snapshots__/PullRequestOverview-test.tsx.snap
@@ -14,12 +14,18 @@ exports[`should render correctly for a failed QG 1`] = `
className="big-spacer-right"
>
<h2
- className="overview-panel-title spacer-bottom small"
+ className="overview-panel-title spacer-bottom small display-inline-flex-center"
>
overview.quality_gate
- <DocTooltip
- className="spacer-left"
- doc={Promise {}}
+ <HelpTooltip
+ className="little-spacer-left"
+ overlay={
+ <div
+ className="big-padded-top big-padded-bottom"
+ >
+ overview.quality_gate.help
+ </div>
+ }
/>
</h2>
<Memo(LargeQualityGateBadge)
@@ -1369,12 +1375,18 @@ exports[`should render correctly for a passed QG 1`] = `
className="big-spacer-right"
>
<h2
- className="overview-panel-title spacer-bottom small"
+ className="overview-panel-title spacer-bottom small display-inline-flex-center"
>
overview.quality_gate
- <DocTooltip
- className="spacer-left"
- doc={Promise {}}
+ <HelpTooltip
+ className="little-spacer-left"
+ overlay={
+ <div
+ className="big-padded-top big-padded-bottom"
+ >
+ overview.quality_gate.help
+ </div>
+ }
/>
</h2>
<Memo(LargeQualityGateBadge)
diff --git a/server/sonar-web/src/main/js/apps/permissions/project/components/App.tsx b/server/sonar-web/src/main/js/apps/permissions/project/components/App.tsx
index 586e1503a1e..c76000ebf5b 100644
--- a/server/sonar-web/src/main/js/apps/permissions/project/components/App.tsx
+++ b/server/sonar-web/src/main/js/apps/permissions/project/components/App.tsx
@@ -23,7 +23,6 @@ import { Helmet } from 'react-helmet-async';
import { translate } from 'sonar-ui-common/helpers/l10n';
import * as api from '../../../../api/permissions';
import VisibilitySelector from '../../../../components/common/VisibilitySelector';
-import UpgradeOrganizationBox from '../../../create/components/UpgradeOrganizationBox';
import '../../styles.css';
import AllHoldersList from './AllHoldersList';
import PageHeader from './PageHeader';
@@ -31,9 +30,7 @@ import PublicProjectDisclaimer from './PublicProjectDisclaimer';
interface Props {
component: T.Component;
- fetchOrganization: (organization: string) => void;
onComponentChange: (changes: Partial<T.Component>) => void;
- organization?: T.Organization;
}
interface State {
@@ -88,7 +85,6 @@ export default class App extends React.PureComponent<Props, State> {
projectKey: component.key,
q: query || undefined,
permission: selectedPermission,
- organization: component.organization,
p: userPage
})
: Promise.resolve({ paging: undefined, users: [] });
@@ -99,7 +95,6 @@ export default class App extends React.PureComponent<Props, State> {
projectKey: component.key,
q: query || undefined,
permission: selectedPermission,
- organization: component.organization,
p: groupsPage
})
: Promise.resolve({ paging: undefined, groups: [] });
@@ -207,8 +202,7 @@ export default class App extends React.PureComponent<Props, State> {
.grantPermissionToGroup({
projectKey: this.props.component.key,
groupName: group,
- permission,
- organization: this.props.component.organization
+ permission
})
.then(this.stopLoading, () => {
if (this.mounted) {
@@ -232,8 +226,7 @@ export default class App extends React.PureComponent<Props, State> {
.grantPermissionToUser({
projectKey: this.props.component.key,
login: user,
- permission,
- organization: this.props.component.organization
+ permission
})
.then(this.stopLoading, () => {
if (this.mounted) {
@@ -257,8 +250,7 @@ export default class App extends React.PureComponent<Props, State> {
.revokePermissionFromGroup({
projectKey: this.props.component.key,
groupName: group,
- permission,
- organization: this.props.component.organization
+ permission
})
.then(this.stopLoading, () => {
if (this.mounted) {
@@ -282,8 +274,7 @@ export default class App extends React.PureComponent<Props, State> {
.revokePermissionFromUser({
projectKey: this.props.component.key,
login: user,
- permission,
- organization: this.props.component.organization
+ permission
})
.then(this.stopLoading, () => {
if (this.mounted) {
@@ -297,16 +288,6 @@ export default class App extends React.PureComponent<Props, State> {
return Promise.resolve();
};
- handleOrganizationUpgrade = () => {
- const { component, organization } = this.props;
- if (organization) {
- this.props.onComponentChange({
- configuration: { ...component.configuration, canUpdateProjectVisibilityToPrivate: true }
- });
- this.props.fetchOrganization(organization.key);
- }
- };
-
handleVisibilityChange = (visibility: string) => {
if (visibility === 'public') {
this.openDisclaimer();
@@ -356,19 +337,10 @@ export default class App extends React.PureComponent<Props, State> {
};
render() {
- const { component, organization } = this.props;
+ const { component } = this.props;
const canTurnToPrivate =
component.configuration && component.configuration.canUpdateProjectVisibilityToPrivate;
- let showUpgradeBox;
- if (organization && !canTurnToPrivate) {
- const isOrgAdmin = organization.actions && organization.actions.admin;
- showUpgradeBox =
- isOrgAdmin &&
- this.props.component.qualifier === 'TRK' &&
- !organization.canUpdateProjectsVisibilityToPrivate;
- }
-
return (
<div className="page page-limited" id="project-permissions-page">
<Helmet defer={false} title={translate('permissions.page')} />
@@ -385,13 +357,6 @@ export default class App extends React.PureComponent<Props, State> {
onChange={this.handleVisibilityChange}
visibility={component.visibility}
/>
- {showUpgradeBox && organization && (
- <UpgradeOrganizationBox
- className="big-spacer-bottom"
- onOrganizationUpgrade={this.handleOrganizationUpgrade}
- organization={organization}
- />
- )}
{this.state.disclaimer && (
<PublicProjectDisclaimer
component={component}
diff --git a/server/sonar-web/src/main/js/apps/permissions/project/components/AppContainer.ts b/server/sonar-web/src/main/js/apps/permissions/project/components/AppContainer.ts
index e69f476a356..83c89b028a5 100644
--- a/server/sonar-web/src/main/js/apps/permissions/project/components/AppContainer.ts
+++ b/server/sonar-web/src/main/js/apps/permissions/project/components/AppContainer.ts
@@ -18,20 +18,11 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import { connect } from 'react-redux';
-import { fetchOrganization } from '../../../../store/rootActions';
-import { getCurrentUser, getOrganizationByKey, Store } from '../../../../store/rootReducer';
+import { getCurrentUser, Store } from '../../../../store/rootReducer';
import App from './App';
-interface OwnProps {
- component: T.Component;
- onComponentChange: (changes: Partial<T.Component>) => void;
-}
-
-const mapStateToProps = (state: Store, { component }: OwnProps) => ({
- currentUser: getCurrentUser(state),
- organization: getOrganizationByKey(state, component.organization)
+const mapStateToProps = (state: Store) => ({
+ currentUser: getCurrentUser(state)
});
-const mapDispatchToProps = { fetchOrganization };
-
-export default connect(mapStateToProps, mapDispatchToProps)(App);
+export default connect(mapStateToProps)(App);
diff --git a/server/sonar-web/src/main/js/apps/permissions/project/components/__tests__/App-test.tsx b/server/sonar-web/src/main/js/apps/permissions/project/components/__tests__/App-test.tsx
index 9e88b16affe..70e03bfd265 100644
--- a/server/sonar-web/src/main/js/apps/permissions/project/components/__tests__/App-test.tsx
+++ b/server/sonar-web/src/main/js/apps/permissions/project/components/__tests__/App-test.tsx
@@ -26,7 +26,7 @@ import {
revokePermissionFromGroup,
revokePermissionFromUser
} from '../../../../../api/permissions';
-import { mockComponent, mockOrganization } from '../../../../../helpers/testMocks';
+import { mockComponent } from '../../../../../helpers/testMocks';
import App from '../App';
jest.mock('../../../../../api/permissions', () => ({
@@ -98,8 +98,7 @@ describe('should manage state correctly', () => {
const apiPayload = {
projectKey: 'my-project',
groupName: 'Anyone',
- permission: 'foo',
- organization: 'foo'
+ permission: 'foo'
};
instance.grantPermissionToGroup('Anyone', 'foo');
@@ -132,8 +131,7 @@ describe('should manage state correctly', () => {
const apiPayload = {
projectKey: 'my-project',
login: 'user1',
- permission: 'foo',
- organization: 'foo'
+ permission: 'foo'
};
instance.grantPermissionToUser('user1', 'foo');
@@ -150,13 +148,5 @@ describe('should manage state correctly', () => {
});
function shallowRender(props: Partial<App['props']> = {}) {
- return shallow<App>(
- <App
- component={mockComponent()}
- fetchOrganization={jest.fn()}
- onComponentChange={jest.fn()}
- organization={mockOrganization()}
- {...props}
- />
- );
+ return shallow<App>(<App component={mockComponent()} onComponentChange={jest.fn()} {...props} />);
}
diff --git a/server/sonar-web/src/main/js/apps/projectQualityGate/Header.tsx b/server/sonar-web/src/main/js/apps/projectQualityGate/Header.tsx
index 220d6be9e5c..d2fee01125e 100644
--- a/server/sonar-web/src/main/js/apps/projectQualityGate/Header.tsx
+++ b/server/sonar-web/src/main/js/apps/projectQualityGate/Header.tsx
@@ -18,19 +18,21 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import * as React from 'react';
+import HelpTooltip from 'sonar-ui-common/components/controls/HelpTooltip';
import { translate } from 'sonar-ui-common/helpers/l10n';
-import DocTooltip from '../../components/docs/DocTooltip';
export default function Header() {
return (
<header className="page-header">
<div className="page-title display-flex-center">
<h1>{translate('project_quality_gate.page')}</h1>
- <DocTooltip
+ <HelpTooltip
className="spacer-left"
- doc={import(
- /* webpackMode: "eager" */ 'Docs/tooltips/quality-gates/quality-gate-projects.md'
- )}
+ overlay={
+ <div className="big-padded-top big-padded-bottom">
+ {translate('quality_gates.projects.help')}
+ </div>
+ }
/>
</div>
<div className="page-description">{translate('project_quality_gate.page.description')}</div>
diff --git a/server/sonar-web/src/main/js/apps/projectQualityGate/__tests__/__snapshots__/Header-test.tsx.snap b/server/sonar-web/src/main/js/apps/projectQualityGate/__tests__/__snapshots__/Header-test.tsx.snap
index bcc91125263..234232fc945 100644
--- a/server/sonar-web/src/main/js/apps/projectQualityGate/__tests__/__snapshots__/Header-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/projectQualityGate/__tests__/__snapshots__/Header-test.tsx.snap
@@ -10,9 +10,15 @@ exports[`renders 1`] = `
<h1>
project_quality_gate.page
</h1>
- <DocTooltip
+ <HelpTooltip
className="spacer-left"
- doc={Promise {}}
+ overlay={
+ <div
+ className="big-padded-top big-padded-bottom"
+ >
+ quality_gates.projects.help
+ </div>
+ }
/>
</div>
<div
diff --git a/server/sonar-web/src/main/js/apps/projectQualityProfiles/Header.tsx b/server/sonar-web/src/main/js/apps/projectQualityProfiles/Header.tsx
index 610686aec8d..10f8741af9b 100644
--- a/server/sonar-web/src/main/js/apps/projectQualityProfiles/Header.tsx
+++ b/server/sonar-web/src/main/js/apps/projectQualityProfiles/Header.tsx
@@ -18,19 +18,21 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import * as React from 'react';
+import HelpTooltip from 'sonar-ui-common/components/controls/HelpTooltip';
import { translate } from 'sonar-ui-common/helpers/l10n';
-import DocTooltip from '../../components/docs/DocTooltip';
export default function Header() {
return (
<header className="page-header">
<div className="page-title display-flex-center">
<h1>{translate('project_quality_profiles.page')}</h1>
- <DocTooltip
+ <HelpTooltip
className="spacer-left"
- doc={import(
- /* webpackMode: "eager" */ 'Docs/tooltips/quality-profiles/quality-profile-projects.md'
- )}
+ overlay={
+ <div className="big-padded-top big-padded-bottom">
+ {translate('quality_profiles.list.projects.help')}
+ </div>
+ }
/>
</div>
<div className="page-description">
diff --git a/server/sonar-web/src/main/js/apps/projectQualityProfiles/__tests__/__snapshots__/Header-test.tsx.snap b/server/sonar-web/src/main/js/apps/projectQualityProfiles/__tests__/__snapshots__/Header-test.tsx.snap
index b59e95a99e2..6ab35969262 100644
--- a/server/sonar-web/src/main/js/apps/projectQualityProfiles/__tests__/__snapshots__/Header-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/projectQualityProfiles/__tests__/__snapshots__/Header-test.tsx.snap
@@ -10,9 +10,15 @@ exports[`renders 1`] = `
<h1>
project_quality_profiles.page
</h1>
- <DocTooltip
+ <HelpTooltip
className="spacer-left"
- doc={Promise {}}
+ overlay={
+ <div
+ className="big-padded-top big-padded-bottom"
+ >
+ quality_profiles.list.projects.help
+ </div>
+ }
/>
</div>
<div
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 368695adb41..8d69cf678bf 100644
--- a/server/sonar-web/src/main/js/apps/projectsManagement/CreateProjectForm.tsx
+++ b/server/sonar-web/src/main/js/apps/projectsManagement/CreateProjectForm.tsx
@@ -27,7 +27,6 @@ import { translate } from 'sonar-ui-common/helpers/l10n';
import { createProject } from '../../api/components';
import VisibilitySelector from '../../components/common/VisibilitySelector';
import { getProjectUrl } from '../../helpers/urls';
-import UpgradeOrganizationBox from '../create/components/UpgradeOrganizationBox';
interface Props {
onClose: () => void;
@@ -196,18 +195,6 @@ export default class CreateProjectForm extends React.PureComponent<Props, State>
visibility={this.state.visibility}
/>
</div>
- {organization.actions &&
- organization.actions.admin &&
- !organization.canUpdateProjectsVisibilityToPrivate && (
- <div className="spacer-top">
- <UpgradeOrganizationBox
- className="width-100"
- insideModal={true}
- onOrganizationUpgrade={this.props.onOrganizationUpgrade}
- organization={organization}
- />
- </div>
- )}
</div>
<footer className="modal-foot">
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 9879d2fd163..bf16aa754b7 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
@@ -78,25 +78,6 @@ exports[`creates project 1`] = `
visibility="public"
/>
</div>
- <div
- className="spacer-top"
- >
- <UpgradeOrganizationBox
- className="width-100"
- insideModal={true}
- onOrganizationUpgrade={[MockFunction]}
- organization={
- Object {
- "actions": Object {
- "admin": true,
- },
- "key": "org",
- "name": "org",
- "projectVisibility": "public",
- }
- }
- />
- </div>
</div>
<footer
className="modal-foot"
@@ -196,25 +177,6 @@ exports[`creates project 2`] = `
visibility="private"
/>
</div>
- <div
- className="spacer-top"
- >
- <UpgradeOrganizationBox
- className="width-100"
- insideModal={true}
- onOrganizationUpgrade={[MockFunction]}
- organization={
- Object {
- "actions": Object {
- "admin": true,
- },
- "key": "org",
- "name": "org",
- "projectVisibility": "public",
- }
- }
- />
- </div>
</div>
<footer
className="modal-foot"
@@ -314,25 +276,6 @@ exports[`creates project 3`] = `
visibility="private"
/>
</div>
- <div
- className="spacer-top"
- >
- <UpgradeOrganizationBox
- className="width-100"
- insideModal={true}
- onOrganizationUpgrade={[MockFunction]}
- organization={
- Object {
- "actions": Object {
- "admin": true,
- },
- "key": "org",
- "name": "org",
- "projectVisibility": "public",
- }
- }
- />
- </div>
</div>
<footer
className="modal-foot"
diff --git a/server/sonar-web/src/main/js/apps/quality-gates/components/BuiltInQualityGateBadge.tsx b/server/sonar-web/src/main/js/apps/quality-gates/components/BuiltInQualityGateBadge.tsx
index b0a7b2a8c7f..b83d4572a43 100644
--- a/server/sonar-web/src/main/js/apps/quality-gates/components/BuiltInQualityGateBadge.tsx
+++ b/server/sonar-web/src/main/js/apps/quality-gates/components/BuiltInQualityGateBadge.tsx
@@ -19,8 +19,8 @@
*/
import * as classNames from 'classnames';
import * as React from 'react';
+import Tooltip from 'sonar-ui-common/components/controls/Tooltip';
import { translate } from 'sonar-ui-common/helpers/l10n';
-import DocTooltip from '../../../components/docs/DocTooltip';
interface Props {
className?: string;
@@ -28,11 +28,8 @@ interface Props {
export default function BuiltInQualityGateBadge({ className }: Props) {
return (
- <DocTooltip
- doc={import(
- /* webpackMode: "eager" */ 'Docs/tooltips/quality-gates/built-in-quality-gate.md'
- )}>
+ <Tooltip overlay={translate('quality_gates.built_in.help')}>
<div className={classNames('badge', className)}>{translate('quality_gates.built_in')}</div>
- </DocTooltip>
+ </Tooltip>
);
}
diff --git a/server/sonar-web/src/main/js/apps/quality-gates/components/Conditions.tsx b/server/sonar-web/src/main/js/apps/quality-gates/components/Conditions.tsx
index b7385ef07f7..d90c53ebe2a 100644
--- a/server/sonar-web/src/main/js/apps/quality-gates/components/Conditions.tsx
+++ b/server/sonar-web/src/main/js/apps/quality-gates/components/Conditions.tsx
@@ -24,7 +24,7 @@ import ModalButton from 'sonar-ui-common/components/controls/ModalButton';
import { Alert } from 'sonar-ui-common/components/ui/Alert';
import { getLocalizedMetricName, translate } from 'sonar-ui-common/helpers/l10n';
import { isDiffMetric } from 'sonar-ui-common/helpers/measures';
-import DocTooltip from '../../../components/docs/DocTooltip';
+import DocumentationTooltip from '../../../components/common/DocumentationTooltip';
import { withAppState } from '../../../components/hoc/withAppState';
import { MetricKey } from '../../../types/metrics';
import Condition from './Condition';
@@ -165,11 +165,15 @@ export class Conditions extends React.PureComponent<Props> {
<header className="display-flex-center spacer-bottom">
<h3>{translate('quality_gates.conditions')}</h3>
- <DocTooltip
+ <DocumentationTooltip
className="spacer-left"
- doc={import(
- /* webpackMode: "eager" */ 'Docs/tooltips/quality-gates/quality-gate-conditions.md'
- )}
+ content={translate('quality_gates.conditions.help')}
+ links={[
+ {
+ href: '/documentation/user-guide/clean-as-you-code/',
+ label: translate('quality_gates.conditions.help.link')
+ }
+ ]}
/>
</header>
diff --git a/server/sonar-web/src/main/js/apps/quality-gates/components/DetailsContent.tsx b/server/sonar-web/src/main/js/apps/quality-gates/components/DetailsContent.tsx
index 1c45dfad50a..5966b0cb1bc 100644
--- a/server/sonar-web/src/main/js/apps/quality-gates/components/DetailsContent.tsx
+++ b/server/sonar-web/src/main/js/apps/quality-gates/components/DetailsContent.tsx
@@ -18,8 +18,8 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import * as React from 'react';
+import HelpTooltip from 'sonar-ui-common/components/controls/HelpTooltip';
import { translate } from 'sonar-ui-common/helpers/l10n';
-import DocTooltip from '../../../components/docs/DocTooltip';
import Conditions from './Conditions';
import Projects from './Projects';
@@ -56,11 +56,13 @@ export function DetailsContent(props: DetailsContentProps) {
<div className="quality-gate-section" id="quality-gate-projects">
<header className="display-flex-center spacer-bottom">
<h3>{translate('quality_gates.projects')}</h3>
- <DocTooltip
+ <HelpTooltip
className="spacer-left"
- doc={import(
- /* webpackMode: "eager" */ 'Docs/tooltips/quality-gates/quality-gate-projects.md'
- )}
+ overlay={
+ <div className="big-padded-top big-padded-bottom">
+ {translate('quality_gates.projects.help')}
+ </div>
+ }
/>
</header>
{isDefault ? (
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 f9858b45947..8fc6c24c0b3 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
@@ -21,7 +21,7 @@ import * as React from 'react';
import { Button } from 'sonar-ui-common/components/controls/buttons';
import ModalButton from 'sonar-ui-common/components/controls/ModalButton';
import { translate } from 'sonar-ui-common/helpers/l10n';
-import DocTooltip from '../../../components/docs/DocTooltip';
+import DocumentationTooltip from '../../../components/common/DocumentationTooltip';
import CreateQualityGateForm from './CreateQualityGateForm';
interface Props {
@@ -54,9 +54,15 @@ export default function ListHeader({ canCreate, refreshQualityGates, organizatio
<div className="display-flex-center">
<h1 className="page-title">{translate('quality_gates.page')}</h1>
- <DocTooltip
+ <DocumentationTooltip
className="spacer-left"
- doc={import(/* webpackMode: "eager" */ 'Docs/tooltips/quality-gates/quality-gate.md')}
+ content={translate('quality_gates.help')}
+ links={[
+ {
+ href: '/documentation/user-guide/quality-gates/',
+ label: translate('learn_more')
+ }
+ ]}
/>
</div>
</header>
diff --git a/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/__snapshots__/BuiltInQualityGateBadge-test.tsx.snap b/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/__snapshots__/BuiltInQualityGateBadge-test.tsx.snap
index 76f55d531f8..04bf352dbe8 100644
--- a/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/__snapshots__/BuiltInQualityGateBadge-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/__snapshots__/BuiltInQualityGateBadge-test.tsx.snap
@@ -1,13 +1,13 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`should render correctly 1`] = `
-<DocTooltip
- doc={Promise {}}
+<Tooltip
+ overlay="quality_gates.built_in.help"
>
<div
className="badge"
>
quality_gates.built_in
</div>
-</DocTooltip>
+</Tooltip>
`;
diff --git a/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/__snapshots__/Conditions-test.tsx.snap b/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/__snapshots__/Conditions-test.tsx.snap
index 14bf9466228..cb7ff83d304 100644
--- a/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/__snapshots__/Conditions-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/__snapshots__/Conditions-test.tsx.snap
@@ -10,9 +10,17 @@ exports[`should render correctly 1`] = `
<h3>
quality_gates.conditions
</h3>
- <DocTooltip
+ <DocumentationTooltip
className="spacer-left"
- doc={Promise {}}
+ content="quality_gates.conditions.help"
+ links={
+ Array [
+ Object {
+ "href": "/documentation/user-guide/clean-as-you-code/",
+ "label": "quality_gates.conditions.help.link",
+ },
+ ]
+ }
/>
</header>
<div
@@ -129,9 +137,17 @@ exports[`should render correctly for no conditions 1`] = `
<h3>
quality_gates.conditions
</h3>
- <DocTooltip
+ <DocumentationTooltip
className="spacer-left"
- doc={Promise {}}
+ content="quality_gates.conditions.help"
+ links={
+ Array [
+ Object {
+ "href": "/documentation/user-guide/clean-as-you-code/",
+ "label": "quality_gates.conditions.help.link",
+ },
+ ]
+ }
/>
</header>
<div
@@ -152,9 +168,17 @@ exports[`should render correctly with an updated condition 1`] = `
<h3>
quality_gates.conditions
</h3>
- <DocTooltip
+ <DocumentationTooltip
className="spacer-left"
- doc={Promise {}}
+ content="quality_gates.conditions.help"
+ links={
+ Array [
+ Object {
+ "href": "/documentation/user-guide/clean-as-you-code/",
+ "label": "quality_gates.conditions.help.link",
+ },
+ ]
+ }
/>
</header>
<div
@@ -271,9 +295,17 @@ exports[`should render correctly with new code conditions 1`] = `
<h3>
quality_gates.conditions
</h3>
- <DocTooltip
+ <DocumentationTooltip
className="spacer-left"
- doc={Promise {}}
+ content="quality_gates.conditions.help"
+ links={
+ Array [
+ Object {
+ "href": "/documentation/user-guide/clean-as-you-code/",
+ "label": "quality_gates.conditions.help.link",
+ },
+ ]
+ }
/>
</header>
<div
@@ -500,9 +532,17 @@ exports[`should render the add conditions button and modal 1`] = `
<h3>
quality_gates.conditions
</h3>
- <DocTooltip
+ <DocumentationTooltip
className="spacer-left"
- doc={Promise {}}
+ content="quality_gates.conditions.help"
+ links={
+ Array [
+ Object {
+ "href": "/documentation/user-guide/clean-as-you-code/",
+ "label": "quality_gates.conditions.help.link",
+ },
+ ]
+ }
/>
</header>
<div
diff --git a/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/__snapshots__/DetailsContent-test.tsx.snap b/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/__snapshots__/DetailsContent-test.tsx.snap
index c98a62ada70..59ba0ebfd65 100644
--- a/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/__snapshots__/DetailsContent-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/__snapshots__/DetailsContent-test.tsx.snap
@@ -27,9 +27,15 @@ exports[`should render correctly: is default 1`] = `
<h3>
quality_gates.projects
</h3>
- <DocTooltip
+ <HelpTooltip
className="spacer-left"
- doc={Promise {}}
+ overlay={
+ <div
+ className="big-padded-top big-padded-bottom"
+ >
+ quality_gates.projects.help
+ </div>
+ }
/>
</header>
quality_gates.projects_for_default
@@ -64,9 +70,15 @@ exports[`should render correctly: is not default 1`] = `
<h3>
quality_gates.projects
</h3>
- <DocTooltip
+ <HelpTooltip
className="spacer-left"
- doc={Promise {}}
+ overlay={
+ <div
+ className="big-padded-top big-padded-bottom"
+ >
+ quality_gates.projects.help
+ </div>
+ }
/>
</header>
<Projects
diff --git a/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/__snapshots__/ListHeader-test.tsx.snap b/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/__snapshots__/ListHeader-test.tsx.snap
index f12ac9a8ce6..0913eca851b 100644
--- a/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/__snapshots__/ListHeader-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/__snapshots__/ListHeader-test.tsx.snap
@@ -12,9 +12,17 @@ exports[`should render correctly 1`] = `
>
quality_gates.page
</h1>
- <DocTooltip
+ <DocumentationTooltip
className="spacer-left"
- doc={Promise {}}
+ content="quality_gates.help"
+ links={
+ Array [
+ Object {
+ "href": "/documentation/user-guide/quality-gates/",
+ "label": "learn_more",
+ },
+ ]
+ }
/>
</div>
</header>
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileRules.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileRules.tsx
index 6d9faab7932..5119f24816d 100644
--- a/server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileRules.tsx
+++ b/server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileRules.tsx
@@ -21,10 +21,10 @@ import { keyBy } from 'lodash';
import * as React from 'react';
import { Link } from 'react-router';
import { Button } from 'sonar-ui-common/components/controls/buttons';
+import Tooltip from 'sonar-ui-common/components/controls/Tooltip';
import { translate } from 'sonar-ui-common/helpers/l10n';
import { getQualityProfile } from '../../../api/quality-profiles';
import { searchRules, takeFacet } from '../../../api/rules';
-import DocTooltip from '../../../components/docs/DocTooltip';
import { getRulesUrl } from '../../../helpers/urls';
import { Profile } from '../types';
import ProfileRulesDeprecatedWarning from './ProfileRulesDeprecatedWarning';
@@ -197,14 +197,11 @@ export default class ProfileRules extends React.PureComponent<Props, State> {
{/* in such cases it's better to show the button but disable it with a tooltip */}
{actions.copy && profile.isBuiltIn && (
<div className="text-right big-spacer-top">
- <DocTooltip
- doc={import(
- /* webpackMode: "eager" */ 'Docs/tooltips/quality-profiles/activate-rules-in-built-in-profile.md'
- )}>
+ <Tooltip overlay={translate('quality_profiles.activate_more.help.built_in')}>
<Button className="disabled js-activate-rules">
{translate('quality_profiles.activate_more')}
</Button>
- </DocTooltip>
+ </Tooltip>
</div>
)}
</div>
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/home/ProfilesList.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/home/ProfilesList.tsx
index ba36aed88ab..f6f39ea33f9 100644
--- a/server/sonar-web/src/main/js/apps/quality-profiles/home/ProfilesList.tsx
+++ b/server/sonar-web/src/main/js/apps/quality-profiles/home/ProfilesList.tsx
@@ -20,9 +20,9 @@
import { Location } from 'history';
import { groupBy, pick, sortBy } from 'lodash';
import * as React from 'react';
+import HelpTooltip from 'sonar-ui-common/components/controls/HelpTooltip';
import { Alert } from 'sonar-ui-common/components/ui/Alert';
import { translate, translateWithParameters } from 'sonar-ui-common/helpers/l10n';
-import DocTooltip from '../../../components/docs/DocTooltip';
import { Profile } from '../types';
import ProfilesListHeader from './ProfilesListHeader';
import ProfilesListRow from './ProfilesListRow';
@@ -64,11 +64,13 @@ export default class ProfilesList extends React.PureComponent<Props> {
</th>
<th className="text-right nowrap">
{translate('quality_profiles.list.projects')}
- <DocTooltip
+ <HelpTooltip
className="table-cell-doc"
- doc={import(
- /* webpackMode: "eager" */ 'Docs/tooltips/quality-profiles/quality-profile-projects.md'
- )}
+ overlay={
+ <div className="big-padded-top big-padded-bottom">
+ {translate('quality_profiles.list.projects.help')}
+ </div>
+ }
/>
</th>
<th className="text-right nowrap">{translate('quality_profiles.list.rules')}</th>
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/home/ProfilesListRow.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/home/ProfilesListRow.tsx
index fc2cb985b35..3ea27dcec1f 100644
--- a/server/sonar-web/src/main/js/apps/quality-profiles/home/ProfilesListRow.tsx
+++ b/server/sonar-web/src/main/js/apps/quality-profiles/home/ProfilesListRow.tsx
@@ -22,7 +22,6 @@ import { Link } from 'react-router';
import Tooltip from 'sonar-ui-common/components/controls/Tooltip';
import DateFromNow from 'sonar-ui-common/components/intl/DateFromNow';
import { translate } from 'sonar-ui-common/helpers/l10n';
-import DocTooltip from '../../../components/docs/DocTooltip';
import { getRulesUrl } from '../../../helpers/urls';
import BuiltInQualityProfileBadge from '../components/BuiltInQualityProfileBadge';
import ProfileActions from '../components/ProfileActions';
@@ -76,12 +75,9 @@ export function ProfilesListRow(props: ProfilesListRowProps) {
<td className="quality-profiles-table-projects thin nowrap text-middle text-right">
{profile.isDefault ? (
- <DocTooltip
- doc={import(
- /* webpackMode: "eager" */ 'Docs/tooltips/quality-profiles/default-quality-profile.md'
- )}>
+ <Tooltip overlay={translate('quality_profiles.list.default.help')}>
<span className="badge">{translate('default')}</span>
- </DocTooltip>
+ </Tooltip>
) : (
<span>{profile.projectCount}</span>
)}
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/home/__tests__/__snapshots__/ProfilesList-test.tsx.snap b/server/sonar-web/src/main/js/apps/quality-profiles/home/__tests__/__snapshots__/ProfilesList-test.tsx.snap
index 23e63a5ccbe..e374ba8697e 100644
--- a/server/sonar-web/src/main/js/apps/quality-profiles/home/__tests__/__snapshots__/ProfilesList-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/quality-profiles/home/__tests__/__snapshots__/ProfilesList-test.tsx.snap
@@ -36,9 +36,15 @@ exports[`should render correctly 1`] = `
className="text-right nowrap"
>
quality_profiles.list.projects
- <DocTooltip
+ <HelpTooltip
className="table-cell-doc"
- doc={Promise {}}
+ overlay={
+ <div
+ className="big-padded-top big-padded-bottom"
+ >
+ quality_profiles.list.projects.help
+ </div>
+ }
/>
</th>
<th
@@ -106,9 +112,15 @@ exports[`should render correctly 1`] = `
className="text-right nowrap"
>
quality_profiles.list.projects
- <DocTooltip
+ <HelpTooltip
className="table-cell-doc"
- doc={Promise {}}
+ overlay={
+ <div
+ className="big-padded-top big-padded-bottom"
+ >
+ quality_profiles.list.projects.help
+ </div>
+ }
/>
</th>
<th
@@ -197,9 +209,15 @@ exports[`should render correctly 2`] = `
className="text-right nowrap"
>
quality_profiles.list.projects
- <DocTooltip
+ <HelpTooltip
className="table-cell-doc"
- doc={Promise {}}
+ overlay={
+ <div
+ className="big-padded-top big-padded-bottom"
+ >
+ quality_profiles.list.projects.help
+ </div>
+ }
/>
</th>
<th
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/home/__tests__/__snapshots__/ProfilesListRow-test.tsx.snap b/server/sonar-web/src/main/js/apps/quality-profiles/home/__tests__/__snapshots__/ProfilesListRow-test.tsx.snap
index f4761ea4483..9d4c7e133e0 100644
--- a/server/sonar-web/src/main/js/apps/quality-profiles/home/__tests__/__snapshots__/ProfilesListRow-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/quality-profiles/home/__tests__/__snapshots__/ProfilesListRow-test.tsx.snap
@@ -249,15 +249,15 @@ exports[`should render correctly: default profile 1`] = `
<td
className="quality-profiles-table-projects thin nowrap text-middle text-right"
>
- <DocTooltip
- doc={Promise {}}
+ <Tooltip
+ overlay="quality_profiles.list.default.help"
>
<span
className="badge"
>
default
</span>
- </DocTooltip>
+ </Tooltip>
</td>
<td
className="quality-profiles-table-rules thin nowrap text-middle text-right"
diff --git a/server/sonar-web/src/main/js/components/common/DocumentationTooltip.tsx b/server/sonar-web/src/main/js/components/common/DocumentationTooltip.tsx
new file mode 100644
index 00000000000..c2ede9b95f1
--- /dev/null
+++ b/server/sonar-web/src/main/js/components/common/DocumentationTooltip.tsx
@@ -0,0 +1,72 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2020 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import * as React from 'react';
+import HelpTooltip from 'sonar-ui-common/components/controls/HelpTooltip';
+import DetachIcon from 'sonar-ui-common/components/icons/DetachIcon';
+import { isWebUri } from 'valid-url';
+
+export interface DocumentationTooltipProps {
+ children?: React.ReactNode;
+ className?: string;
+ content?: React.ReactNode;
+ links?: Array<{ href: string; label: string }>;
+ title?: string;
+}
+
+export default function DocumentationTooltip(props: DocumentationTooltipProps) {
+ const { className, content, links, title } = props;
+
+ return (
+ <HelpTooltip
+ className={className}
+ overlay={
+ <div className="big-padded-top big-padded-bottom">
+ {title && (
+ <div className="spacer-bottom">
+ <strong>{title}</strong>
+ </div>
+ )}
+
+ {content && <p>{content}</p>}
+
+ {links && (
+ <>
+ <hr className="big-spacer-top big-spacer-bottom" />
+
+ {links.map(({ href, label }) => (
+ <div className="little-spacer-bottom" key={label}>
+ <a
+ className="display-inline-flex-center link-with-icon"
+ href={href}
+ rel="noopener noreferrer"
+ target="_blank">
+ {isWebUri(href) && <DetachIcon size={14} className="spacer-right" />}
+ <span>{label}</span>
+ </a>
+ </div>
+ ))}
+ </>
+ )}
+ </div>
+ }>
+ {props.children}
+ </HelpTooltip>
+ );
+}
diff --git a/server/sonar-web/src/main/js/apps/create/components/__tests__/FreeCardPlan-test.tsx b/server/sonar-web/src/main/js/components/common/__tests__/DocumentationTooltip-test.tsx
index f3bcba95619..fc7ae766eb8 100644
--- a/server/sonar-web/src/main/js/apps/create/components/__tests__/FreeCardPlan-test.tsx
+++ b/server/sonar-web/src/main/js/components/common/__tests__/DocumentationTooltip-test.tsx
@@ -19,20 +19,22 @@
*/
import { shallow } from 'enzyme';
import * as React from 'react';
-import FreeCardPlan from '../FreeCardPlan';
+import DocumentationTooltip, { DocumentationTooltipProps } from '../DocumentationTooltip';
-it('should render', () => {
- expect(shallow(<FreeCardPlan hasWarning={false} />)).toMatchSnapshot();
-});
-
-it('should render with warning', () => {
+it('renders correctly', () => {
+ expect(shallowRender()).toMatchSnapshot('basic');
expect(
- shallow(<FreeCardPlan almName="GitHub" hasWarning={true} selected={true} />)
- ).toMatchSnapshot();
+ shallowRender({
+ links: [
+ { href: 'http://link.tosome.place', label: 'external link' },
+ { href: '/documentation/guide', label: 'internal link' }
+ ]
+ })
+ ).toMatchSnapshot('with links');
+ expect(shallowRender({ title: undefined })).toMatchSnapshot('no title');
+ expect(shallowRender({ content: undefined })).toMatchSnapshot('no content');
});
-it('should render disabled with info', () => {
- expect(
- shallow(<FreeCardPlan almName="GitHub" disabled={true} hasWarning={false} />)
- ).toMatchSnapshot();
-});
+function shallowRender(props: Partial<DocumentationTooltipProps> = {}) {
+ return shallow(<DocumentationTooltip content="content" title="title" {...props} />);
+}
diff --git a/server/sonar-web/src/main/js/components/common/__tests__/__snapshots__/DocumentationTooltip-test.tsx.snap b/server/sonar-web/src/main/js/components/common/__tests__/__snapshots__/DocumentationTooltip-test.tsx.snap
new file mode 100644
index 00000000000..423376fa2ce
--- /dev/null
+++ b/server/sonar-web/src/main/js/components/common/__tests__/__snapshots__/DocumentationTooltip-test.tsx.snap
@@ -0,0 +1,112 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`renders correctly: basic 1`] = `
+<HelpTooltip
+ overlay={
+ <div
+ className="big-padded-top big-padded-bottom"
+ >
+ <div
+ className="spacer-bottom"
+ >
+ <strong>
+ title
+ </strong>
+ </div>
+ <p>
+ content
+ </p>
+ </div>
+ }
+/>
+`;
+
+exports[`renders correctly: no content 1`] = `
+<HelpTooltip
+ overlay={
+ <div
+ className="big-padded-top big-padded-bottom"
+ >
+ <div
+ className="spacer-bottom"
+ >
+ <strong>
+ title
+ </strong>
+ </div>
+ </div>
+ }
+/>
+`;
+
+exports[`renders correctly: no title 1`] = `
+<HelpTooltip
+ overlay={
+ <div
+ className="big-padded-top big-padded-bottom"
+ >
+ <p>
+ content
+ </p>
+ </div>
+ }
+/>
+`;
+
+exports[`renders correctly: with links 1`] = `
+<HelpTooltip
+ overlay={
+ <div
+ className="big-padded-top big-padded-bottom"
+ >
+ <div
+ className="spacer-bottom"
+ >
+ <strong>
+ title
+ </strong>
+ </div>
+ <p>
+ content
+ </p>
+ <React.Fragment>
+ <hr
+ className="big-spacer-top big-spacer-bottom"
+ />
+ <div
+ className="little-spacer-bottom"
+ >
+ <a
+ className="display-inline-flex-center link-with-icon"
+ href="http://link.tosome.place"
+ rel="noopener noreferrer"
+ target="_blank"
+ >
+ <DetachIcon
+ className="spacer-right"
+ size={14}
+ />
+ <span>
+ external link
+ </span>
+ </a>
+ </div>
+ <div
+ className="little-spacer-bottom"
+ >
+ <a
+ className="display-inline-flex-center link-with-icon"
+ href="/documentation/guide"
+ rel="noopener noreferrer"
+ target="_blank"
+ >
+ <span>
+ internal link
+ </span>
+ </a>
+ </div>
+ </React.Fragment>
+ </div>
+ }
+/>
+`;
diff --git a/server/sonar-web/src/main/js/components/docs/DocTooltip.tsx b/server/sonar-web/src/main/js/components/docs/DocTooltip.tsx
deleted file mode 100644
index d3f096a8957..00000000000
--- a/server/sonar-web/src/main/js/components/docs/DocTooltip.tsx
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import * as React from 'react';
-import HelpTooltip from 'sonar-ui-common/components/controls/HelpTooltip';
-import { lazyLoadComponent } from 'sonar-ui-common/components/lazyLoadComponent';
-import { filterContent } from '../../helpers/markdown';
-
-const DocMarkdownBlock = lazyLoadComponent(() => import('./DocMarkdownBlock'), 'DocMarkdownBlock');
-
-interface Props {
- className?: string;
- children?: React.ReactNode;
- // Use as `import(/* webpackMode: "eager" */ 'Docs/tooltips/foo/bar.md')`
- doc: Promise<{ default: string }>;
- overlayProps?: T.Dict<string>;
-}
-
-interface State {
- content?: string;
-}
-
-export default class DocTooltip extends React.PureComponent<Props, State> {
- mounted = false;
- state: State = {};
-
- componentDidMount() {
- this.mounted = true;
- this.props.doc.then(
- ({ default: content }) => {
- if (this.mounted) {
- this.setState({ content });
- }
- },
- () => {}
- );
- }
-
- componentWillUnmount() {
- this.mounted = false;
- }
-
- render() {
- return this.state.content ? (
- <HelpTooltip
- className={this.props.className}
- overlay={
- <div className="abs-width-300">
- <DocMarkdownBlock
- childProps={this.props.overlayProps}
- className="cut-margins"
- content={filterContent(this.state.content)}
- isTooltip={true}
- />
- </div>
- }>
- {this.props.children}
- </HelpTooltip>
- ) : (
- this.props.children || null
- );
- }
-}
diff --git a/server/sonar-web/src/main/js/components/docs/__tests__/DocTooltip-test.tsx b/server/sonar-web/src/main/js/components/docs/__tests__/DocTooltip-test.tsx
deleted file mode 100644
index 36f6b8ada06..00000000000
--- a/server/sonar-web/src/main/js/components/docs/__tests__/DocTooltip-test.tsx
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import { shallow } from 'enzyme';
-import * as React from 'react';
-import { waitAndUpdate } from 'sonar-ui-common/helpers/testUtils';
-import DocTooltip from '../DocTooltip';
-
-it('should render', async () => {
- const wrapper = shallow(<DocTooltip doc={Promise.resolve({ default: 'this is *bold* text' })} />);
- expect(wrapper).toMatchSnapshot();
- await waitAndUpdate(wrapper);
- expect(wrapper).toMatchSnapshot();
-});
diff --git a/server/sonar-web/src/main/js/components/docs/__tests__/__snapshots__/DocTooltip-test.tsx.snap b/server/sonar-web/src/main/js/components/docs/__tests__/__snapshots__/DocTooltip-test.tsx.snap
deleted file mode 100644
index cb2fe21b9d9..00000000000
--- a/server/sonar-web/src/main/js/components/docs/__tests__/__snapshots__/DocTooltip-test.tsx.snap
+++ /dev/null
@@ -1,19 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render 1`] = `""`;
-
-exports[`should render 2`] = `
-<HelpTooltip
- overlay={
- <div
- className="abs-width-300"
- >
- <DocMarkdownBlock
- className="cut-margins"
- content="this is *bold* text"
- isTooltip={true}
- />
- </div>
- }
-/>
-`;