From 4ecb6fc3ec08ee37a1bb5c19d8ca44e2b832b5a7 Mon Sep 17 00:00:00 2001 From: Stas Vilchik Date: Mon, 27 Jun 2016 16:08:44 +0200 Subject: [PATCH] refactor quality profiles page (#1056) --- .../src/test/java/it/Category4Suite.java | 5 +- .../QualityProfilesPageTest.java | 200 +++++++++++++++ .../normal-user.html | 115 ++++----- .../profile-admin.html | 42 ++-- .../QualityProfilesPageTest/not_found.html | 24 ++ .../should_compare.html | 60 +++++ .../QualityProfilesPageTest/should_copy.html | 105 ++++++++ .../should_create.html | 105 ++++++++ .../should_delete.html | 110 ++++++++ .../should_display_changelog.html | 55 ++++ .../should_display_list.html | 75 ++++++ .../should_display_profile_exporters.html | 50 ++++ .../should_display_profile_inheritance.html | 60 +++++ .../should_display_profile_projects.html | 50 ++++ .../should_display_profile_rules.html | 45 ++++ .../should_filter_by_language.html | 90 +++++++ .../should_open_from_list.html | 55 ++++ .../should_rename.html | 110 ++++++++ .../should_restore.html | 70 ++++++ .../should_restore_built_in.html | 90 +++++++ .../should_set_default.html | 95 +++++++ .../src/main/js/api/quality-profiles.js | 129 +++++++++- .../intro-view.js => api/rules.js} | 14 +- .../quality-profiles/__tests__/utils-test.js | 74 ++++++ .../js/apps/quality-profiles/actions-view.js | 114 --------- .../src/main/js/apps/quality-profiles/app.js | 97 +++---- .../quality-profiles/changelog/Changelog.js | 81 ++++++ .../changelog/ChangelogContainer.js | 128 ++++++++++ .../changelog/ChangelogEmpty.js | 12 +- .../changelog/ChangelogSearch.js | 62 +++++ .../quality-profiles/changelog/ChangesList.js | 46 ++++ .../changelog/ParameterChange.js | 53 ++++ .../changelog/SeverityChange.js | 38 +++ .../changelog/__tests__/Changelog-test.js | 84 +++++++ .../__tests__/ChangelogSearch-test.js | 68 +++++ .../changelog/__tests__/ChangesList-test.js | 54 ++++ .../__tests__/ParameterChange-test.js | 31 +++ .../__tests__/SeverityChange-test.js | 34 +++ .../compare/ComparisonContainer.js | 122 +++++++++ .../ComparisonEmpty.js} | 18 +- .../compare/ComparisonForm.js | 56 +++++ .../compare/ComparisonResults.js | 176 +++++++++++++ .../compare/__tests__/ComparisonForm-test.js | 49 ++++ .../__tests__/ComparisonResults-test.js | 98 ++++++++ .../apps/quality-profiles/components/App.js | 97 +++++++ .../components/ProfileContainer.js | 72 ++++++ .../{router.js => components/ProfileDate.js} | 54 ++-- .../ProfileLink.js} | 36 ++- .../components/ProfileNotFound.js | 40 +++ .../__tests__/ProfileContainer-test.js | 89 +++++++ .../js/apps/quality-profiles/controller.js | 128 ---------- .../details/ProfileDetails.js | 52 ++++ .../details/ProfileEvolution.js | 61 +++++ .../details/ProfileExporters.js | 64 +++++ .../quality-profiles/details/ProfileHeader.js | 183 ++++++++++++++ .../details/ProfileInheritance.js | 126 ++++++++++ .../details/ProfileInheritanceBox.js | 77 ++++++ .../details/ProfileProjects.js | 148 +++++++++++ .../quality-profiles/details/ProfileRules.js | 237 ++++++++++++++++++ .../details/ProfileRulesRow.js | 54 ++++ .../quality-profiles/details/ProgressBar.js | 54 ++++ .../apps/quality-profiles/home/Evolution.js | 40 +++ .../home/EvolutionDeprecated.js | 82 ++++++ .../quality-profiles/home/EvolutionRules.js | 123 +++++++++ .../home/EvolutionStagnant.js | 71 ++++++ .../quality-profiles/home/HomeContainer.js | 41 +++ .../apps/quality-profiles/home/PageHeader.js | 114 +++++++++ .../quality-profiles/home/ProfilesList.js | 134 ++++++++++ .../home/ProfilesListHeader.js | 96 +++++++ .../quality-profiles/home/ProfilesListRow.js | 132 ++++++++++ .../main/js/apps/quality-profiles/layout.js | 47 ---- .../profile-changelog-view.js | 55 ---- .../profile-comparison-view.js | 65 ----- .../quality-profiles/profile-details-view.js | 181 ------------- .../quality-profiles/profile-header-view.js | 91 ------- .../js/apps/quality-profiles/profile-view.js | 60 ----- .../main/js/apps/quality-profiles/profile.js | 136 ---------- .../js/apps/quality-profiles/profiles-view.js | 84 ------- .../js/apps/quality-profiles/propTypes.js | 45 ++++ .../restore-built-in-profiles-view.js | 79 ------ .../main/js/apps/quality-profiles/styles.css | 149 +++++++++++ .../templates/quality-profile-changelog.hbs | 66 ----- .../templates/quality-profile-comparison.hbs | 89 ------- .../templates/quality-profiles-actions.hbs | 40 --- .../quality-profiles-change-projects.hbs | 12 + .../quality-profiles-create-profile.hbs | 6 +- .../quality-profiles-delete-profile.hbs | 4 +- .../templates/quality-profiles-empty.hbs | 1 - .../templates/quality-profiles-intro.hbs | 4 - .../templates/quality-profiles-layout.hbs | 11 - .../quality-profiles-profile-details.hbs | 134 ---------- .../quality-profiles-profile-header.hbs | 19 -- .../templates/quality-profiles-profile.hbs | 21 -- .../quality-profiles-profiles-language.hbs | 1 - .../templates/quality-profiles-profiles.hbs | 1 - ...iles-restore-built-in-profiles-success.hbs | 2 +- ...ity-profiles-restore-built-in-profiles.hbs | 12 +- .../main/js/apps/quality-profiles/utils.js | 61 +++++ .../ChangeParentView.js} | 53 ++-- .../views/ChangeProjectsView.js | 70 ++++++ .../CopyProfileView.js} | 45 ++-- .../CreateProfileView.js} | 15 +- .../DeleteProfileView.js} | 39 ++- .../RenameProfileView.js} | 41 ++- .../views/RestoreBuiltInProfilesView.js | 56 +++++ .../RestoreProfileView.js} | 23 +- .../main/js/components/controls/DateInput.js | 86 +++++++ .../main/js/components/controls/styles.css | 26 ++ .../js/components/mixins/tooltips-mixin.js | 2 +- .../js/components/shared/severity-helper.js | 13 +- server/sonar-web/src/main/js/helpers/urls.js | 26 ++ .../src/main/less/components/page.less | 6 + .../app/controllers/profiles_controller.rb | 4 + server/sonar-web/tests/mocha.opts | 2 +- server/sonar-web/tests/null-compiler.js | 1 + .../resources/org/sonar/l10n/core.properties | 40 ++- 116 files changed, 5872 insertions(+), 1806 deletions(-) create mode 100644 it/it-tests/src/test/java/it/qualityProfile/QualityProfilesPageTest.java create mode 100644 it/it-tests/src/test/resources/qualityProfile/QualityProfilesPageTest/not_found.html create mode 100644 it/it-tests/src/test/resources/qualityProfile/QualityProfilesPageTest/should_compare.html create mode 100644 it/it-tests/src/test/resources/qualityProfile/QualityProfilesPageTest/should_copy.html create mode 100644 it/it-tests/src/test/resources/qualityProfile/QualityProfilesPageTest/should_create.html create mode 100644 it/it-tests/src/test/resources/qualityProfile/QualityProfilesPageTest/should_delete.html create mode 100644 it/it-tests/src/test/resources/qualityProfile/QualityProfilesPageTest/should_display_changelog.html create mode 100644 it/it-tests/src/test/resources/qualityProfile/QualityProfilesPageTest/should_display_list.html create mode 100644 it/it-tests/src/test/resources/qualityProfile/QualityProfilesPageTest/should_display_profile_exporters.html create mode 100644 it/it-tests/src/test/resources/qualityProfile/QualityProfilesPageTest/should_display_profile_inheritance.html create mode 100644 it/it-tests/src/test/resources/qualityProfile/QualityProfilesPageTest/should_display_profile_projects.html create mode 100644 it/it-tests/src/test/resources/qualityProfile/QualityProfilesPageTest/should_display_profile_rules.html create mode 100644 it/it-tests/src/test/resources/qualityProfile/QualityProfilesPageTest/should_filter_by_language.html create mode 100644 it/it-tests/src/test/resources/qualityProfile/QualityProfilesPageTest/should_open_from_list.html create mode 100644 it/it-tests/src/test/resources/qualityProfile/QualityProfilesPageTest/should_rename.html create mode 100644 it/it-tests/src/test/resources/qualityProfile/QualityProfilesPageTest/should_restore.html create mode 100644 it/it-tests/src/test/resources/qualityProfile/QualityProfilesPageTest/should_restore_built_in.html create mode 100644 it/it-tests/src/test/resources/qualityProfile/QualityProfilesPageTest/should_set_default.html rename server/sonar-web/src/main/js/{apps/quality-profiles/intro-view.js => api/rules.js} (73%) create mode 100644 server/sonar-web/src/main/js/apps/quality-profiles/__tests__/utils-test.js delete mode 100644 server/sonar-web/src/main/js/apps/quality-profiles/actions-view.js create mode 100644 server/sonar-web/src/main/js/apps/quality-profiles/changelog/Changelog.js create mode 100644 server/sonar-web/src/main/js/apps/quality-profiles/changelog/ChangelogContainer.js rename it/it-tests/src/test/java/it/qualityProfile/ToDoTest.java => server/sonar-web/src/main/js/apps/quality-profiles/changelog/ChangelogEmpty.js (76%) create mode 100644 server/sonar-web/src/main/js/apps/quality-profiles/changelog/ChangelogSearch.js create mode 100644 server/sonar-web/src/main/js/apps/quality-profiles/changelog/ChangesList.js create mode 100644 server/sonar-web/src/main/js/apps/quality-profiles/changelog/ParameterChange.js create mode 100644 server/sonar-web/src/main/js/apps/quality-profiles/changelog/SeverityChange.js create mode 100644 server/sonar-web/src/main/js/apps/quality-profiles/changelog/__tests__/Changelog-test.js create mode 100644 server/sonar-web/src/main/js/apps/quality-profiles/changelog/__tests__/ChangelogSearch-test.js create mode 100644 server/sonar-web/src/main/js/apps/quality-profiles/changelog/__tests__/ChangesList-test.js create mode 100644 server/sonar-web/src/main/js/apps/quality-profiles/changelog/__tests__/ParameterChange-test.js create mode 100644 server/sonar-web/src/main/js/apps/quality-profiles/changelog/__tests__/SeverityChange-test.js create mode 100644 server/sonar-web/src/main/js/apps/quality-profiles/compare/ComparisonContainer.js rename server/sonar-web/src/main/js/apps/quality-profiles/{profiles-empty-view.js => compare/ComparisonEmpty.js} (74%) create mode 100644 server/sonar-web/src/main/js/apps/quality-profiles/compare/ComparisonForm.js create mode 100644 server/sonar-web/src/main/js/apps/quality-profiles/compare/ComparisonResults.js create mode 100644 server/sonar-web/src/main/js/apps/quality-profiles/compare/__tests__/ComparisonForm-test.js create mode 100644 server/sonar-web/src/main/js/apps/quality-profiles/compare/__tests__/ComparisonResults-test.js create mode 100644 server/sonar-web/src/main/js/apps/quality-profiles/components/App.js create mode 100644 server/sonar-web/src/main/js/apps/quality-profiles/components/ProfileContainer.js rename server/sonar-web/src/main/js/apps/quality-profiles/{router.js => components/ProfileDate.js} (55%) rename server/sonar-web/src/main/js/apps/quality-profiles/{profiles.js => components/ProfileLink.js} (66%) create mode 100644 server/sonar-web/src/main/js/apps/quality-profiles/components/ProfileNotFound.js create mode 100644 server/sonar-web/src/main/js/apps/quality-profiles/components/__tests__/ProfileContainer-test.js delete mode 100644 server/sonar-web/src/main/js/apps/quality-profiles/controller.js create mode 100644 server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileDetails.js create mode 100644 server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileEvolution.js create mode 100644 server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileExporters.js create mode 100644 server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileHeader.js create mode 100644 server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileInheritance.js create mode 100644 server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileInheritanceBox.js create mode 100644 server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileProjects.js create mode 100644 server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileRules.js create mode 100644 server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileRulesRow.js create mode 100644 server/sonar-web/src/main/js/apps/quality-profiles/details/ProgressBar.js create mode 100644 server/sonar-web/src/main/js/apps/quality-profiles/home/Evolution.js create mode 100644 server/sonar-web/src/main/js/apps/quality-profiles/home/EvolutionDeprecated.js create mode 100644 server/sonar-web/src/main/js/apps/quality-profiles/home/EvolutionRules.js create mode 100644 server/sonar-web/src/main/js/apps/quality-profiles/home/EvolutionStagnant.js create mode 100644 server/sonar-web/src/main/js/apps/quality-profiles/home/HomeContainer.js create mode 100644 server/sonar-web/src/main/js/apps/quality-profiles/home/PageHeader.js create mode 100644 server/sonar-web/src/main/js/apps/quality-profiles/home/ProfilesList.js create mode 100644 server/sonar-web/src/main/js/apps/quality-profiles/home/ProfilesListHeader.js create mode 100644 server/sonar-web/src/main/js/apps/quality-profiles/home/ProfilesListRow.js delete mode 100644 server/sonar-web/src/main/js/apps/quality-profiles/layout.js delete mode 100644 server/sonar-web/src/main/js/apps/quality-profiles/profile-changelog-view.js delete mode 100644 server/sonar-web/src/main/js/apps/quality-profiles/profile-comparison-view.js delete mode 100644 server/sonar-web/src/main/js/apps/quality-profiles/profile-details-view.js delete mode 100644 server/sonar-web/src/main/js/apps/quality-profiles/profile-header-view.js delete mode 100644 server/sonar-web/src/main/js/apps/quality-profiles/profile-view.js delete mode 100644 server/sonar-web/src/main/js/apps/quality-profiles/profile.js delete mode 100644 server/sonar-web/src/main/js/apps/quality-profiles/profiles-view.js create mode 100644 server/sonar-web/src/main/js/apps/quality-profiles/propTypes.js delete mode 100644 server/sonar-web/src/main/js/apps/quality-profiles/restore-built-in-profiles-view.js create mode 100644 server/sonar-web/src/main/js/apps/quality-profiles/styles.css delete mode 100644 server/sonar-web/src/main/js/apps/quality-profiles/templates/quality-profile-changelog.hbs delete mode 100644 server/sonar-web/src/main/js/apps/quality-profiles/templates/quality-profile-comparison.hbs delete mode 100644 server/sonar-web/src/main/js/apps/quality-profiles/templates/quality-profiles-actions.hbs create mode 100644 server/sonar-web/src/main/js/apps/quality-profiles/templates/quality-profiles-change-projects.hbs delete mode 100644 server/sonar-web/src/main/js/apps/quality-profiles/templates/quality-profiles-empty.hbs delete mode 100644 server/sonar-web/src/main/js/apps/quality-profiles/templates/quality-profiles-intro.hbs delete mode 100644 server/sonar-web/src/main/js/apps/quality-profiles/templates/quality-profiles-layout.hbs delete mode 100644 server/sonar-web/src/main/js/apps/quality-profiles/templates/quality-profiles-profile-details.hbs delete mode 100644 server/sonar-web/src/main/js/apps/quality-profiles/templates/quality-profiles-profile-header.hbs delete mode 100644 server/sonar-web/src/main/js/apps/quality-profiles/templates/quality-profiles-profile.hbs delete mode 100644 server/sonar-web/src/main/js/apps/quality-profiles/templates/quality-profiles-profiles-language.hbs delete mode 100644 server/sonar-web/src/main/js/apps/quality-profiles/templates/quality-profiles-profiles.hbs create mode 100644 server/sonar-web/src/main/js/apps/quality-profiles/utils.js rename server/sonar-web/src/main/js/apps/quality-profiles/{change-profile-parent-view.js => views/ChangeParentView.js} (52%) create mode 100644 server/sonar-web/src/main/js/apps/quality-profiles/views/ChangeProjectsView.js rename server/sonar-web/src/main/js/apps/quality-profiles/{copy-profile-view.js => views/CopyProfileView.js} (56%) rename server/sonar-web/src/main/js/apps/quality-profiles/{create-profile-view.js => views/CreateProfileView.js} (86%) rename server/sonar-web/src/main/js/apps/quality-profiles/{delete-profile-view.js => views/DeleteProfileView.js} (60%) rename server/sonar-web/src/main/js/apps/quality-profiles/{rename-profile-view.js => views/RenameProfileView.js} (62%) create mode 100644 server/sonar-web/src/main/js/apps/quality-profiles/views/RestoreBuiltInProfilesView.js rename server/sonar-web/src/main/js/apps/quality-profiles/{restore-profile-view.js => views/RestoreProfileView.js} (70%) create mode 100644 server/sonar-web/src/main/js/components/controls/DateInput.js create mode 100644 server/sonar-web/src/main/js/components/controls/styles.css diff --git a/it/it-tests/src/test/java/it/Category4Suite.java b/it/it-tests/src/test/java/it/Category4Suite.java index a12a4f39779..48297240e98 100644 --- a/it/it-tests/src/test/java/it/Category4Suite.java +++ b/it/it-tests/src/test/java/it/Category4Suite.java @@ -33,6 +33,7 @@ import it.duplication.DuplicationsTest; import it.http.HttpHeadersTest; import it.projectComparison.ProjectComparisonTest; import it.projectEvent.EventTest; +import it.qualityProfile.QualityProfilesPageTest; import it.serverSystem.ServerSystemTest; import it.ui.UiTest; import it.uiExtension.UiExtensionsTest; @@ -90,7 +91,9 @@ import static util.ItUtils.xooPlugin; // ui extensions UiExtensionsTest.class, WsLocalCallTest.class, - WsTest.class + WsTest.class, + // quality profiles + QualityProfilesPageTest.class }) public class Category4Suite { diff --git a/it/it-tests/src/test/java/it/qualityProfile/QualityProfilesPageTest.java b/it/it-tests/src/test/java/it/qualityProfile/QualityProfilesPageTest.java new file mode 100644 index 00000000000..8a74c2ba8fa --- /dev/null +++ b/it/it-tests/src/test/java/it/qualityProfile/QualityProfilesPageTest.java @@ -0,0 +1,200 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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. + */ +package it.qualityProfile; + +import com.sonar.orchestrator.Orchestrator; +import com.sonar.orchestrator.build.SonarScanner; +import com.sonar.orchestrator.selenium.Selenese; +import it.Category4Suite; +import org.junit.*; +import org.junit.experimental.categories.Category; +import org.sonarqube.ws.client.PostRequest; +import org.sonarqube.ws.client.WsClient; +import util.QaOnly; +import util.selenium.SeleneseTest; + +import static util.ItUtils.newAdminWsClient; +import static util.ItUtils.projectDir; + +@Category(QaOnly.class) +public class QualityProfilesPageTest { + + @ClassRule + public static Orchestrator orchestrator = Category4Suite.ORCHESTRATOR; + private static WsClient adminWsClient; + + @BeforeClass + public static void setUp() { + adminWsClient = newAdminWsClient(orchestrator); + orchestrator.resetData(); + } + + @Before + public void createSampleProfile() { + createProfile("xoo", "sample"); + inheritProfile("xoo", "sample", "Basic"); + analyzeProject("shared/xoo-sample"); + addProfileToProject("xoo", "sample", "sample"); + } + + @After + public void deleteSampleProfile() { + setDefault("xoo", "Basic"); + deleteProfile("xoo", "sample"); + deleteProfile("xoo", "new name"); + } + + @Test + public void testHomePage() throws Exception { + Selenese selenese = Selenese.builder().setHtmlTestsInClasspath("test_home_page", + "/qualityProfile/QualityProfilesPageTest/should_display_list.html", + "/qualityProfile/QualityProfilesPageTest/should_open_from_list.html", + "/qualityProfile/QualityProfilesPageTest/should_filter_by_language.html" + ).build(); + new SeleneseTest(selenese).runOn(orchestrator); + } + + @Test + public void testProfilePage() throws Exception { + Selenese selenese = Selenese.builder().setHtmlTestsInClasspath("test_profile_page", + "/qualityProfile/QualityProfilesPageTest/should_display_profile_rules.html", + "/qualityProfile/QualityProfilesPageTest/should_display_profile_inheritance.html", + "/qualityProfile/QualityProfilesPageTest/should_display_profile_projects.html", + "/qualityProfile/QualityProfilesPageTest/should_display_profile_exporters.html" + ).build(); + new SeleneseTest(selenese).runOn(orchestrator); + } + + @Test + public void testNotFound() { + Selenese selenese = Selenese.builder().setHtmlTestsInClasspath("test_not_found", + "/qualityProfile/QualityProfilesPageTest/not_found.html").build(); + orchestrator.executeSelenese(selenese); + } + + @Test + public void testProfileChangelog() throws Exception { + Selenese selenese = Selenese.builder().setHtmlTestsInClasspath("test_profile_changelog", + "/qualityProfile/QualityProfilesPageTest/should_display_changelog.html" + ).build(); + new SeleneseTest(selenese).runOn(orchestrator); + } + + @Ignore("find a way to know profile key inside selenium tests") + @Test + public void testComparison() throws Exception { + Selenese selenese = Selenese.builder().setHtmlTestsInClasspath("test_comparison", + "/qualityProfile/QualityProfilesPageTest/should_compare.html" + ).build(); + new SeleneseTest(selenese).runOn(orchestrator); + } + + @Test + public void testCreation() throws Exception { + Selenese selenese = Selenese.builder().setHtmlTestsInClasspath("test_creation", + "/qualityProfile/QualityProfilesPageTest/should_create.html" + ).build(); + new SeleneseTest(selenese).runOn(orchestrator); + } + + @Test + public void testDeletion() throws Exception { + Selenese selenese = Selenese.builder().setHtmlTestsInClasspath("test_deletion", + "/qualityProfile/QualityProfilesPageTest/should_delete.html" + ).build(); + new SeleneseTest(selenese).runOn(orchestrator); + } + + @Test + public void testCopying() throws Exception { + Selenese selenese = Selenese.builder().setHtmlTestsInClasspath("test_copying", + "/qualityProfile/QualityProfilesPageTest/should_copy.html" + ).build(); + new SeleneseTest(selenese).runOn(orchestrator); + } + + @Test + public void testRenaming() throws Exception { + Selenese selenese = Selenese.builder().setHtmlTestsInClasspath("test_renaming", + "/qualityProfile/QualityProfilesPageTest/should_rename.html" + ).build(); + new SeleneseTest(selenese).runOn(orchestrator); + } + + @Test + public void testSettingDefault() throws Exception { + Selenese selenese = Selenese.builder().setHtmlTestsInClasspath("test_setting_default", + "/qualityProfile/QualityProfilesPageTest/should_set_default.html" + ).build(); + new SeleneseTest(selenese).runOn(orchestrator); + } + + @Test + public void testRestoration() throws Exception { + deleteProfile("xoo", "empty"); + + Selenese selenese = Selenese.builder().setHtmlTestsInClasspath("test_restoration", + "/qualityProfile/QualityProfilesPageTest/should_restore.html", + "/qualityProfile/QualityProfilesPageTest/should_restore_built_in.html" + ).build(); + new SeleneseTest(selenese).runOn(orchestrator); + } + + private static void createProfile(String language, String name) { + adminWsClient.wsConnector().call( + new PostRequest("api/qualityprofiles/create") + .setParam("language", language) + .setParam("name", name)); + } + + private static void inheritProfile(String language, String name, String parentName) { + adminWsClient.wsConnector().call( + new PostRequest("api/qualityprofiles/change_parent") + .setParam("language", language) + .setParam("profileName", name) + .setParam("parentName", parentName)); + } + + private static void analyzeProject(String path) { + orchestrator.executeBuild(SonarScanner.create(projectDir(path))); + } + + private static void addProfileToProject(String language, String profileName, String projectKey) { + adminWsClient.wsConnector().call( + new PostRequest("api/qualityprofiles/add_project") + .setParam("language", language) + .setParam("profileName", profileName) + .setParam("projectKey", projectKey)); + } + + private static void deleteProfile(String language, String name) { + adminWsClient.wsConnector().call( + new PostRequest("api/qualityprofiles/delete") + .setParam("language", language) + .setParam("profileName", name)); + } + + private static void setDefault(String language, String name) { + adminWsClient.wsConnector().call( + new PostRequest("api/qualityprofiles/set_default") + .setParam("language", language) + .setParam("profileName", name)); + } +} diff --git a/it/it-tests/src/test/resources/authorisation/QualityProfileAdminPermissionTest/normal-user.html b/it/it-tests/src/test/resources/authorisation/QualityProfileAdminPermissionTest/normal-user.html index ef778363fc3..dee98790990 100644 --- a/it/it-tests/src/test/resources/authorisation/QualityProfileAdminPermissionTest/normal-user.html +++ b/it/it-tests/src/test/resources/authorisation/QualityProfileAdminPermissionTest/normal-user.html @@ -9,71 +9,56 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
open/sessions/logout
open/sessions/new
typeid=loginnot_profileadm
typeid=passworduserpwd
clickAndWaitname=commit
open/profiles
waitForTextcss=.quality-profiles-results*Basic*
assertNotTextcss=.search-navigator-filters*Create*
assertNotTextcss=.search-navigator-filters*Restore Profile*
assertNotTextcss=.search-navigator-filters*Restore Built-in Profiles*
open/project/profile/sample
waitForTextid=content*Log In to SonarQube*
waitForTextid=login_formglob:*You are not authorized to access this page*
open/sessions/logout
open/sessions/new
typeid=loginnot_profileadm
typeid=passworduserpwd
clickAndWaitname=commit
open/profiles
waitForElementPresentcss=.quality-profiles-table-row[data-name="Basic"]
clickcss=.quality-profiles-table-row[data-name="Basic"] .quality-profiles-table-name a
waitForTextcss=.quality-profile-header*Basic*
assertElementNotPresentcss=.js-change-parent
diff --git a/it/it-tests/src/test/resources/authorisation/QualityProfileAdminPermissionTest/profile-admin.html b/it/it-tests/src/test/resources/authorisation/QualityProfileAdminPermissionTest/profile-admin.html index af19a0a1da2..76ec57eadc0 100644 --- a/it/it-tests/src/test/resources/authorisation/QualityProfileAdminPermissionTest/profile-admin.html +++ b/it/it-tests/src/test/resources/authorisation/QualityProfileAdminPermissionTest/profile-admin.html @@ -39,39 +39,39 @@ - waitForText - css=.quality-profiles-results - *Basic* + waitForElementPresent + css=.quality-profiles-table-row[data-name="Basic"] + - waitForText - css=.search-navigator-filters - *Create* + click + css=.quality-profiles-table-row[data-name="Basic"] .quality-profiles-table-name a + - waitForText - css=.search-navigator-filters - *Restore Profile* + waitForText + css=.quality-profile-header + *Basic* - waitForText - css=.search-navigator-filters - *Restore Built-in Profiles* + assertElementPresent + css=.js-change-parent + - open - /project/profile/sample - + open + /project/profile/sample + - waitForText - id=content - *Quality Profiles* + waitForText + id=content + *Quality Profiles* - assertValue - id=submit-xoo - glob:*Update* + assertValue + id=submit-xoo + glob:*Update* diff --git a/it/it-tests/src/test/resources/qualityProfile/QualityProfilesPageTest/not_found.html b/it/it-tests/src/test/resources/qualityProfile/QualityProfilesPageTest/not_found.html new file mode 100644 index 00000000000..220d39856d6 --- /dev/null +++ b/it/it-tests/src/test/resources/qualityProfile/QualityProfilesPageTest/not_found.html @@ -0,0 +1,24 @@ + + + + + + not_found + + + + + + + + + + + + + + + +
open/profiles/show?key=unknown
waitForElementPresentcss=.quality-profile-not-found
+ + \ No newline at end of file diff --git a/it/it-tests/src/test/resources/qualityProfile/QualityProfilesPageTest/should_compare.html b/it/it-tests/src/test/resources/qualityProfile/QualityProfilesPageTest/should_compare.html new file mode 100644 index 00000000000..c2339d690f6 --- /dev/null +++ b/it/it-tests/src/test/resources/qualityProfile/QualityProfilesPageTest/should_compare.html @@ -0,0 +1,60 @@ + + + + + + + should_display_changelog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
should_display_changelog
open/profiles
waitForElementPresentcss=.quality-profiles-table-name a[href^="/profiles/show?key=xoo-sample"]
clickcss=.quality-profiles-table-name a[href^="/profiles/show?key=xoo-sample"]
waitForElementPresentcss=.quality-profile-header .dropdown-toggle
clickcss=.quality-profile-header .dropdown-toggle
clickcss=#quality-profile-compare
waitForElementPresentcss=.js-profile-comparison .Select
clickcss=.js-profile-comparison .Select-control
+ + diff --git a/it/it-tests/src/test/resources/qualityProfile/QualityProfilesPageTest/should_copy.html b/it/it-tests/src/test/resources/qualityProfile/QualityProfilesPageTest/should_copy.html new file mode 100644 index 00000000000..77bced3828a --- /dev/null +++ b/it/it-tests/src/test/resources/qualityProfile/QualityProfilesPageTest/should_copy.html @@ -0,0 +1,105 @@ + + + + + + + should_create + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
should_create
open/sessions/logout
open/sessions/login
typeid=passwordadmin
typeid=loginadmin
clickAndWaitname=commit
open/profiles
waitForElementPresentcss=.quality-profiles-table-name a[href^="/profiles/show?key=xoo-sample"]
clickcss=.quality-profiles-table-name a[href^="/profiles/show?key=xoo-sample"]
waitForElementPresentcss=.quality-profile-header .dropdown-toggle
clickcss=.quality-profile-header .dropdown-toggle
clickcss=#quality-profile-copy
typecss=#copy-profile-namecopied
clickcss=#copy-profile-submit
waitForTextcss=.quality-profile-header*copied*
waitForTextcss=.quality-profile-rules*1*Bugs*0*Vulnerabilities*0*Code Smells*1*
open/profiles
waitForElementPresentcss=.quality-profiles-table-row[data-name="copied"]
+ + diff --git a/it/it-tests/src/test/resources/qualityProfile/QualityProfilesPageTest/should_create.html b/it/it-tests/src/test/resources/qualityProfile/QualityProfilesPageTest/should_create.html new file mode 100644 index 00000000000..2d9a7f58221 --- /dev/null +++ b/it/it-tests/src/test/resources/qualityProfile/QualityProfilesPageTest/should_create.html @@ -0,0 +1,105 @@ + + + + + + + should_create + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
should_create
open/sessions/logout
open/sessions/login
typeid=passwordadmin
typeid=loginadmin
clickAndWaitname=commit
open/profiles
waitForElementPresentcss=#quality-profiles-create
clickcss=#quality-profiles-create
waitForElementPresentcss=#create-profile-name
assertElementPresentcss=#create-profile-form-backup-XooProfileImporter
typecss=#create-profile-nametest
clickcss=#create-profile-submit
waitForElementPresentcss=.quality-profile-header
waitForTextcss=.quality-profile-header*test*
waitForTextcss=.quality-profile-rules*Bugs*0*Vulnerabilities*0*Code Smells*0*
open/profiles
waitForElementPresentcss=.quality-profiles-table-row[data-name="test"]
+ + diff --git a/it/it-tests/src/test/resources/qualityProfile/QualityProfilesPageTest/should_delete.html b/it/it-tests/src/test/resources/qualityProfile/QualityProfilesPageTest/should_delete.html new file mode 100644 index 00000000000..9ed1f3a6124 --- /dev/null +++ b/it/it-tests/src/test/resources/qualityProfile/QualityProfilesPageTest/should_delete.html @@ -0,0 +1,110 @@ + + + + + + + should_create + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
should_create
open/sessions/logout
open/sessions/login
typeid=passwordadmin
typeid=loginadmin
clickAndWaitname=commit
open/profiles
waitForElementPresentcss=.quality-profiles-table-name a[href^="/profiles/show?key=xoo-sample"]
clickcss=.quality-profiles-table-name a[href^="/profiles/show?key=xoo-sample"]
waitForElementPresentcss=.quality-profile-header .dropdown-toggle
clickcss=.quality-profile-header .dropdown-toggle
clickcss=#quality-profile-delete
waitForElementPresentcss=#delete-profile-submit
clickcss=#delete-profile-submit
waitForElementPresentcss=.quality-profiles-table-row[data-name="Basic"]
waitForElementNotPresentcss=.quality-profiles-table-row[data-name="sample"]
open/profiles
waitForElementPresentcss=.quality-profiles-table-row[data-name="Basic"]
assertElementNotPresentcss=.quality-profiles-table-row[data-name="sample"]
+ + diff --git a/it/it-tests/src/test/resources/qualityProfile/QualityProfilesPageTest/should_display_changelog.html b/it/it-tests/src/test/resources/qualityProfile/QualityProfilesPageTest/should_display_changelog.html new file mode 100644 index 00000000000..18851fbf8b5 --- /dev/null +++ b/it/it-tests/src/test/resources/qualityProfile/QualityProfilesPageTest/should_display_changelog.html @@ -0,0 +1,55 @@ + + + + + + + should_display_changelog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
should_display_changelog
open/profiles
waitForElementPresentcss=.quality-profiles-table-name a[href^="/profiles/show?key=xoo-basic"]
clickcss=.quality-profiles-table-name a[href^="/profiles/show?key=xoo-basic"]
waitForElementPresentcss=a[href^="/profiles/changelog?key=xoo-basic"]
clickcss=a[href^="/profiles/changelog?key=xoo-basic"]
waitForElementPresentcss=.js-profile-changelog-event
assertTextcss=.js-profile-changelog-event*System*Activated*Has Tag*Major*tag*xoo*
+ + diff --git a/it/it-tests/src/test/resources/qualityProfile/QualityProfilesPageTest/should_display_list.html b/it/it-tests/src/test/resources/qualityProfile/QualityProfilesPageTest/should_display_list.html new file mode 100644 index 00000000000..9d171b7bcb1 --- /dev/null +++ b/it/it-tests/src/test/resources/qualityProfile/QualityProfilesPageTest/should_display_list.html @@ -0,0 +1,75 @@ + + + + + + + should_display_list + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
should_display_list
open/profiles
waitForElementPresentcss=.quality-profiles-table
assertElementPresentcss=.quality-profiles-table[data-language="xoo"]
assertElementPresentcss=.quality-profiles-table[data-language="xoo2"]
assertElementPresentcss=.quality-profiles-table-row[data-key^="xoo-basic"]
assertTextcss=.quality-profiles-table-row[data-key^="xoo-basic"] .quality-profiles-table-name*Basic*
assertTextcss=.quality-profiles-table-row[data-key^="xoo-basic"] .quality-profiles-table-projects*Default*
assertTextcss=.quality-profiles-table-row[data-key^="xoo-basic"] .quality-profiles-table-rules*1*
assertElementPresentcss=.quality-profiles-table-row[data-key^="xoo-basic"] .quality-profiles-table-rules a[href^="/coding_rules#qprofile=xoo-basic"]
assertTextcss=.quality-profiles-table-row[data-key^="xoo-empty"] .quality-profiles-table-projects*0*
assertTextcss=.quality-profiles-table-row[data-key^="xoo2-basic"] .quality-profiles-table-name*Basic*
+ + diff --git a/it/it-tests/src/test/resources/qualityProfile/QualityProfilesPageTest/should_display_profile_exporters.html b/it/it-tests/src/test/resources/qualityProfile/QualityProfilesPageTest/should_display_profile_exporters.html new file mode 100644 index 00000000000..aaabd19baac --- /dev/null +++ b/it/it-tests/src/test/resources/qualityProfile/QualityProfilesPageTest/should_display_profile_exporters.html @@ -0,0 +1,50 @@ + + + + + + + should_display_profile_projects.html + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
should_display_profile_projects.html
open/profiles
waitForElementPresentcss=.quality-profiles-table-name a[href^="/profiles/show?key=xoo-sample"]
clickcss=.quality-profiles-table-name a[href^="/profiles/show?key=xoo-sample"]
waitForElementPresentcss=.quality-profile-exporters
waitForElementPresentcss=.quality-profile-exporters [data-key="XooFakeExporter"]
waitForElementPresentcss=.quality-profile-exporters a[href^="/api/qualityprofiles/export"]
+ + diff --git a/it/it-tests/src/test/resources/qualityProfile/QualityProfilesPageTest/should_display_profile_inheritance.html b/it/it-tests/src/test/resources/qualityProfile/QualityProfilesPageTest/should_display_profile_inheritance.html new file mode 100644 index 00000000000..22477a9b4d4 --- /dev/null +++ b/it/it-tests/src/test/resources/qualityProfile/QualityProfilesPageTest/should_display_profile_inheritance.html @@ -0,0 +1,60 @@ + + + + + + + should_display_profile_inheritance.html + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
should_display_profile_inheritance.html
open/profiles
waitForElementPresentcss=.quality-profiles-table-name a[href^="/profiles/show?key=xoo-sample"]
clickcss=.quality-profiles-table-name a[href^="/profiles/show?key=xoo-sample"]
waitForElementPresentcss=.quality-profile-inheritance
waitForElementPresentcss=.js-inheritance-ancestor
assertTextcss=.js-inheritance-ancestor*Basic*1*
assertElementPresentcss=.js-inheritance-current
assertTextcss=.js-inheritance-current*sample*1*
+ + diff --git a/it/it-tests/src/test/resources/qualityProfile/QualityProfilesPageTest/should_display_profile_projects.html b/it/it-tests/src/test/resources/qualityProfile/QualityProfilesPageTest/should_display_profile_projects.html new file mode 100644 index 00000000000..fba5742452a --- /dev/null +++ b/it/it-tests/src/test/resources/qualityProfile/QualityProfilesPageTest/should_display_profile_projects.html @@ -0,0 +1,50 @@ + + + + + + + should_display_profile_projects.html + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
should_display_profile_projects.html
open/profiles
waitForElementPresentcss=.quality-profiles-table-name a[href^="/profiles/show?key=xoo-sample"]
clickcss=.quality-profiles-table-name a[href^="/profiles/show?key=xoo-sample"]
waitForElementPresentcss=.quality-profile-projects
waitForElementPresentcss=.js-profile-project
assertTextcss=.js-profile-project*Sample*
+ + diff --git a/it/it-tests/src/test/resources/qualityProfile/QualityProfilesPageTest/should_display_profile_rules.html b/it/it-tests/src/test/resources/qualityProfile/QualityProfilesPageTest/should_display_profile_rules.html new file mode 100644 index 00000000000..9819f42bdec --- /dev/null +++ b/it/it-tests/src/test/resources/qualityProfile/QualityProfilesPageTest/should_display_profile_rules.html @@ -0,0 +1,45 @@ + + + + + + + should_display_profile_rules.html + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
should_display_profile_rules.html
open/profiles
waitForElementPresentcss=.quality-profiles-table-name a[href^="/profiles/show?key=xoo-basic"]
clickcss=.quality-profiles-table-name a[href^="/profiles/show?key=xoo-basic"]
waitForElementPresentcss=.quality-profile-rules
waitForTextcss=.quality-profile-rules*Active*1*Bugs*0*Vulnerabilities*0*Code Smells*1*
+ + diff --git a/it/it-tests/src/test/resources/qualityProfile/QualityProfilesPageTest/should_filter_by_language.html b/it/it-tests/src/test/resources/qualityProfile/QualityProfilesPageTest/should_filter_by_language.html new file mode 100644 index 00000000000..192ad66f497 --- /dev/null +++ b/it/it-tests/src/test/resources/qualityProfile/QualityProfilesPageTest/should_filter_by_language.html @@ -0,0 +1,90 @@ + + + + + + + should_filter_by_language + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
should_filter_by_language
open/profiles
waitForElementPresentcss=.quality-profiles-table[data-language="xoo"]
assertElementPresentcss=.quality-profiles-table[data-language="xoo2"]
assertTextcss=.js-language-filter*All*
clickcss=.js-language-filter
waitForElementPresentcss=.js-language-filter-option[data-language="xoo2"]
clickcss=.js-language-filter-option[data-language="xoo2"]
waitForElementNotPresentcss=.quality-profiles-table[data-language="xoo"]
assertElementPresentcss=.quality-profiles-table[data-language="xoo2"]
assertTextcss=.js-language-filter*Xoo2*
open/profiles?language=xoo2
waitForElementPresentcss=.quality-profiles-table[data-language="xoo2"]
assertElementNotPresentcss=.quality-profiles-table[data-language="xoo"]
assertTextcss=.js-language-filter*Xoo2*
+ + diff --git a/it/it-tests/src/test/resources/qualityProfile/QualityProfilesPageTest/should_open_from_list.html b/it/it-tests/src/test/resources/qualityProfile/QualityProfilesPageTest/should_open_from_list.html new file mode 100644 index 00000000000..8a8adb9c0d0 --- /dev/null +++ b/it/it-tests/src/test/resources/qualityProfile/QualityProfilesPageTest/should_open_from_list.html @@ -0,0 +1,55 @@ + + + + + + + should_open_from_list + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
should_open_from_list
open/profiles
waitForElementPresentcss=.quality-profiles-table-row[data-key^="xoo-basic"]
clickcss=.quality-profiles-table-row[data-key^="xoo-basic"] .quality-profiles-table-name a
waitForElementPresentcss=.quality-profile-header
waitForElementPresentcss=.quality-profile-rules
waitForElementPresentcss=.quality-profile-inheritance
waitForElementPresentcss=.quality-profile-projects
+ + diff --git a/it/it-tests/src/test/resources/qualityProfile/QualityProfilesPageTest/should_rename.html b/it/it-tests/src/test/resources/qualityProfile/QualityProfilesPageTest/should_rename.html new file mode 100644 index 00000000000..059057a3d31 --- /dev/null +++ b/it/it-tests/src/test/resources/qualityProfile/QualityProfilesPageTest/should_rename.html @@ -0,0 +1,110 @@ + + + + + + + should_create + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
should_create
open/sessions/logout
open/sessions/login
typeid=passwordadmin
typeid=loginadmin
clickAndWaitname=commit
open/profiles
waitForElementPresentcss=.quality-profiles-table-name a[href^="/profiles/show?key=xoo-sample"]
clickcss=.quality-profiles-table-name a[href^="/profiles/show?key=xoo-sample"]
waitForElementPresentcss=.quality-profile-header .dropdown-toggle
clickcss=.quality-profile-header .dropdown-toggle
clickcss=#quality-profile-rename
waitForElementPresentcss=#rename-profile-name
typecss=#rename-profile-namenew name
clickcss=#rename-profile-submit
waitForTextcss=.quality-profile-header*new name*
open/profiles
waitForElementPresentcss=.quality-profiles-table-name a[href^="/profiles/show?key=xoo-sample"]
assertElementPresentcss=.quality-profiles-table-row[data-name="new name"]
+ + diff --git a/it/it-tests/src/test/resources/qualityProfile/QualityProfilesPageTest/should_restore.html b/it/it-tests/src/test/resources/qualityProfile/QualityProfilesPageTest/should_restore.html new file mode 100644 index 00000000000..d35885921b2 --- /dev/null +++ b/it/it-tests/src/test/resources/qualityProfile/QualityProfilesPageTest/should_restore.html @@ -0,0 +1,70 @@ + + + + + + + should_create + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
should_create
open/sessions/logout
open/sessions/login
typeid=passwordadmin
typeid=loginadmin
clickAndWaitname=commit
open/profiles
waitForElementPresentcss=#quality-profiles-restore
clickcss=#quality-profiles-restore
waitForElementPresentcss=#restore-profile-backup
waitForElementPresentcss=#restore-profile-submit
+ + diff --git a/it/it-tests/src/test/resources/qualityProfile/QualityProfilesPageTest/should_restore_built_in.html b/it/it-tests/src/test/resources/qualityProfile/QualityProfilesPageTest/should_restore_built_in.html new file mode 100644 index 00000000000..2ece1415652 --- /dev/null +++ b/it/it-tests/src/test/resources/qualityProfile/QualityProfilesPageTest/should_restore_built_in.html @@ -0,0 +1,90 @@ + + + + + + + should_create + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
should_create
open/sessions/logout
open/sessions/login
typeid=passwordadmin
typeid=loginadmin
clickAndWaitname=commit
open/profiles
waitForElementPresentcss=.js-restore-built-in[data-language="xoo"]
assertElementNotPresentcss=.quality-profiles-table-row[data-name="empty"]
clickcss=.js-restore-built-in[data-language="xoo"]
waitForElementPresentcss=#restore-built-in-profiles-submit
clickcss=#restore-built-in-profiles-submit
waitForElementPresentcss=#restore-built-in-profiles-form .alert-success
clickcss=.js-modal-close
waitForElementPresentcss=.quality-profiles-table-row[data-name="empty"]
+ + diff --git a/it/it-tests/src/test/resources/qualityProfile/QualityProfilesPageTest/should_set_default.html b/it/it-tests/src/test/resources/qualityProfile/QualityProfilesPageTest/should_set_default.html new file mode 100644 index 00000000000..11c15d492be --- /dev/null +++ b/it/it-tests/src/test/resources/qualityProfile/QualityProfilesPageTest/should_set_default.html @@ -0,0 +1,95 @@ + + + + + + + should_create + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
should_create
open/sessions/logout
open/sessions/login
typeid=passwordadmin
typeid=loginadmin
clickAndWaitname=commit
open/profiles
waitForElementPresentcss=.quality-profiles-table-name a[href^="/profiles/show?key=xoo-sample"]
clickcss=.quality-profiles-table-name a[href^="/profiles/show?key=xoo-sample"]
waitForElementPresentcss=.quality-profile-header .dropdown-toggle
clickcss=.quality-profile-header .dropdown-toggle
clickcss=#quality-profile-set-as-default
waitForTextcss=.quality-profile-projects*Default*
open/profiles
waitForElementPresentcss=.quality-profiles-table-row[data-name="sample"]
assertTextcss=.quality-profiles-table-row[data-name="sample"] .quality-profiles-table-projects*Default*
+ + diff --git a/server/sonar-web/src/main/js/api/quality-profiles.js b/server/sonar-web/src/main/js/api/quality-profiles.js index 8172dec3517..4ddb455e9e6 100644 --- a/server/sonar-web/src/main/js/api/quality-profiles.js +++ b/server/sonar-web/src/main/js/api/quality-profiles.js @@ -17,7 +17,19 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -import { request, checkStatus, parseJSON } from '../helpers/request'; +import { + request, + checkStatus, + parseJSON, + getJSON, + post, + postJSON +} from '../helpers/request'; + +export function getQualityProfiles () { + const url = '/api/qualityprofiles/search'; + return getJSON(url).then(r => r.profiles); +} export function createQualityProfile (data) { return request('/api/qualityprofiles/create') @@ -36,3 +48,118 @@ export function restoreQualityProfile (data) { .then(checkStatus) .then(parseJSON); } + +export function getProfileProjects (data) { + const url = '/api/qualityprofiles/projects'; + return getJSON(url, data); +} + +export function getProfileInheritance (profileKey) { + const url = '/api/qualityprofiles/inheritance'; + const data = { profileKey }; + return getJSON(url, data); +} + +export function setDefaultProfile (profileKey) { + const url = '/api/qualityprofiles/set_default'; + const data = { profileKey }; + return post(url, data); +} + +/** + * Rename profile + * @param {string} key + * @param {string} name + * @returns {Promise} + */ +export function renameProfile (key, name) { + const url = '/api/qualityprofiles/rename'; + const data = { key, name }; + return post(url, data); +} + +/** + * Copy profile + * @param {string} fromKey + * @param {string} toName + * @returns {Promise} + */ +export function copyProfile (fromKey, toName) { + const url = '/api/qualityprofiles/copy'; + const data = { fromKey, toName }; + return postJSON(url, data); +} + +/** + * Delete profile + * @param {string} profileKey + * @returns {Promise} + */ +export function deleteProfile (profileKey) { + const url = '/api/qualityprofiles/delete'; + const data = { profileKey }; + return post(url, data); +} + +/** + * Change profile parent + * @param {string} profileKey + * @param {string} parentKey + * @returns {Promise} + */ +export function changeProfileParent (profileKey, parentKey) { + const url = '/api/qualityprofiles/change_parent'; + const data = { profileKey, parentKey }; + return post(url, data); +} + +/** + * Get list of available importers + * @returns {Promise} + */ +export function getImporters () { + const url = '/api/qualityprofiles/importers'; + return getJSON(url).then(r => r.importers); +} + +/** + * Get list of available exporters + * @returns {Promise} + */ +export function getExporters () { + const url = '/api/qualityprofiles/exporters'; + return getJSON(url).then(r => r.exporters); +} + +/** + * Restore built-in profiles + * @param {string} languageKey + * @returns {Promise} + */ +export function restoreBuiltInProfiles (languageKey) { + const url = '/api/qualityprofiles/restore_built_in'; + const data = { language: languageKey }; + return post(url, data); +} + +/** + * Get changelog of a quality profile + * @param {Object} data API parameters + * @returns {Promise} + */ +export function getProfileChangelog (data) { + const url = '/api/qualityprofiles/changelog'; + return getJSON(url, data); +} + +/** + * Compare two profiles + * @param {string} leftKey + * @param {string} rightKey + * @returns {Promise} + */ +export function compareProfiles (leftKey, rightKey) { + const url = '/api/qualityprofiles/compare'; + const data = { leftKey, rightKey }; + return getJSON(url, data); +} diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/intro-view.js b/server/sonar-web/src/main/js/api/rules.js similarity index 73% rename from server/sonar-web/src/main/js/apps/quality-profiles/intro-view.js rename to server/sonar-web/src/main/js/api/rules.js index 924a99ef640..825e114d0f7 100644 --- a/server/sonar-web/src/main/js/apps/quality-profiles/intro-view.js +++ b/server/sonar-web/src/main/js/api/rules.js @@ -17,10 +17,14 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -import Marionette from 'backbone.marionette'; -import Template from './templates/quality-profiles-intro.hbs'; +import { getJSON } from '../helpers/request'; -export default Marionette.ItemView.extend({ - template: Template -}); +export function searchRules (data) { + const url = '/api/rules/search'; + return getJSON(url, data); +} +export function takeFacet (response, property) { + const facet = response.facets.find(facet => facet.property === property); + return facet ? facet.values : []; +} diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/__tests__/utils-test.js b/server/sonar-web/src/main/js/apps/quality-profiles/__tests__/utils-test.js new file mode 100644 index 00000000000..97811993e43 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/quality-profiles/__tests__/utils-test.js @@ -0,0 +1,74 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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 { expect } from 'chai'; +import { sortProfiles } from '../utils'; + +function createProfile (key, parentKey) { + return { name: key, key, parentKey }; +} + +function checkOrder (list, order) { + const listKeys = list.map(item => item.key); + expect(listKeys).to.deep.equal(order); +} + +describe('Quality Profiles :: Utils', () => { + describe('#sortProfiles', () => { + it('should sort when no parents', () => { + const profile1 = createProfile('profile1'); + const profile2 = createProfile('profile2'); + const profile3 = createProfile('profile3'); + checkOrder( + sortProfiles([profile1, profile2, profile3]), + ['profile1', 'profile2', 'profile3'] + ); + }); + + it('should sort by name', () => { + const profile1 = createProfile('profile1'); + const profile2 = createProfile('profile2'); + const profile3 = createProfile('profile3'); + checkOrder( + sortProfiles([profile3, profile1, profile2]), + ['profile1', 'profile2', 'profile3'] + ); + }); + + it('should sort with children', () => { + const child1 = createProfile('child1', 'parent'); + const child2 = createProfile('child2', 'parent'); + const parent = createProfile('parent'); + checkOrder( + sortProfiles([child1, child2, parent]), + ['parent', 'child1', 'child2'] + ); + }); + + it('should sort single branch', () => { + const profile1 = createProfile('profile1'); + const profile2 = createProfile('profile2', 'profile3'); + const profile3 = createProfile('profile3', 'profile1'); + checkOrder( + sortProfiles([profile3, profile2, profile1]), + ['profile1', 'profile3', 'profile2'] + ); + }); + }); +}); diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/actions-view.js b/server/sonar-web/src/main/js/apps/quality-profiles/actions-view.js deleted file mode 100644 index ae5c603d3cb..00000000000 --- a/server/sonar-web/src/main/js/apps/quality-profiles/actions-view.js +++ /dev/null @@ -1,114 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2016 SonarSource SA - * mailto:contact 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 $ from 'jquery'; -import _ from 'underscore'; -import Marionette from 'backbone.marionette'; -import CreateProfileView from './create-profile-view'; -import RestoreProfileView from './restore-profile-view'; -import RestoreBuiltInProfilesView from './restore-built-in-profiles-view'; -import Template from './templates/quality-profiles-actions.hbs'; - -export default Marionette.ItemView.extend({ - template: Template, - - events: { - 'click #quality-profiles-create': 'onCreateClick', - 'click #quality-profiles-restore': 'onRestoreClick', - 'click #quality-profiles-restore-built-in': 'onRestoreBuiltInClick', - - 'click .js-filter-by-language': 'onLanguageClick' - }, - - onCreateClick (e) { - e.preventDefault(); - this.create(); - }, - - onRestoreClick (e) { - e.preventDefault(); - this.restore(); - }, - - onRestoreBuiltInClick (e) { - e.preventDefault(); - this.restoreBuiltIn(); - }, - - onLanguageClick (e) { - e.preventDefault(); - const language = $(e.currentTarget).data('language'); - this.filterByLanguage(language); - }, - - create () { - const that = this; - this.requestImporters().done(function () { - new CreateProfileView({ - collection: that.collection, - languages: that.languages, - importers: that.importers - }).render(); - }); - }, - - restore () { - new RestoreProfileView({ - collection: this.collection - }).render(); - }, - - restoreBuiltIn () { - new RestoreBuiltInProfilesView({ - collection: this.collection, - languages: this.languages - }).render(); - }, - - requestLanguages () { - const that = this; - const url = window.baseUrl + '/api/languages/list'; - return $.get(url).done(function (r) { - that.languages = r.languages; - }); - }, - - requestImporters () { - const that = this; - const url = window.baseUrl + '/api/qualityprofiles/importers'; - return $.get(url).done(function (r) { - that.importers = r.importers; - }); - }, - - filterByLanguage (language) { - this.selectedLanguage = _.findWhere(this.languages, { key: language }); - this.render(); - this.collection.trigger('filter', language); - }, - - serializeData () { - return _.extend(Marionette.ItemView.prototype.serializeData.apply(this, arguments), { - canWrite: this.options.canWrite, - languages: this.languages, - selectedLanguage: this.selectedLanguage - }); - } -}); - diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/app.js b/server/sonar-web/src/main/js/apps/quality-profiles/app.js index 74a8511776c..cb998c8edfc 100644 --- a/server/sonar-web/src/main/js/apps/quality-profiles/app.js +++ b/server/sonar-web/src/main/js/apps/quality-profiles/app.js @@ -17,66 +17,43 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -import $ from 'jquery'; -import Backbone from 'backbone'; -import Marionette from 'backbone.marionette'; -import Router from './router'; -import Controller from './controller'; -import Layout from './layout'; -import Profiles from './profiles'; -import ActionsView from './actions-view'; -import ProfilesView from './profiles-view'; - -const App = new Marionette.Application(); -const requestUser = $.get(window.baseUrl + '/api/users/current').done(function (r) { - App.canWrite = r.permissions.global.indexOf('profileadmin') !== -1; -}); -const requestExporters = $.get(window.baseUrl + '/api/qualityprofiles/exporters').done(function (r) { - App.exporters = r.exporters; -}); -const init = function () { - const options = window.sonarqube; - - // Layout - this.layout = new Layout({ el: options.el }); - this.layout.render(); - $('#footer').addClass('search-navigator-footer'); - - // Profiles List - this.profiles = new Profiles(); - - // Controller - this.controller = new Controller({ app: this }); - - // Actions View - this.actionsView = new ActionsView({ - collection: this.profiles, - canWrite: this.canWrite - }); - this.actionsView.requestLanguages().done(function () { - App.layout.actionsRegion.show(App.actionsView); +import React from 'react'; +import { render } from 'react-dom'; +import { + Router, + Route, + IndexRoute, + Redirect, + useRouterHistory +} from 'react-router'; +import { createHistory } from 'history'; +import App from './components/App'; +import ProfileContainer from './components/ProfileContainer'; +import HomeContainer from './home/HomeContainer'; +import ProfileDetails from './details/ProfileDetails'; +import ChangelogContainer from './changelog/ChangelogContainer'; +import ComparisonContainer from './compare/ComparisonContainer'; + +window.sonarqube.appStarted.then(options => { + const el = document.querySelector(options.el); + + const history = useRouterHistory(createHistory)({ + basename: window.baseUrl + '/profiles' }); - // Profiles View - this.profilesView = new ProfilesView({ - collection: this.profiles, - canWrite: this.canWrite - }); - this.layout.resultsRegion.show(this.profilesView); - - // Router - this.router = new Router({ app: this }); - Backbone.history.start({ - pushState: true, - root: options.urlRoot - }); -}; - -App.on('start', function () { - $.when(requestUser, requestExporters).done(function () { - init.call(App); - }); + render(( + + + + + + + + + + + + + + ), el); }); - -window.sonarqube.appStarted.then(options => App.start(options)); - diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/changelog/Changelog.js b/server/sonar-web/src/main/js/apps/quality-profiles/changelog/Changelog.js new file mode 100644 index 00000000000..b7c8184d488 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/quality-profiles/changelog/Changelog.js @@ -0,0 +1,81 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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 React from 'react'; +import moment from 'moment'; +import ChangesList from './ChangesList'; +import { translate } from '../../../helpers/l10n'; +import { getRulesUrl } from '../../../helpers/urls'; + +export default class Changelog extends React.Component { + static propTypes = { + events: React.PropTypes.array.isRequired + }; + + render () { + const rows = this.props.events.map((event, index) => ( + + + {moment(event.date).format('LLL')} + + + + {event.authorName ? ( + {event.authorName} + ) : ( + System + )} + + + + {translate('quality_profiles.changelog', event.action)} + + + + + {event.ruleName} + + + + + + + + )); + + return ( + + + + + + + + + + + {rows} +
+ {translate('date')} + {' '} + + {translate('user')}{translate('action')}{translate('rule')}{translate('parameters')}
+ ); + } +} diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/changelog/ChangelogContainer.js b/server/sonar-web/src/main/js/apps/quality-profiles/changelog/ChangelogContainer.js new file mode 100644 index 00000000000..247b3a6f402 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/quality-profiles/changelog/ChangelogContainer.js @@ -0,0 +1,128 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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 React from 'react'; +import Changelog from './Changelog'; +import ChangelogSearch from './ChangelogSearch'; +import ChangelogEmpty from './ChangelogEmpty'; +import { getProfileChangelog } from '../../../api/quality-profiles'; +import { ProfileType } from '../propTypes'; + +export default class ChangelogContainer extends React.Component { + static propTypes = { + location: React.PropTypes.object.isRequired, + profile: ProfileType + }; + + static contextTypes = { + router: React.PropTypes.object + }; + + state = { + loading: true + }; + + componentWillMount () { + this.handleFromDateChange = this.handleFromDateChange.bind(this); + this.handleToDateChange = this.handleToDateChange.bind(this); + this.handleReset = this.handleReset.bind(this); + } + + componentDidMount () { + this.mounted = true; + this.loadChangelog(); + } + + componentDidUpdate (prevProps) { + if (prevProps.location !== this.props.location) { + this.loadChangelog(); + } + } + + componentWillUnmount () { + this.mounted = false; + } + + loadChangelog () { + this.setState({ loading: true }); + const { query } = this.props.location; + const data = { profileKey: this.props.profile.key }; + if (query.since) { + data.since = query.since; + } + if (query.to) { + data.to = query.to; + } + + getProfileChangelog(data).then(r => { + if (this.mounted) { + this.setState({ + events: r.events, + total: r.total, + page: r.p, + loading: false + }); + } + }); + } + + handleFromDateChange (fromDate) { + const query = { ...this.props.location.query, since: fromDate }; + this.context.router.push({ pathname: '/changelog', query }); + } + + handleToDateChange (toDate) { + const query = { ...this.props.location.query, to: toDate }; + this.context.router.push({ pathname: '/changelog', query }); + } + + handleReset () { + const query = { key: this.props.profile.key }; + this.context.router.push({ pathname: '/changelog', query }); + } + + render () { + const { query } = this.props.location; + + return ( +
+
+ + + {this.state.loading && ( + + )} +
+ + {this.state.events != null && this.state.events.length === 0 && ( + + )} + + {this.state.events != null && this.state.events.length > 0 && ( + + )} +
+ ); + } +} diff --git a/it/it-tests/src/test/java/it/qualityProfile/ToDoTest.java b/server/sonar-web/src/main/js/apps/quality-profiles/changelog/ChangelogEmpty.js similarity index 76% rename from it/it-tests/src/test/java/it/qualityProfile/ToDoTest.java rename to server/sonar-web/src/main/js/apps/quality-profiles/changelog/ChangelogEmpty.js index 1823f9779be..797e551454b 100644 --- a/it/it-tests/src/test/java/it/qualityProfile/ToDoTest.java +++ b/server/sonar-web/src/main/js/apps/quality-profiles/changelog/ChangelogEmpty.js @@ -17,7 +17,15 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -package it.qualityProfile; +import React from 'react'; +import { translate } from '../../../helpers/l10n'; -public class ToDoTest { +export default class ChangelogEmpty extends React.Component { + render () { + return ( +
+ {translate('no_results')} +
+ ); + } } diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/changelog/ChangelogSearch.js b/server/sonar-web/src/main/js/apps/quality-profiles/changelog/ChangelogSearch.js new file mode 100644 index 00000000000..1093f7fe3ac --- /dev/null +++ b/server/sonar-web/src/main/js/apps/quality-profiles/changelog/ChangelogSearch.js @@ -0,0 +1,62 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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 React from 'react'; +import DateInput from '../../../components/controls/DateInput'; +import { translate } from '../../../helpers/l10n'; + +export default class ChangelogSearch extends React.Component { + static propTypes = { + fromDate: React.PropTypes.string, + toDate: React.PropTypes.string, + onFromDateChange: React.PropTypes.func.isRequired, + onToDateChange: React.PropTypes.func.isRequired, + onReset: React.PropTypes.func.isRequired + }; + + handleResetClick (e) { + e.preventDefault(); + e.target.blur(); + this.props.onReset(); + } + + render () { + return ( +
+ + {' — '} + + +
+ ); + } +} diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/changelog/ChangesList.js b/server/sonar-web/src/main/js/apps/quality-profiles/changelog/ChangesList.js new file mode 100644 index 00000000000..5a413b0a856 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/quality-profiles/changelog/ChangesList.js @@ -0,0 +1,46 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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 React from 'react'; +import SeverityChange from './SeverityChange'; +import ParameterChange from './ParameterChange'; + +export default class ChangesList extends React.Component { + static propTypes = { + changes: React.PropTypes.object.isRequired + }; + + render () { + const { changes } = this.props; + + return ( +
    + {Object.keys(changes).map(key => ( +
  • + {key === 'severity' ? ( + + ) : ( + + )} +
  • + ))} +
+ ); + } +} diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/changelog/ParameterChange.js b/server/sonar-web/src/main/js/apps/quality-profiles/changelog/ParameterChange.js new file mode 100644 index 00000000000..82e685af470 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/quality-profiles/changelog/ParameterChange.js @@ -0,0 +1,53 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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 React from 'react'; +import { translateWithParameters } from '../../../helpers/l10n'; + +export default class ParameterChange extends React.Component { + static propTypes = { + name: React.PropTypes.string.isRequired, + value: React.PropTypes.any + }; + + render () { + const { name, value } = this.props; + + if (value == null) { + return ( +
+ {translateWithParameters( + 'quality_profiles.changelog.parameter_reset_to_default_value', + name + )} +
+ ); + } + + return ( +
+ {translateWithParameters( + 'quality_profiles.parameter_set_to', + name, + value + )} +
+ ); + } +} diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/changelog/SeverityChange.js b/server/sonar-web/src/main/js/apps/quality-profiles/changelog/SeverityChange.js new file mode 100644 index 00000000000..2b854311455 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/quality-profiles/changelog/SeverityChange.js @@ -0,0 +1,38 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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 React from 'react'; +import SeverityHelper from '../../../components/shared/severity-helper'; +import { translate } from '../../../helpers/l10n'; + +export default class SeverityChange extends React.Component { + static propTypes = { + severity: React.PropTypes.string.isRequired + }; + + render () { + return ( +
+ {translate('quality_profiles.severity_set_to')} + {' '} + +
+ ); + } +} diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/changelog/__tests__/Changelog-test.js b/server/sonar-web/src/main/js/apps/quality-profiles/changelog/__tests__/Changelog-test.js new file mode 100644 index 00000000000..9a36c64207f --- /dev/null +++ b/server/sonar-web/src/main/js/apps/quality-profiles/changelog/__tests__/Changelog-test.js @@ -0,0 +1,84 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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 { expect } from 'chai'; +import { shallow } from 'enzyme'; +import React from 'react'; +import Changelog from '../Changelog'; +import ChangesList from '../ChangesList'; + +function createEvent (overrides) { + return { + date: '2016-01-01', + authorName: 'John', + action: 'ACTIVATED', + ruleKey: 'squid1234', + ruleName: 'Do not do this', + params: {}, + ...overrides + }; +} + +describe('Quality Profiles :: Changelog', () => { + it('should render events', () => { + const events = [createEvent(), createEvent()]; + const changelog = shallow(); + expect(changelog.find('tbody').find('tr')).to.have.length(2); + }); + + it('should render event date', () => { + const events = [createEvent()]; + const changelog = shallow(); + expect(changelog.text()).to.include('2016'); + }); + + it('should render author', () => { + const events = [createEvent()]; + const changelog = shallow(); + expect(changelog.text()).to.include('John'); + }); + + it('should render system author', () => { + const events = [createEvent({ authorName: undefined })]; + const changelog = shallow(); + expect(changelog.text()).to.include('System'); + }); + + it('should render action', () => { + const events = [createEvent()]; + const changelog = shallow(); + expect(changelog.text()).to.include('ACTIVATED'); + }); + + it('should render rule', () => { + const events = [createEvent()]; + const changelog = shallow(); + expect(changelog.text()).to.include('Do not do this'); + expect(changelog.find('a').prop('href')).to.include('rule_key=squid1234'); + }); + + it('should render ChangesList', () => { + const params = { severity: 'BLOCKER' }; + const events = [createEvent({ params })]; + const changelog = shallow(); + const changesList = changelog.find(ChangesList); + expect(changesList).to.have.length(1); + expect(changesList.prop('changes')).to.equal(params); + }); +}); diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/changelog/__tests__/ChangelogSearch-test.js b/server/sonar-web/src/main/js/apps/quality-profiles/changelog/__tests__/ChangelogSearch-test.js new file mode 100644 index 00000000000..302273cedf4 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/quality-profiles/changelog/__tests__/ChangelogSearch-test.js @@ -0,0 +1,68 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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 { expect } from 'chai'; +import { shallow } from 'enzyme'; +import sinon from 'sinon'; +import React from 'react'; +import ChangelogSearch from '../ChangelogSearch'; +import DateInput from '../../../../components/controls/DateInput'; + +function click (element) { + return element.simulate('click', { + target: { blur () {} }, + preventDefault () {} + }); +} + +describe('Quality Profiles :: ChangelogSearch', () => { + it('should render DateInput', () => { + const onFromDateChange = sinon.spy(); + const onToDateChange = sinon.spy(); + const output = shallow( + + ); + const dateInputs = output.find(DateInput); + expect(dateInputs).to.have.length(2); + expect(dateInputs.at(0).prop('value')).to.equal('2016-01-01'); + expect(dateInputs.at(0).prop('onChange')).to.equal(onFromDateChange); + expect(dateInputs.at(1).prop('value')).to.equal('2016-05-05'); + expect(dateInputs.at(1).prop('onChange')).to.equal(onToDateChange); + }); + + it('should reset', () => { + const onReset = sinon.spy(); + const output = shallow( + + ); + expect(onReset.called).to.equal(false); + click(output.find('button')); + expect(onReset.called).to.equal(true); + }); +}); diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/changelog/__tests__/ChangesList-test.js b/server/sonar-web/src/main/js/apps/quality-profiles/changelog/__tests__/ChangesList-test.js new file mode 100644 index 00000000000..86e194b22aa --- /dev/null +++ b/server/sonar-web/src/main/js/apps/quality-profiles/changelog/__tests__/ChangesList-test.js @@ -0,0 +1,54 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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 { expect } from 'chai'; +import { shallow } from 'enzyme'; +import React from 'react'; +import ChangesList from '../ChangesList'; +import SeverityChange from '../SeverityChange'; +import ParameterChange from '../ParameterChange'; + +describe('Quality Profiles :: ChangesList', () => { + it('should render changes', () => { + const changes = { severity: 'BLOCKER', foo: 'bar' }; + const output = shallow( + + ); + expect(output.find('li')).to.have.length(2); + }); + + it('should render severity change', () => { + const changes = { severity: 'BLOCKER' }; + const output = shallow( + + ).find(SeverityChange); + expect(output).to.have.length(1); + expect(output.prop('severity')).to.equal('BLOCKER'); + }); + + it('should render parameter change', () => { + const changes = { foo: 'bar' }; + const output = shallow( + + ).find(ParameterChange); + expect(output).to.have.length(1); + expect(output.prop('name')).to.equal('foo'); + expect(output.prop('value')).to.equal('bar'); + }); +}); diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/changelog/__tests__/ParameterChange-test.js b/server/sonar-web/src/main/js/apps/quality-profiles/changelog/__tests__/ParameterChange-test.js new file mode 100644 index 00000000000..1845b09c506 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/quality-profiles/changelog/__tests__/ParameterChange-test.js @@ -0,0 +1,31 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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 { expect } from 'chai'; +import { shallow } from 'enzyme'; +import React from 'react'; +import ParameterChange from '../ParameterChange'; + +describe('Quality Profiles :: ParameterChange', () => { + it('should render different messages', () => { + const first = shallow(); + const second = shallow(); + expect(first.text()).to.not.be.equal(second.text()); + }); +}); diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/changelog/__tests__/SeverityChange-test.js b/server/sonar-web/src/main/js/apps/quality-profiles/changelog/__tests__/SeverityChange-test.js new file mode 100644 index 00000000000..3a7fcb37b29 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/quality-profiles/changelog/__tests__/SeverityChange-test.js @@ -0,0 +1,34 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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 { expect } from 'chai'; +import { shallow } from 'enzyme'; +import React from 'react'; +import SeverityChange from '../SeverityChange'; +import SeverityHelper from '../../../../components/shared/severity-helper'; + +describe('Quality Profiles :: SeverityChange', () => { + it('should render SeverityHelper', () => { + const output = shallow( + + ).find(SeverityHelper); + expect(output).to.have.length(1); + expect(output.prop('severity')).to.equal('BLOCKER'); + }); +}); diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/compare/ComparisonContainer.js b/server/sonar-web/src/main/js/apps/quality-profiles/compare/ComparisonContainer.js new file mode 100644 index 00000000000..03d5d145212 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/quality-profiles/compare/ComparisonContainer.js @@ -0,0 +1,122 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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 React from 'react'; +import ComparisonForm from './ComparisonForm'; +import ComparisonResults from './ComparisonResults'; +import { ProfileType, ProfilesListType } from '../propTypes'; +import { compareProfiles } from '../../../api/quality-profiles'; + +export default class ComparisonContainer extends React.Component { + static propTypes = { + profile: ProfileType, + profiles: ProfilesListType + }; + + static contextTypes = { + router: React.PropTypes.object + }; + + state = { + loading: false + }; + + componentWillMount () { + this.handleCompare = this.handleCompare.bind(this); + } + + componentDidMount () { + this.mounted = true; + this.loadResults(); + } + + componentDidUpdate (prevProps) { + if (prevProps.profile !== this.props.profile || + prevProps.location !== this.props.location) { + this.loadResults(); + } + } + + componentWillUnmount () { + this.mounted = false; + } + + loadResults () { + const { withKey } = this.props.location.query; + if (!withKey) { + this.setState({ left: null, loading: false }); + return; + } + + this.setState({ loading: true }); + compareProfiles(this.props.profile.key, withKey).then(r => { + if (this.mounted) { + this.setState({ + left: r.left, + right: r.right, + inLeft: r.inLeft, + inRight: r.inRight, + modified: r.modified, + loading: false + }); + } + }); + } + + handleCompare (withKey) { + this.context.router.push({ + pathname: '/compare', + query: { + key: this.props.profile.key, + withKey + } + }); + } + + render () { + const { profile, profiles, location } = this.props; + const { withKey } = location.query; + const { left, right, inLeft, inRight, modified } = this.state; + + return ( +
+
+ + + {this.state.loading && ( + + )} +
+ + {left != null && ( + + )} +
+ ); + } +} diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/profiles-empty-view.js b/server/sonar-web/src/main/js/apps/quality-profiles/compare/ComparisonEmpty.js similarity index 74% rename from server/sonar-web/src/main/js/apps/quality-profiles/profiles-empty-view.js rename to server/sonar-web/src/main/js/apps/quality-profiles/compare/ComparisonEmpty.js index 9dbd11e1ea6..d3e49aedf26 100644 --- a/server/sonar-web/src/main/js/apps/quality-profiles/profiles-empty-view.js +++ b/server/sonar-web/src/main/js/apps/quality-profiles/compare/ComparisonEmpty.js @@ -17,11 +17,15 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -import Marionette from 'backbone.marionette'; -import Template from './templates/quality-profiles-empty.hbs'; - -export default Marionette.ItemView.extend({ - className: 'list-group-item', - template: Template -}); +import React from 'react'; +import { translate } from '../../../helpers/l10n'; +export default class ComparisonEmpty extends React.Component { + render () { + return ( +
+ {translate('quality_profile.empty_comparison')} +
+ ); + } +} diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/compare/ComparisonForm.js b/server/sonar-web/src/main/js/apps/quality-profiles/compare/ComparisonForm.js new file mode 100644 index 00000000000..149a8092066 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/quality-profiles/compare/ComparisonForm.js @@ -0,0 +1,56 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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 React from 'react'; +import Select from 'react-select'; +import { ProfileType, ProfilesListType } from '../propTypes'; +import { translate } from '../../../helpers/l10n'; + +export default class ComparisonForm extends React.Component { + static propTypes = { + profile: ProfileType.isRequired, + profiles: ProfilesListType.isRequired, + onCompare: React.PropTypes.func.isRequired + }; + + handleChange (option) { + this.props.onCompare(option.value); + } + + render () { + const { profile, profiles, withKey } = this.props; + const options = profiles + .filter(p => p.language === profile.language && p !== profile) + .map(p => ({ value: p.key, label: p.name })); + + return ( +
+ + - {{t 'to'}} - - - - -{{#notEmpty events}} - - - - - - - - - - - - {{#each events}} - - - - - - - - {{/each}} - -
{{t 'date'}}{{t 'user'}}{{t 'action'}}{{t 'rule'}}{{t 'parameters'}}
{{dt date}}{{default authorName 'System'}}{{t 'quality_profiles.changelog' action}}{{ruleName}} -
    - {{#each params}} -
  • - {{#eq @key 'severity'}} - {{severityChangelog this}} - {{else}} - {{parameterChangelog @key this}} - {{/eq}} -
  • - {{/each}} -
-
- - -

- {{#unlessLength events totalEvents}} - {{t 'show_more'}} - {{/unlessLength}} - {{t 'hide'}} -

- -{{else}} - {{#notNull totalEvents}} -
- {{t 'quality_profiles.changelog.empty'}} - {{t 'hide'}} -
- {{/notNull}} -{{/notEmpty}} diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/templates/quality-profile-comparison.hbs b/server/sonar-web/src/main/js/apps/quality-profiles/templates/quality-profile-comparison.hbs deleted file mode 100644 index e26259b6bad..00000000000 --- a/server/sonar-web/src/main/js/apps/quality-profiles/templates/quality-profile-comparison.hbs +++ /dev/null @@ -1,89 +0,0 @@ - - -{{#notEmpty profiles}} -
- - - -
-{{else}} -
{{t 'quality_profiles.no_profiles_for_comparison'}}
-{{/notEmpty}} - -{{#notNull comparison}} - - {{#notEmpty comparison.inLeft}} - - - - - {{#each comparison.inLeft}} - - - - - {{/each}} - {{/notEmpty}} - - {{#notEmpty comparison.inRight}} - - - - - {{#each comparison.inRight}} - - - - - {{/each}} - {{/notEmpty}} - - {{#notEmpty comparison.modified}} - - - - - - - - {{#each comparison.modified}} - - - - - {{/each}} - {{/notEmpty}} -
{{tp 'quality_profiles.x_rules_only_in' comparison.inLeftSize}} {{comparison.left.name}}
{{severityIcon severity}} {{name}}
{{tp 'quality_profiles.x_rules_only_in' comparison.inRightSize}} {{comparison.right.name}}
{{severityIcon severity}} {{name}}
-
{{tp 'quality_profiles.x_rules_have_different_configuration' comparison.modifiedSize}}
-
{{comparison.left.name}}
{{comparison.right.name}}
-

{{severityIcon left.severity}} {{name}}

- {{#notNull left.params}} -
    - {{#each left.params}} -
  • {{@key}}: {{this}}
  • - {{/each}} -
- {{/notNull}} -
-

{{severityIcon right.severity}} {{name}}

- {{#notNull right.params}} -
    - {{#each right.params}} -
  • {{@key}}: {{this}}
  • - {{/each}} -
- {{/notNull}} -
- -

- {{t 'hide'}} -

-{{/notNull}} diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/templates/quality-profiles-actions.hbs b/server/sonar-web/src/main/js/apps/quality-profiles/templates/quality-profiles-actions.hbs deleted file mode 100644 index 672a7a6ec17..00000000000 --- a/server/sonar-web/src/main/js/apps/quality-profiles/templates/quality-profiles-actions.hbs +++ /dev/null @@ -1,40 +0,0 @@ - - - diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/templates/quality-profiles-change-projects.hbs b/server/sonar-web/src/main/js/apps/quality-profiles/templates/quality-profiles-change-projects.hbs new file mode 100644 index 00000000000..09e591327e2 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/quality-profiles/templates/quality-profiles-change-projects.hbs @@ -0,0 +1,12 @@ + + + + + diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/templates/quality-profiles-create-profile.hbs b/server/sonar-web/src/main/js/apps/quality-profiles/templates/quality-profiles-create-profile.hbs index 50fbc195fff..845e4843ef6 100644 --- a/server/sonar-web/src/main/js/apps/quality-profiles/templates/quality-profiles-create-profile.hbs +++ b/server/sonar-web/src/main/js/apps/quality-profiles/templates/quality-profiles-create-profile.hbs @@ -6,9 +6,9 @@ + {{tp 'quality_profiles.restore_built_in_profiles_confirmation' language.name}}
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/utils.js b/server/sonar-web/src/main/js/apps/quality-profiles/utils.js new file mode 100644 index 00000000000..cba412ba81a --- /dev/null +++ b/server/sonar-web/src/main/js/apps/quality-profiles/utils.js @@ -0,0 +1,61 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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/sortBy'; + +export function sortProfiles (profiles) { + const result = []; + const sorted = sortBy(profiles, 'name'); + + function retrieveChildren (parent) { + return sorted.filter(p => ( + (parent == null && p.parentKey == null) || + (parent != null && p.parentKey === parent.key) + )); + } + + function putProfile (profile = null, depth = 0) { + const children = retrieveChildren(profile); + + if (profile != null) { + result.push({ ...profile, childrenCount: children.length, depth }); + } + + children.forEach(child => putProfile(child, depth + 1)); + } + + putProfile(); + + return result; +} + +export function createFakeProfile (overrides) { + return { + key: 'key', + name: 'name', + isDefault: false, + isInherited: false, + language: 'js', + languageName: 'JavaScript', + activeRuleCount: 10, + activeDeprecatedRuleCount: 2, + projectCount: 3, + ...overrides + }; +} diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/change-profile-parent-view.js b/server/sonar-web/src/main/js/apps/quality-profiles/views/ChangeParentView.js similarity index 52% rename from server/sonar-web/src/main/js/apps/quality-profiles/change-profile-parent-view.js rename to server/sonar-web/src/main/js/apps/quality-profiles/views/ChangeParentView.js index e86554b516e..6b405179e44 100644 --- a/server/sonar-web/src/main/js/apps/quality-profiles/change-profile-parent-view.js +++ b/server/sonar-web/src/main/js/apps/quality-profiles/views/ChangeParentView.js @@ -17,11 +17,9 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -import $ from 'jquery'; -import _ from 'underscore'; -import Marionette from 'backbone.marionette'; -import ModalFormView from '../../components/common/modal-form'; -import Template from './templates/quality-profiles-change-profile-parent.hbs'; +import ModalFormView from '../../../components/common/modal-form'; +import Template from '../templates/quality-profiles-change-profile-parent.hbs'; +import { changeProfileParent } from '../../../api/quality-profiles'; export default ModalFormView.extend({ template: Template, @@ -41,40 +39,25 @@ export default ModalFormView.extend({ }, sendRequest () { - const that = this; - const url = window.baseUrl + '/api/qualityprofiles/change_parent'; const parent = this.$('#change-profile-parent').val(); - const options = { - profileKey: this.model.get('key'), - parentKey: parent - }; - return $.ajax({ - url, - type: 'POST', - data: options, - statusCode: { - // do not show global error - 400: null - } - }).done(function () { - that.model.collection.fetch(); - that.model.trigger('select', that.model); - that.destroy(); - }).fail(function (jqXHR) { - that.showErrors(jqXHR.responseJSON.errors, jqXHR.responseJSON.warnings); - that.enableForm(); - }); + changeProfileParent(this.options.profile.key, parent) + .then(() => { + this.destroy(); + this.trigger('done'); + }) + .catch(e => { + if (e.response.status === 400) { + this.enableForm(); + e.response.json().then(r => this.showErrors(r.errors, r.warnings)); + } + }); }, serializeData () { - const that = this; - const profilesData = this.model.collection.toJSON(); - const profiles = _.filter(profilesData, function (profile) { - return profile.language === that.model.get('language') && profile.key !== that.model.id; - }); - return _.extend(Marionette.ItemView.prototype.serializeData.apply(this, arguments), { - profiles - }); + const { profile } = this.options; + const profiles = this.options.profiles + .filter(p => p !== profile && p.language === profile.language); + return { ...profile, profiles }; } }); diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/views/ChangeProjectsView.js b/server/sonar-web/src/main/js/apps/quality-profiles/views/ChangeProjectsView.js new file mode 100644 index 00000000000..5292bfa183e --- /dev/null +++ b/server/sonar-web/src/main/js/apps/quality-profiles/views/ChangeProjectsView.js @@ -0,0 +1,70 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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 ModalFormView from '../../../components/common/modal-form'; +import Template from '../templates/quality-profiles-change-projects.hbs'; +import { translate } from '../../../helpers/l10n'; +import '../../../components/SelectList'; + +export default ModalFormView.extend({ + template: Template, + + onRender () { + ModalFormView.prototype.onRender.apply(this, arguments); + + const { key } = this.options.profile; + + const searchUrl = window.baseUrl + '/api/qualityprofiles/projects?key=' + + encodeURIComponent(key); + + new window.SelectList({ + searchUrl, + el: this.$('#profile-projects'), + width: '100%', + readOnly: false, + focusSearch: false, + format (item) { + return item.name; + }, + selectUrl: window.baseUrl + '/api/qualityprofiles/add_project', + deselectUrl: window.baseUrl + '/api/qualityprofiles/remove_project', + extra: { + profileKey: key + }, + selectParameter: 'projectUuid', + selectParameterValue: 'uuid', + labels: { + selected: translate('quality_gates.projects.with'), + deselected: translate('quality_gates.projects.without'), + all: translate('quality_gates.projects.all'), + noResults: translate('quality_gates.projects.noResults') + }, + tooltips: { + select: translate('quality_profiles.projects.select_hint'), + deselect: translate('quality_profiles.projects.deselect_hint') + } + }); + }, + + onDestroy() { + this.options.loadProjects(); + ModalFormView.prototype.onDestroy.apply(this, arguments); + } +}); + diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/copy-profile-view.js b/server/sonar-web/src/main/js/apps/quality-profiles/views/CopyProfileView.js similarity index 56% rename from server/sonar-web/src/main/js/apps/quality-profiles/copy-profile-view.js rename to server/sonar-web/src/main/js/apps/quality-profiles/views/CopyProfileView.js index e391f8bc274..5809894287e 100644 --- a/server/sonar-web/src/main/js/apps/quality-profiles/copy-profile-view.js +++ b/server/sonar-web/src/main/js/apps/quality-profiles/views/CopyProfileView.js @@ -17,10 +17,9 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -import $ from 'jquery'; -import ModalFormView from '../../components/common/modal-form'; -import Profile from './profile'; -import Template from './templates/quality-profiles-copy-profile.hbs'; +import ModalFormView from '../../../components/common/modal-form'; +import Template from '../templates/quality-profiles-copy-profile.hbs'; +import { copyProfile } from '../../../api/quality-profiles'; export default ModalFormView.extend({ template: Template, @@ -32,34 +31,22 @@ export default ModalFormView.extend({ }, sendRequest () { - const that = this; - const url = window.baseUrl + '/api/qualityprofiles/copy'; const name = this.$('#copy-profile-name').val(); - const options = { - fromKey: this.model.get('key'), - toName: name - }; - return $.ajax({ - url, - type: 'POST', - data: options, - statusCode: { - // do not show global error - 400: null - } - }).done(function (r) { - that.addProfile(r); - that.destroy(); - }).fail(function (jqXHR) { - that.enableForm(); - that.showErrors(jqXHR.responseJSON.errors, jqXHR.responseJSON.warnings); - }); + copyProfile(this.options.profile.key, name) + .then(profile => { + this.destroy(); + this.trigger('done', profile); + }) + .catch(e => { + if (e.response.status === 400) { + this.enableForm(); + e.response.json().then(r => this.showErrors(r.errors, r.warnings)); + } + }); }, - addProfile (profileData) { - const profile = new Profile(profileData); - this.model.collection.add([profile]); - profile.trigger('select', profile); + serializeData () { + return this.options.profile; } }); diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/create-profile-view.js b/server/sonar-web/src/main/js/apps/quality-profiles/views/CreateProfileView.js similarity index 86% rename from server/sonar-web/src/main/js/apps/quality-profiles/create-profile-view.js rename to server/sonar-web/src/main/js/apps/quality-profiles/views/CreateProfileView.js index 68aa25279dd..60d800bc9fa 100644 --- a/server/sonar-web/src/main/js/apps/quality-profiles/create-profile-view.js +++ b/server/sonar-web/src/main/js/apps/quality-profiles/views/CreateProfileView.js @@ -19,10 +19,9 @@ */ import $ from 'jquery'; import _ from 'underscore'; -import ModalFormView from '../../components/common/modal-form'; -import Profile from './profile'; -import Template from './templates/quality-profiles-create-profile.hbs'; -import { createQualityProfile } from '../../api/quality-profiles'; +import ModalFormView from '../../../components/common/modal-form'; +import Template from '../templates/quality-profiles-create-profile.hbs'; +import { createQualityProfile } from '../../../api/quality-profiles'; export default ModalFormView.extend({ template: Template, @@ -41,7 +40,7 @@ export default ModalFormView.extend({ createQualityProfile(data) .then(r => { - this.addProfile(r.profile); + this.trigger('done', r.profile); this.destroy(); }) .catch(e => { @@ -76,12 +75,6 @@ export default ModalFormView.extend({ e.unwrap(); }, - addProfile (profileData) { - const profile = new Profile(profileData); - this.collection.add([profile]); - profile.trigger('select', profile); - }, - getImportersForLanguages (language) { if (language != null) { return this.options.importers.filter(function (importer) { diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/delete-profile-view.js b/server/sonar-web/src/main/js/apps/quality-profiles/views/DeleteProfileView.js similarity index 60% rename from server/sonar-web/src/main/js/apps/quality-profiles/delete-profile-view.js rename to server/sonar-web/src/main/js/apps/quality-profiles/views/DeleteProfileView.js index b75d930867b..b9bb6023c71 100644 --- a/server/sonar-web/src/main/js/apps/quality-profiles/delete-profile-view.js +++ b/server/sonar-web/src/main/js/apps/quality-profiles/views/DeleteProfileView.js @@ -17,9 +17,9 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -import $ from 'jquery'; -import ModalFormView from '../../components/common/modal-form'; -import Template from './templates/quality-profiles-delete-profile.hbs'; +import ModalFormView from '../../../components/common/modal-form'; +import Template from '../templates/quality-profiles-delete-profile.hbs'; +import { deleteProfile } from '../../../api/quality-profiles'; export default ModalFormView.extend({ template: Template, @@ -35,24 +35,21 @@ export default ModalFormView.extend({ }, sendRequest () { - const that = this; - const url = window.baseUrl + '/api/qualityprofiles/delete'; - const options = { profileKey: this.model.get('key') }; - return $.ajax({ - url, - type: 'POST', - data: options, - statusCode: { - // do not show global error - 400: null - } - }).done(function () { - that.model.collection.fetch(); - that.model.trigger('destroy', that.model, that.model.collection); - }).fail(function (jqXHR) { - that.showErrors(jqXHR.responseJSON.errors, jqXHR.responseJSON.warnings); - that.enableForm(); - }); + deleteProfile(this.options.profile.key) + .then(() => { + this.destroy(); + this.trigger('done'); + }) + .catch(e => { + if (e.response.status === 400) { + this.enableForm(); + e.response.json().then(r => this.showErrors(r.errors, r.warnings)); + } + }); + }, + + serializeData () { + return this.options.profile; } }); diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/rename-profile-view.js b/server/sonar-web/src/main/js/apps/quality-profiles/views/RenameProfileView.js similarity index 62% rename from server/sonar-web/src/main/js/apps/quality-profiles/rename-profile-view.js rename to server/sonar-web/src/main/js/apps/quality-profiles/views/RenameProfileView.js index 52c4e7eaf50..964a4b58115 100644 --- a/server/sonar-web/src/main/js/apps/quality-profiles/rename-profile-view.js +++ b/server/sonar-web/src/main/js/apps/quality-profiles/views/RenameProfileView.js @@ -17,9 +17,9 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -import $ from 'jquery'; -import ModalFormView from '../../components/common/modal-form'; -import Template from './templates/quality-profiles-rename-profile.hbs'; +import ModalFormView from '../../../components/common/modal-form'; +import Template from '../templates/quality-profiles-rename-profile.hbs'; +import { renameProfile } from '../../../api/quality-profiles'; export default ModalFormView.extend({ template: Template, @@ -30,27 +30,22 @@ export default ModalFormView.extend({ }, sendRequest () { - const that = this; - const url = window.baseUrl + '/api/qualityprofiles/rename'; const name = this.$('#rename-profile-name').val(); - const options = { - key: this.model.get('key'), - name - }; - return $.ajax({ - url, - type: 'POST', - data: options, - statusCode: { - // do not show global error - 400: null - } - }).done(function () { - that.model.set({ name }); - that.destroy(); - }).fail(function (jqXHR) { - that.showErrors(jqXHR.responseJSON.errors, jqXHR.responseJSON.warnings); - }); + renameProfile(this.options.profile.key, name) + .then(profile => { + this.destroy(); + this.trigger('done', profile); + }) + .catch(e => { + if (e.response.status === 400) { + this.enableForm(); + e.response.json().then(r => this.showErrors(r.errors, r.warnings)); + } + }); + }, + + serializeData () { + return this.options.profile; } }); diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/views/RestoreBuiltInProfilesView.js b/server/sonar-web/src/main/js/apps/quality-profiles/views/RestoreBuiltInProfilesView.js new file mode 100644 index 00000000000..f71f85c06af --- /dev/null +++ b/server/sonar-web/src/main/js/apps/quality-profiles/views/RestoreBuiltInProfilesView.js @@ -0,0 +1,56 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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 ModalFormView from '../../../components/common/modal-form'; +import Template from '../templates/quality-profiles-restore-built-in-profiles.hbs'; +import TemplateSuccess from '../templates/quality-profiles-restore-built-in-profiles-success.hbs'; +import { restoreBuiltInProfiles } from '../../../api/quality-profiles'; + +export default ModalFormView.extend({ + template: Template, + successTemplate: TemplateSuccess, + + getTemplate () { + return this.done ? this.successTemplate : this.template; + }, + + onFormSubmit () { + ModalFormView.prototype.onFormSubmit.apply(this, arguments); + this.disableForm(); + this.sendRequest(); + }, + + sendRequest () { + restoreBuiltInProfiles(this.options.language.key) + .then(() => { + this.done = true; + this.render(); + this.trigger('done'); + }) + .catch(e => { + this.enableForm(); + e.response.json().then(r => this.showErrors(r.errors, r.warnings)); + }); + }, + + serializeData () { + return { language: this.options.language }; + } +}); + diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/restore-profile-view.js b/server/sonar-web/src/main/js/apps/quality-profiles/views/RestoreProfileView.js similarity index 70% rename from server/sonar-web/src/main/js/apps/quality-profiles/restore-profile-view.js rename to server/sonar-web/src/main/js/apps/quality-profiles/views/RestoreProfileView.js index 3c5bad5adb7..4fceffda657 100644 --- a/server/sonar-web/src/main/js/apps/quality-profiles/restore-profile-view.js +++ b/server/sonar-web/src/main/js/apps/quality-profiles/views/RestoreProfileView.js @@ -17,10 +17,9 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -import ModalFormView from '../../components/common/modal-form'; -import Profile from './profile'; -import Template from './templates/quality-profiles-restore-profile.hbs'; -import { restoreQualityProfile } from '../../api/quality-profiles'; +import ModalFormView from '../../../components/common/modal-form'; +import Template from '../templates/quality-profiles-restore-profile.hbs'; +import { restoreQualityProfile } from '../../../api/quality-profiles'; export default ModalFormView.extend({ template: Template, @@ -37,7 +36,7 @@ export default ModalFormView.extend({ this.ruleSuccesses = r.ruleSuccesses; this.ruleFailures = r.ruleFailures; this.render(); - this.addProfile(r.profile); + this.trigger('done'); }) .catch(e => { this.enableForm(); @@ -45,20 +44,12 @@ export default ModalFormView.extend({ }); }, - addProfile (profileData) { - const profile = new Profile(profileData); - this.collection.add([profile], { merge: true }); - const addedProfile = this.collection.get(profile.id); - if (addedProfile != null) { - addedProfile.trigger('select', addedProfile); - } - }, - serializeData() { - return Object.assign({}, ModalFormView.prototype.serializeData.apply(this, arguments), { + return { + ...ModalFormView.prototype.serializeData.apply(this, arguments), profile: this.profile, ruleSuccesses: this.ruleSuccesses, ruleFailures: this.ruleFailures - }); + }; } }); diff --git a/server/sonar-web/src/main/js/components/controls/DateInput.js b/server/sonar-web/src/main/js/components/controls/DateInput.js new file mode 100644 index 00000000000..59581521bc4 --- /dev/null +++ b/server/sonar-web/src/main/js/components/controls/DateInput.js @@ -0,0 +1,86 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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 $ from 'jquery'; +import React from 'react'; +import pick from 'lodash/pick'; +import './styles.css'; + +export default class DateInput extends React.Component { + static propTypes = { + value: React.PropTypes.string, + format: React.PropTypes.string, + name: React.PropTypes.string, + placeholder: React.PropTypes.string, + onChange: React.PropTypes.func.isRequired + }; + + static defaultProps = { + value: '', + format: 'yy-mm-dd' + }; + + componentDidMount () { + this.attachDatePicker(); + } + + componentWillReceiveProps (nextProps) { + this.refs.input.value = nextProps.value; + } + + handleChange () { + const { value } = this.refs.input; + this.props.onChange(value); + } + + attachDatePicker () { + const opts = { + dateFormat: this.props.format, + changeMonth: true, + changeYear: true, + onSelect: this.handleChange.bind(this) + }; + + if ($.fn && $.fn.datepicker) { + $(this.refs.input).datepicker(opts); + } + } + + render () { + const inputProps = pick(this.props, ['placeholder', 'name']); + + return ( + + + + + + + + + ); + } +} diff --git a/server/sonar-web/src/main/js/components/controls/styles.css b/server/sonar-web/src/main/js/components/controls/styles.css new file mode 100644 index 00000000000..1ed5c1f4e52 --- /dev/null +++ b/server/sonar-web/src/main/js/components/controls/styles.css @@ -0,0 +1,26 @@ +.date-input-control { + position: relative; + display: inline-block; + cursor: pointer; +} + +.date-input-control-input { + width: 105px; + padding-left: 24px !important; + cursor: pointer; +} + +.date-input-control-icon { + position: absolute; + top: 5px; + left: 5px; +} + +.date-input-control-icon path { + fill: #cdcdcd; + transition: fill 0.3s ease; +} + +.date-input-control-input:focus + .date-input-control-icon path { + fill: #4b9fd5; +} diff --git a/server/sonar-web/src/main/js/components/mixins/tooltips-mixin.js b/server/sonar-web/src/main/js/components/mixins/tooltips-mixin.js index 4536c61dbb3..13f67901447 100644 --- a/server/sonar-web/src/main/js/components/mixins/tooltips-mixin.js +++ b/server/sonar-web/src/main/js/components/mixins/tooltips-mixin.js @@ -66,7 +66,7 @@ export const TooltipsContainer = React.createClass({ }, componentWillUpdate() { - this.hideTooltips(); + this.destroyTooltips(); }, componentDidUpdate () { diff --git a/server/sonar-web/src/main/js/components/shared/severity-helper.js b/server/sonar-web/src/main/js/components/shared/severity-helper.js index 6bbbbec9efa..818d8068e77 100644 --- a/server/sonar-web/src/main/js/components/shared/severity-helper.js +++ b/server/sonar-web/src/main/js/components/shared/severity-helper.js @@ -26,11 +26,12 @@ export default React.createClass({ if (!this.props.severity) { return null; } - return - - - - {translate('severity', this.props.severity)} - ; + return ( + + + {' '} + {translate('severity', this.props.severity)} + + ); } }); diff --git a/server/sonar-web/src/main/js/helpers/urls.js b/server/sonar-web/src/main/js/helpers/urls.js index cf1a0fe57a4..17c424ab9e7 100644 --- a/server/sonar-web/src/main/js/helpers/urls.js +++ b/server/sonar-web/src/main/js/helpers/urls.js @@ -101,3 +101,29 @@ export function getQualityProfileUrl (key) { export function getQualityGateUrl (key) { return window.baseUrl + '/quality_gates/show/' + encodeURIComponent(key); } + +/** + * Generate URL for the rules page + * @param {object} query + * @returns {string} + */ +export function getRulesUrl (query) { + if (query) { + const serializedQuery = Object.keys(query).map(criterion => ( + `${encodeURIComponent(criterion)}=${encodeURIComponent( + query[criterion])}` + )).join('|'); + return window.baseUrl + '/coding_rules#' + serializedQuery; + } + return window.baseUrl + '/coding_rules'; +} + +/** + * Generate URL for the rules page filtering only active deprecated rules + * @param {object} query + * @returns {string} + */ +export function getDeprecatedActiveRulesUrl (query = {}) { + const baseQuery = { activation: 'true', statuses: 'DEPRECATED' }; + return getRulesUrl({ ...query, ...baseQuery }); +} diff --git a/server/sonar-web/src/main/less/components/page.less b/server/sonar-web/src/main/less/components/page.less index 84f496dea95..e6a828a0542 100644 --- a/server/sonar-web/src/main/less/components/page.less +++ b/server/sonar-web/src/main/less/components/page.less @@ -42,6 +42,12 @@ body { padding-bottom: 20px; } +.page-limited-small { + .page-limited; + width: 1080px; + box-sizing: border-box; +} + .page-container { min-width: 1080px; } diff --git a/server/sonar-web/src/main/webapp/WEB-INF/app/controllers/profiles_controller.rb b/server/sonar-web/src/main/webapp/WEB-INF/app/controllers/profiles_controller.rb index aa8d7613397..9483155f10c 100644 --- a/server/sonar-web/src/main/webapp/WEB-INF/app/controllers/profiles_controller.rb +++ b/server/sonar-web/src/main/webapp/WEB-INF/app/controllers/profiles_controller.rb @@ -36,6 +36,10 @@ class ProfilesController < ApplicationController render :action => 'index' end + def create + render :action => 'index' + end + # GET /profiles/export?name=&language=&format= def export language = params[:language] diff --git a/server/sonar-web/tests/mocha.opts b/server/sonar-web/tests/mocha.opts index 083265fe8a5..d3dbd50844c 100644 --- a/server/sonar-web/tests/mocha.opts +++ b/server/sonar-web/tests/mocha.opts @@ -1,3 +1,3 @@ --recursive ---compilers js:babel-register,css:tests/null-compiler.js +--compilers js:babel-register,css:tests/null-compiler.js,hbs:tests/null-compiler.js --require tests/jsdom-setup.js diff --git a/server/sonar-web/tests/null-compiler.js b/server/sonar-web/tests/null-compiler.js index f0167414d7a..22595ed6337 100644 --- a/server/sonar-web/tests/null-compiler.js +++ b/server/sonar-web/tests/null-compiler.js @@ -22,3 +22,4 @@ function nothing () { } require.extensions['.css'] = nothing; +require.extensions['.hbs'] = nothing; diff --git a/sonar-core/src/main/resources/org/sonar/l10n/core.properties b/sonar-core/src/main/resources/org/sonar/l10n/core.properties index 2f7820ffcf4..c4854f06fe3 100644 --- a/sonar-core/src/main/resources/org/sonar/l10n/core.properties +++ b/sonar-core/src/main/resources/org/sonar/l10n/core.properties @@ -102,6 +102,7 @@ moreCriteria=+ More Criteria name=Name name_too_long_x=Name is too long (maximum is {0} characters) navigation=Navigation +never=Never none=None unassigned=Not assigned off=Off @@ -688,6 +689,10 @@ issue.set_type=Change Type issue.type.CODE_SMELL=Code Smell issue.type.BUG=Bug issue.type.VULNERABILITY=Vulnerability +issue.type.CODE_SMELL.plural=Code Smells +issue.type.BUG.plural=Bugs +issue.type.VULNERABILITY.plural=Vulnerabilities + issue.status.REOPENED=Reopened issue.status.REOPENED.description=Transitioned to and then back from some other status. @@ -1670,7 +1675,8 @@ cloud.top_risk=Top risk quality_profiles.quality_profiles=Quality Profiles quality_profiles.new_profile=New Profile quality_profiles.compare_profiles=Compare Profiles -quality_profiles.restore_profile=Restore Profile +quality_profiles.compare_with=Compare with +quality_profiles.restore_profile=Restore quality_profiles.restore_submit=Restore quality_profiles.restore_profile.success={1} rule(s) restored in profile "{0}" quality_profiles.restore_profile.warning={1} rule(s) restored, {2} rule(s) ignored in profile "{0}" @@ -1698,7 +1704,7 @@ quality_profiles.editing_profile=Editing profile quality_profiles.profile_inheritance=Inheritance quality_profiles.available_projects=Available projects quality_profiles.associated_projects=Associated projects -quality_profiles.no_projects_associated_to_profile_x=No projects are explicitly associated to the profile "{0}". +quality_profiles.no_projects_associated_to_profile=No projects are explicitly associated to the profile. quality_profiles.projects_warning=List of projects explicitly associated to this Quality profile : quality_profiles.including_x_overriding.suffix=, incl. {0} overriding quality_profiles.set_parent=Set parent @@ -1707,7 +1713,7 @@ quality_profiles.no_version=no version quality_profiles.last_version_x_with_date=last version {0} ({1}) quality_profiles.version_x_with_date=version {0} ({1}) quality_profiles.version_x=version {0} -quality_profiles.parameter_set_to_x=Parameter {0} set to {1} +quality_profiles.parameter_set_to=Parameter {0} set to {1} quality_profiles.only_in_profile_x=Only in {0} quality_profiles.with_different_configuration=With different configuration quality_profiles.with_same_configuration=With same configuration @@ -1727,8 +1733,8 @@ quality_profiles.copy_new_name=New name quality_profiles.copy_overwrite_x=You are about to copy this quality profile into the existing "{0}" profile, which will fully overwrite it. Please confirm the name if you want to overwrite, or choose another name. quality_profiles.copy_x_overwritten=Profile '{0}' has been overwritten. quality_profiles.rename_x_title=Rename Profile {0} - {1} -quality_profiles.restore_built_in_profiles=Restore Built-in Profiles -quality_profiles.restore_built_in_profiles_confirmation=Are you sure you want to restore "{0}" profile(s) for {1}? +quality_profiles.restore_built_in_profiles=Restore Built-in +quality_profiles.restore_built_in_profiles_confirmation=Are you sure you want to restore {0} built-in profiles? quality_profiles.restore_built_in_profiles_success_message={0} built-in profiles have been restored. quality_profiles.including=including quality_profiles.deprecated=deprecated @@ -1736,30 +1742,50 @@ quality_profiles.manage_rules_tooltip=Manage rules of this profile quality_profiles.manage_rules_tooltip_x_profile=Manage rules of profile '{0}' quality_profiles.see_rules_tooltip=See rules of this profile quality_profiles.see_rules_tooltip_x_profile=See rules of profile '{0}' -quality_profiles.severity_set_to_x=Severity set to {0} +quality_profiles.severity_set_to=Severity set to quality_profiles.changelog_from=Changelog from quality_profiles.changelog.empty=No changes have been done. quality_profiles.changelog.ACTIVATED=Activated quality_profiles.changelog.DEACTIVATED=Deactivated quality_profiles.changelog.UPDATED=Updated -quality_profiles.changelog.parameter_reset_to_default_value_x=Parameter {0} reset to default value +quality_profiles.changelog.parameter_reset_to_default_value=Parameter {0} reset to default value quality_profiles.deleted_profile=The profile {0} doesn't exist anymore quality_profiles.projects_for_default=Every project not specifically associated to a quality profile will be associated to this one by default. quality_profiles.projects_for_default.edit=You must not select specific projects for the default quality profile. quality_profiles.inherits=Inherits "{0}" +quality_profile.x_rules={0} rules quality_profile.x_active_rules={0} active rules +quality_profile.total_active_rules=Total Active Rules quality_profiles.x_overridden_rules={0} overridden rules quality_profiles.change_parent=Change Parent quality_profiles.all_profiles=All Profiles quality_profiles.x_profiles={0} Profiles +quality_profiles._quality_profiles=quality profiles quality_profiles.x_projects={0} projects quality_profiles.no_results=No profiles found. Try installing a language plugin. quality_profiles.projects.select_hint=Click to associate this project with the quality profile quality_profiles.projects.deselect_hint=Click to remove association between this project and the quality profile quality_profiles.no_profiles_for_comparison=There are no profiles for comparison +quality_profile.empty_comparison=The quality profiles are equal. quality_profiles.activate_more=Activate More quality_profiles.intro1=Quality Profiles are collections of rules to apply during an analysis. quality_profiles.intro2=For each language there is a default profile. All projects not explicitly assigned to some other profile will be analyzed with the default. +quality_profiles.list.profile=Profile +quality_profiles.list.inheritance=Inheritance +quality_profiles.list.projects=Projects +quality_profiles.list.rules=Rules +quality_profiles.list.updated=Updated +quality_profiles.list.used=Used +quality_profiles.x_activated_out_of_y={0} rules activated out of {1} available +quality_profiles.change_projects=Change Projects +quality_profiles.not_found=The requested quality profile was not found. +quality_profiles.latest_new_rules=Latest New Rules +quality_profiles.latest_new_rules.activated={0}, activated on {1} profiles +quality_profiles.latest_new_rules.not_activated={0}, not yet activated +quality_profiles.deprecated_rules=Deprecated Rules +quality_profiles.x_deprecated_rules_are_still_activated={0} deprecated rules are still activated on {1} quality profiles: +quality_profiles.stagnant_profiles=Stagnant Profiles +quality_profiles.not_updated_more_than_year=The following profiles haven't been updated for more than 1 year: -- 2.39.5