@@ -49,7 +49,6 @@ import it.qualityGate.QualityGateTest; | |||
import it.qualityGate.QualityGateUiTest; | |||
import it.settings.PropertySetsTest; | |||
import it.settings.SettingsTest; | |||
import it.settings.SubCategoriesTest; | |||
import it.sourceCode.EncodingTest; | |||
import it.sourceCode.HighlightingTest; | |||
import it.sourceCode.ProjectCodeTest; | |||
@@ -71,7 +70,6 @@ import static util.ItUtils.xooPlugin; | |||
BackgroundTasksTest.class, | |||
// settings | |||
PropertySetsTest.class, | |||
SubCategoriesTest.class, | |||
SettingsTest.class, | |||
// i18n | |||
I18nTest.class, |
@@ -70,9 +70,6 @@ public class DashboardTest { | |||
// SONAR-2073 | |||
"/componentDashboard/DashboardTest/global_dashboard/filter-widget-anonymous.html", | |||
// SONAR-3460 | |||
"/componentDashboard/DashboardTest/global_dashboard/global-admin-dashboards.html", | |||
// SONAR-3461 | |||
"/componentDashboard/DashboardTest/global_dashboard/default-dashboards.html", | |||
@@ -21,7 +21,6 @@ package it.measureHistory; | |||
import com.sonar.orchestrator.Orchestrator; | |||
import com.sonar.orchestrator.locator.FileLocation; | |||
import com.sonar.orchestrator.selenium.Selenese; | |||
import it.Category1Suite; | |||
import java.util.Date; | |||
import java.util.List; | |||
@@ -32,8 +31,8 @@ import org.junit.Test; | |||
import org.sonar.wsclient.services.Measure; | |||
import org.sonar.wsclient.services.Resource; | |||
import org.sonar.wsclient.services.ResourceQuery; | |||
import pageobjects.Navigation; | |||
import util.ItUtils; | |||
import util.selenium.SeleneseTest; | |||
import static org.apache.commons.lang.time.DateUtils.addDays; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
@@ -133,9 +132,8 @@ public class DifferentialPeriodsTest { | |||
assertThat(measures.get(0).getVariation1()).isEqualTo(17); | |||
// Check on ui that it's possible to define leak period on project | |||
new SeleneseTest(Selenese.builder().setHtmlTestsInClasspath("define-leak-period-on-project", | |||
"/measureHistory/DifferentialPeriodsTest/define-leak-period-on-project.html" | |||
).build()).runOn(orchestrator); | |||
Navigation.get(orchestrator).openHomepage().logIn().asAdmin().openSettings("sample") | |||
.assertSettingDisplayed("sonar.timemachine.period1"); | |||
} | |||
/** |
@@ -23,6 +23,7 @@ import com.sonar.orchestrator.Orchestrator; | |||
import com.sonar.orchestrator.build.SonarScanner; | |||
import com.sonar.orchestrator.selenium.Selenese; | |||
import it.Category1Suite; | |||
import java.io.UnsupportedEncodingException; | |||
import java.sql.SQLException; | |||
import java.util.Calendar; | |||
import java.util.GregorianCalendar; | |||
@@ -34,22 +35,27 @@ import org.junit.Test; | |||
import org.junit.rules.ExpectedException; | |||
import org.sonar.wsclient.SonarClient; | |||
import org.sonar.wsclient.base.HttpException; | |||
import org.sonar.wsclient.services.PropertyQuery; | |||
import org.sonar.wsclient.services.ResourceQuery; | |||
import org.sonar.wsclient.user.UserParameters; | |||
import pageobjects.Navigation; | |||
import pageobjects.settings.SettingsPage; | |||
import util.selenium.SeleneseTest; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static util.ItUtils.projectDir; | |||
public class ProjectAdministrationTest { | |||
private static final String DELETE_WS_ENDPOINT = "api/projects/bulk_delete"; | |||
@ClassRule | |||
public static Orchestrator orchestrator = Category1Suite.ORCHESTRATOR; | |||
@Rule | |||
public ExpectedException expectedException = ExpectedException.none(); | |||
@Rule | |||
public Navigation nav = Navigation.get(orchestrator); | |||
private static final String PROJECT_KEY = "sample"; | |||
private static final String FILE_KEY = "sample:src/main/xoo/sample/Sample.xoo"; | |||
@@ -116,7 +122,7 @@ public class ProjectAdministrationTest { | |||
new SeleneseTest( | |||
Selenese.builder().setHtmlTestsInClasspath("project-deletion", "/projectAdministration/ProjectAdministrationTest/project-deletion/project-deletion.html").build()) | |||
.runOn(orchestrator); | |||
.runOn(orchestrator); | |||
} finally { | |||
wsClient.userClient().deactivate(projectAdminUser); | |||
} | |||
@@ -156,40 +162,37 @@ public class ProjectAdministrationTest { | |||
assertThat(count("events where category='Version'")).as("Different number of events").isEqualTo(1); | |||
} | |||
/** | |||
* SONAR-3425 | |||
*/ | |||
@Test | |||
public void project_settings() { | |||
scanSampleWithDate("2012-01-01"); | |||
Selenese selenese = Selenese.builder().setHtmlTestsInClasspath("project-settings", | |||
// SONAR-3425 | |||
"/projectAdministration/ProjectAdministrationTest/project-settings/override-global-settings.html", | |||
"/projectAdministration/ProjectAdministrationTest/project-settings/only-on-project-settings.html").build(); | |||
new SeleneseTest(selenese).runOn(orchestrator); | |||
// GET /api/properties/sonar.exclusions?resource=sample | |||
assertThat(orchestrator.getServer().getAdminWsClient().find(PropertyQuery.createForResource("sonar.exclusions", "sample")).getValue()) | |||
.isEqualTo("my-exclusions"); | |||
// GET /api/properties?resource=sample | |||
// Note that this WS is used by SonarLint | |||
assertThat(orchestrator.getServer().getAdminWsClient().findAll(PropertyQuery.createForResource(null, "sample"))).isNotEmpty(); | |||
public void display_project_settings() throws UnsupportedEncodingException { | |||
scanSample(null, null); | |||
SettingsPage page = nav.logIn().asAdmin().openSettings("sample") | |||
.assertMenuContains("Analysis Scope") | |||
.assertMenuContains("Category 1") | |||
.assertMenuContains("DEV") | |||
.assertMenuContains("project-only") | |||
.assertMenuContains("Xoo") | |||
.assertSettingDisplayed("sonar.dbcleaner.daysBeforeDeletingClosedIssues"); | |||
page.openCategory("project-only") | |||
.assertSettingDisplayed("prop_only_on_project"); | |||
page.openCategory("General") | |||
.assertStringSettingValue("sonar.dbcleaner.daysBeforeDeletingClosedIssues", "30") | |||
.assertStringSettingValue("sonar.timemachine.period1", "previous_version") | |||
.assertBooleanSettingValue("sonar.dbcleaner.cleanDirectory", true) | |||
.setStringValue("sonar.dbcleaner.daysBeforeDeletingClosedIssues", "1") | |||
.assertStringSettingValue("sonar.dbcleaner.daysBeforeDeletingClosedIssues", "1"); | |||
} | |||
/** | |||
* SONAR-4060 | |||
*/ | |||
@Test | |||
public void display_module_settings() { | |||
public void display_module_settings() throws UnsupportedEncodingException { | |||
orchestrator.executeBuild(SonarScanner.create(projectDir("shared/xoo-multi-modules-sample"))); | |||
Selenese selenese = Selenese.builder().setHtmlTestsInClasspath("module-settings", | |||
// SONAR-3425 | |||
"/projectAdministration/ProjectAdministrationTest/module-settings/display-module-settings.html").build(); | |||
new SeleneseTest(selenese).runOn(orchestrator); | |||
nav.logIn().asAdmin() | |||
.openSettings("com.sonarsource.it.samples:multi-modules-sample:module_a") | |||
.assertMenuContains("Analysis Scope") | |||
.assertSettingDisplayed("sonar.coverage.exclusions"); | |||
} | |||
private void scanSampleWithDate(String date) { |
@@ -20,20 +20,22 @@ | |||
package it.settings; | |||
import com.sonar.orchestrator.Orchestrator; | |||
import com.sonar.orchestrator.selenium.Selenese; | |||
import it.Category1Suite; | |||
import java.io.UnsupportedEncodingException; | |||
import java.util.List; | |||
import java.util.Map; | |||
import org.junit.After; | |||
import org.junit.BeforeClass; | |||
import org.junit.ClassRule; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.sonarqube.ws.Settings; | |||
import org.sonarqube.ws.client.setting.ResetRequest; | |||
import org.sonarqube.ws.client.setting.SetRequest; | |||
import org.sonarqube.ws.client.setting.SettingsService; | |||
import org.sonarqube.ws.client.setting.ValuesRequest; | |||
import util.selenium.SeleneseTest; | |||
import pageobjects.Navigation; | |||
import pageobjects.settings.SettingsPage; | |||
import static com.google.common.collect.Lists.newArrayList; | |||
import static java.util.Arrays.asList; | |||
@@ -47,6 +49,9 @@ public class PropertySetsTest { | |||
@ClassRule | |||
public static Orchestrator orchestrator = Category1Suite.ORCHESTRATOR; | |||
@Rule | |||
public Navigation nav = Navigation.get(orchestrator); | |||
static SettingsService SETTINGS; | |||
@BeforeClass | |||
@@ -60,37 +65,37 @@ public class PropertySetsTest { | |||
} | |||
@Test | |||
public void support_property_sets() { | |||
Selenese selenese = Selenese.builder().setHtmlTestsInClasspath("property-sets", | |||
"/settings/PropertySetsTest/property-sets/create.html", | |||
"/settings/PropertySetsTest/property-sets/delete.html", | |||
"/settings/PropertySetsTest/property-sets/reference.html", | |||
"/settings/PropertySetsTest/property-sets/all_types.html").build(); | |||
// Use the old runner because it fails with the new Selenium runner | |||
orchestrator.executeSelenese(selenese); | |||
// SSF-25 Check that the password has well be setted as now it does not appears in the html source code | |||
assertPropertySet("sonar.demo", | |||
asList(entry("password", "abcde"), | |||
entry("boolean", "true"), | |||
entry("float", "42.0"), | |||
entry("license", "abc"), | |||
entry("list", "AAA"), | |||
entry("metric", "overall_branch_coverage"), | |||
entry("regexp", ".*"), | |||
entry("text", "text"))); | |||
public void support_property_sets() throws UnsupportedEncodingException { | |||
SettingsPage page = nav.logIn().asAdmin().openSettings(null).openCategory("DEV") | |||
.assertSettingDisplayed("sonar.test.jira.servers"); | |||
page.getPropertySetInput("sonar.test.jira.servers") | |||
.setFieldValue("key", "jira1") | |||
.setFieldValue("url", "http://jira") | |||
.setFieldValue("port", "12345") | |||
.save(); | |||
assertPropertySet("sonar.test.jira.servers", asList( | |||
entry("key", "jira1"), | |||
entry("url", "http://jira"), | |||
entry("port", "12345"))); | |||
} | |||
@Test | |||
public void support_property_sets_with_auto_generated_keys() { | |||
new SeleneseTest( | |||
Selenese.builder().setHtmlTestsInClasspath("create-auto-generated", | |||
"/settings/PropertySetsTest/auto-generated/create.html").build()).runOn(orchestrator); | |||
assertPropertySet("sonar.autogenerated", asList(entry("value", "FIRST")), asList(entry("value", "SECOND")), asList(entry("value", "THIRD"))); | |||
new SeleneseTest(Selenese.builder().setHtmlTestsInClasspath("update-auto-generated", | |||
"/settings/PropertySetsTest/auto-generated/update.html").build()).runOn(orchestrator); | |||
assertPropertySet("sonar.autogenerated", asList(entry("value", "FIRST")), asList(entry("value", "THIRD"))); | |||
public void support_property_sets_with_auto_generated_keys() throws UnsupportedEncodingException { | |||
SettingsPage page = nav.logIn().asAdmin().openSettings(null).openCategory("DEV") | |||
.assertSettingDisplayed("sonar.autogenerated"); | |||
page.getPropertySetInput("sonar.autogenerated") | |||
.setFieldValue(0, "value", "FIRST") | |||
.setFieldValue(1, "value", "SECOND") | |||
.setFieldValue(2, "value", "THIRD") | |||
.save(); | |||
assertPropertySet("sonar.autogenerated", | |||
asList(entry("value", "FIRST")), | |||
asList(entry("value", "SECOND")), | |||
asList(entry("value", "THIRD"))); | |||
} | |||
@Test | |||
@@ -124,7 +129,7 @@ public class PropertySetsTest { | |||
assertThat(setting.getFieldValues().getFieldValuesList()).hasSize(fieldsValues.length); | |||
int index = 0; | |||
for (Settings.FieldValues.Value fieldsValue : setting.getFieldValues().getFieldValuesList()) { | |||
assertThat(fieldsValue.getValue()).containsOnly(fieldsValues[index].toArray(new Map.Entry[] {})); | |||
assertThat(fieldsValue.getValue()).containsOnly(fieldsValues[index].toArray(new Map.Entry[]{})); | |||
index++; | |||
} | |||
} |
@@ -22,11 +22,13 @@ package it.settings; | |||
import com.sonar.orchestrator.Orchestrator; | |||
import com.sonar.orchestrator.build.SonarScanner; | |||
import com.sonar.orchestrator.selenium.Selenese; | |||
import java.io.UnsupportedEncodingException; | |||
import java.net.URL; | |||
import org.junit.After; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.junit.rules.ExpectedException; | |||
import pageobjects.Navigation; | |||
import util.selenium.SeleneseTest; | |||
import static util.ItUtils.pluginArtifact; | |||
@@ -51,7 +53,7 @@ public class SettingsTestRestartingOrchestrator { | |||
} | |||
@Test | |||
public void test_settings() { | |||
public void test_settings() throws UnsupportedEncodingException { | |||
URL secretKeyUrl = getClass().getResource("/settings/SettingsTest/sonar-secret.txt"); | |||
orchestrator = Orchestrator.builderEnv() | |||
.addPlugin(pluginArtifact("settings-plugin")) | |||
@@ -60,33 +62,28 @@ public class SettingsTestRestartingOrchestrator { | |||
.build(); | |||
orchestrator.start(); | |||
Selenese selenese = Selenese.builder().setHtmlTestsInClasspath("test_settings", | |||
"/settings/SettingsTest/general-settings.html", | |||
// SONAR-2869 the annotation @Properties can be used on extensions and not only on plugin entry points | |||
"/settings/SettingsTest/hidden-extension-property.html", | |||
"/settings/SettingsTest/global-extension-property.html", | |||
Navigation.get(orchestrator).openHomepage().logIn().asAdmin().openSettings(null) | |||
.assertMenuContains("General") | |||
.assertSettingDisplayed("sonar.dbcleaner.cleanDirectory") | |||
.assertSettingNotDisplayed("settings.extension.hidden") | |||
.assertSettingNotDisplayed("settings.extension.global"); | |||
// SONAR-3344 - licenses | |||
"/settings/SettingsTest/ignore-corrupted-license.html", | |||
"/settings/SettingsTest/display-license.html", | |||
"/settings/SettingsTest/display-untyped-license.html", | |||
// SONAR-2084 - encryption | |||
Selenese selenese = Selenese.builder().setHtmlTestsInClasspath("test_settings", | |||
// test encryption | |||
"/settings/SettingsTest/generate-secret-key.html", | |||
"/settings/SettingsTest/encrypt-text.html", | |||
// SONAR-1378 - property types | |||
"/settings/SettingsTest/validate-property-type.html", | |||
// SONAR-3127 - hide passwords | |||
"/settings/SettingsTest/hide-passwords.html" | |||
).build(); | |||
"/settings/SettingsTest/encrypt-text.html" | |||
// test licenses | |||
// TODO enable when license page will be rewritten | |||
// "/settings/SettingsTest/ignore-corrupted-license.html", | |||
// "/settings/SettingsTest/display-license.html", | |||
// "/settings/SettingsTest/display-untyped-license.html" | |||
).build(); | |||
new SeleneseTest(selenese).runOn(orchestrator); | |||
} | |||
@Test | |||
public void property_relocation() { | |||
public void property_relocation() throws UnsupportedEncodingException { | |||
orchestrator = Orchestrator.builderEnv() | |||
.addPlugin(pluginArtifact("property-relocation-plugin")) | |||
.addPlugin(xooPlugin()) | |||
@@ -101,10 +98,10 @@ public class SettingsTestRestartingOrchestrator { | |||
// should not fail | |||
orchestrator.executeBuilds(withDeprecatedKey, withNewKey); | |||
Selenese selenese = Selenese.builder().setHtmlTestsInClasspath("property_relocation", | |||
"/settings/SettingsTest/property_relocation.html" | |||
).build(); | |||
new SeleneseTest(selenese).runOn(orchestrator); | |||
Navigation.get(orchestrator).openHomepage().logIn().asAdmin().openSettings(null) | |||
.assertMenuContains("General") | |||
.assertSettingDisplayed("sonar.newKey") | |||
.assertSettingNotDisplayed("sonar.deprecatedKey"); | |||
} | |||
} |
@@ -1,72 +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. | |||
*/ | |||
package it.settings; | |||
import com.sonar.orchestrator.Orchestrator; | |||
import com.sonar.orchestrator.build.SonarScanner; | |||
import com.sonar.orchestrator.selenium.Selenese; | |||
import it.Category1Suite; | |||
import org.junit.ClassRule; | |||
import org.junit.Test; | |||
import org.sonar.wsclient.services.PropertyQuery; | |||
import util.selenium.SeleneseTest; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static util.ItUtils.projectDir; | |||
public class SubCategoriesTest { | |||
@ClassRule | |||
public static Orchestrator orchestrator = Category1Suite.ORCHESTRATOR; | |||
/** | |||
* SONAR-3159 | |||
*/ | |||
@Test | |||
public void should_support_global_subcategories() { | |||
Selenese selenese = Selenese.builder().setHtmlTestsInClasspath("subcategories", | |||
"/settings/subcategories/global-subcategories.html", | |||
// SONAR-4495 | |||
"/settings/subcategories/global-subcategories-no-default.html" | |||
).build(); | |||
new SeleneseTest(selenese).runOn(orchestrator); | |||
assertThat(getProperty("prop3", null)).isEqualTo("myValue"); | |||
} | |||
/** | |||
* SONAR-3159 | |||
*/ | |||
@Test | |||
public void should_support_project_subcategories() { | |||
orchestrator.executeBuild(SonarScanner.create(projectDir("shared/xoo-sample"))); | |||
Selenese selenese = Selenese.builder().setHtmlTestsInClasspath("subcategories", | |||
"/settings/subcategories/project-subcategories.html", | |||
// SONAR-4495 | |||
"/settings/subcategories/project-subcategories-no-default.html" | |||
).build(); | |||
new SeleneseTest(selenese).runOn(orchestrator); | |||
assertThat(getProperty("prop3", "sample")).isEqualTo("myValue2"); | |||
} | |||
static String getProperty(String key, String resourceKeyOrId) { | |||
return orchestrator.getServer().getAdminWsClient().find(new PropertyQuery().setKey(key).setResourceKeyOrId(resourceKeyOrId)).getValue(); | |||
} | |||
} |
@@ -36,6 +36,10 @@ public class LoginPage { | |||
return submitCredentials(login, password, Navigation.class); | |||
} | |||
public Navigation asAdmin() { | |||
return submitCredentials("admin", "admin"); | |||
} | |||
public LoginPage submitWrongCredentials(String login, String password) { | |||
$("#login").val(login); | |||
$("#password").val(password); |
@@ -24,8 +24,12 @@ import com.codeborne.selenide.Selenide; | |||
import com.codeborne.selenide.SelenideElement; | |||
import com.codeborne.selenide.WebDriverRunner; | |||
import com.sonar.orchestrator.Orchestrator; | |||
import java.io.UnsupportedEncodingException; | |||
import java.net.URLEncoder; | |||
import javax.annotation.Nullable; | |||
import org.junit.rules.ExternalResource; | |||
import org.openqa.selenium.By; | |||
import pageobjects.settings.SettingsPage; | |||
import static com.codeborne.selenide.Selenide.$; | |||
import static com.codeborne.selenide.Selenide.page; | |||
@@ -84,6 +88,13 @@ public class Navigation extends ExternalResource { | |||
return open("/background_tasks", BackgroundTasksPage.class); | |||
} | |||
public SettingsPage openSettings(@Nullable String projectKey) throws UnsupportedEncodingException { | |||
String url = projectKey != null ? | |||
"/project/settings?id=" + URLEncoder.encode(projectKey, "UTF-8") : | |||
"/settings"; | |||
return open(url, SettingsPage.class); | |||
} | |||
public void open(String relativeUrl) { | |||
Selenide.open(relativeUrl); | |||
} |
@@ -0,0 +1,48 @@ | |||
/* | |||
* 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 pageobjects.settings; | |||
import com.codeborne.selenide.SelenideElement; | |||
import static com.codeborne.selenide.Condition.exist; | |||
public class PropertySetInput { | |||
private final SelenideElement elt; | |||
public PropertySetInput(SelenideElement elt) { | |||
this.elt = elt; | |||
} | |||
public PropertySetInput setFieldValue(int index, String fieldKey, String value) { | |||
elt.findAll("input[name$=\"[" + fieldKey + "]\"]").get(index).val(value); | |||
return this; | |||
} | |||
public PropertySetInput setFieldValue(String fieldKey, String value) { | |||
return setFieldValue(0, fieldKey, value); | |||
} | |||
public PropertySetInput save() { | |||
elt.find(".js-save-changes").click(); | |||
elt.find(".js-save-changes").shouldNot(exist); | |||
return this; | |||
} | |||
} |
@@ -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. | |||
*/ | |||
package pageobjects.settings; | |||
import com.codeborne.selenide.SelenideElement; | |||
import org.openqa.selenium.By; | |||
import static com.codeborne.selenide.Condition.cssClass; | |||
import static com.codeborne.selenide.Condition.exactValue; | |||
import static com.codeborne.selenide.Condition.exist; | |||
import static com.codeborne.selenide.Condition.visible; | |||
import static com.codeborne.selenide.Selenide.$; | |||
public class SettingsPage { | |||
public SettingsPage() { | |||
$("#settings-page").shouldBe(visible); | |||
} | |||
public SettingsPage assertMenuContains(String categoryName) { | |||
$(".settings-menu").$(By.linkText(categoryName)).shouldBe(visible); | |||
return this; | |||
} | |||
public SettingsPage assertSettingDisplayed(String settingKey) { | |||
$(".settings-definition[data-key='" + settingKey + "']").shouldBe(visible); | |||
return this; | |||
} | |||
public SettingsPage assertSettingNotDisplayed(String settingKey) { | |||
$(".settings-definition[data-key='" + settingKey + "']").shouldNotBe(visible); | |||
return this; | |||
} | |||
public SettingsPage openCategory(String categoryName) { | |||
$(".settings-menu").$(By.linkText(categoryName)).click(); | |||
return this; | |||
} | |||
public SettingsPage assertStringSettingValue(String settingKey, String value) { | |||
$("input[name=\"settings[" + settingKey + "]\"]").shouldHave(exactValue(value)); | |||
return this; | |||
} | |||
public SettingsPage assertBooleanSettingValue(String settingKey, boolean value) { | |||
SelenideElement toggle = $("button[name=\"settings[" + settingKey + "]\"]"); | |||
if (value) { | |||
toggle.shouldHave(cssClass("boolean-toggle-on")); | |||
} else { | |||
toggle.shouldNotHave(cssClass("boolean-toggle-on")); | |||
} | |||
return this; | |||
} | |||
public SettingsPage setStringValue(String settingKey, String value) { | |||
SelenideElement setting = $(".settings-definition[data-key=\"" + settingKey + "\"]"); | |||
setting.find("input").val(value); | |||
setting.find(".js-save-changes").click(); | |||
setting.find(".js-save-changes").shouldNot(exist); | |||
return this; | |||
} | |||
public PropertySetInput getPropertySetInput(String settingKey) { | |||
SelenideElement setting = $(".settings-definition[data-key=\"" + settingKey + "\"]"); | |||
return new PropertySetInput(setting); | |||
} | |||
} |
@@ -1,89 +0,0 @@ | |||
<?xml version="1.0" encoding="UTF-8"?> | |||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> | |||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> | |||
<head profile="http://selenium-ide.openqa.org/profiles/test-case"> | |||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> | |||
<title>global-admin-dashboards</title> | |||
</head> | |||
<body> | |||
<table cellpadding="1" cellspacing="1" border="1"> | |||
<thead> | |||
<tr> | |||
<td rowspan="1" colspan="3">global-admin-dashboards</td> | |||
</tr> | |||
</thead> | |||
<tbody> | |||
<tr> | |||
<td>open</td> | |||
<td>/sessions/login</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>type</td> | |||
<td>login</td> | |||
<td>admin</td> | |||
</tr> | |||
<tr> | |||
<td>type</td> | |||
<td>password</td> | |||
<td>admin</td> | |||
</tr> | |||
<tr> | |||
<td>clickAndWait</td> | |||
<td>commit</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>open</td> | |||
<td>/</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>waitForElementPresent</td> | |||
<td>link=Home</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>clickAndWait</td> | |||
<td>link=Home</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>clickAndWait</td> | |||
<td>link=Configure widgets</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>clickAndWait</td> | |||
<td>link=Back to dashboard</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>open</td> | |||
<td>/dashboards</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>open</td> | |||
<td>/settings/index</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>waitForElementPresent</td> | |||
<td>link=Configuration</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>click</td> | |||
<td>link=Configuration</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>clickAndWait</td> | |||
<td>link=Default Dashboards</td> | |||
<td></td> | |||
</tr> | |||
</tbody> | |||
</table> | |||
</body> | |||
</html> |
@@ -1,49 +0,0 @@ | |||
<?xml version="1.0" encoding="UTF-8"?> | |||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> | |||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> | |||
<head profile="http://selenium-ide.openqa.org/profiles/test-case"> | |||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> | |||
<title>display-added-files</title> | |||
</head> | |||
<body> | |||
<table cellpadding="1" cellspacing="1" border="1"> | |||
<thead> | |||
<tr> | |||
<td rowspan="1" colspan="3">should_display_added_files_in_differential_drilldown</td> | |||
</tr> | |||
</thead> | |||
<tbody> | |||
<tr> | |||
<td>open</td> | |||
<td>/sessions/logout</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>open</td> | |||
<td>/project/settings?id=sample&category=general&subcategory=differentialviews</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>type</td> | |||
<td>id=login</td> | |||
<td>admin</td> | |||
</tr> | |||
<tr> | |||
<td>type</td> | |||
<td>id=password</td> | |||
<td>admin</td> | |||
</tr> | |||
<tr> | |||
<td>clickAndWait</td> | |||
<td>name=commit</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>waitForText</td> | |||
<td>properties</td> | |||
<td>*Leak Period*</td> | |||
</tr> | |||
</tbody> | |||
</table> | |||
</body> | |||
</html> |
@@ -1,49 +0,0 @@ | |||
<?xml version="1.0" encoding="UTF-8"?> | |||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> | |||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> | |||
<head profile="http://selenium-ide.openqa.org/profiles/test-case"> | |||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> | |||
<title>override-global-settings</title> | |||
</head> | |||
<body> | |||
<table cellpadding="1" cellspacing="1" border="1"> | |||
<thead> | |||
<tr> | |||
<td rowspan="1" colspan="3">override-global-settings</td> | |||
</tr> | |||
</thead> | |||
<tbody> | |||
<tr> | |||
<td>open</td> | |||
<td>/sessions/logout</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>open</td> | |||
<td>/project/settings/com.sonarsource.it.samples%3Amulti-modules-sample%3Amodule_a</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>type</td> | |||
<td>id=login</td> | |||
<td>admin</td> | |||
</tr> | |||
<tr> | |||
<td>type</td> | |||
<td>id=password</td> | |||
<td>admin</td> | |||
</tr> | |||
<tr> | |||
<td>clickAndWait</td> | |||
<td>name=commit</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>waitForText</td> | |||
<td>plugins</td> | |||
<td>*Settings*</td> | |||
</tr> | |||
</tbody> | |||
</table> | |||
</body> | |||
</html> |
@@ -1,64 +0,0 @@ | |||
<?xml version="1.0" encoding="UTF-8"?> | |||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> | |||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> | |||
<head profile="http://selenium-ide.openqa.org/profiles/test-case"> | |||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> | |||
<title>override-global-settings</title> | |||
</head> | |||
<body> | |||
<table cellpadding="1" cellspacing="1" border="1"> | |||
<thead> | |||
<tr> | |||
<td rowspan="1" colspan="3">override-global-settings</td> | |||
</tr> | |||
</thead> | |||
<tbody> | |||
<tr> | |||
<td>open</td> | |||
<td>/sessions/logout</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>open</td> | |||
<td>/project/settings/sample?category=project-only</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>type</td> | |||
<td>id=login</td> | |||
<td>admin</td> | |||
</tr> | |||
<tr> | |||
<td>type</td> | |||
<td>id=password</td> | |||
<td>admin</td> | |||
</tr> | |||
<tr> | |||
<td>clickAndWait</td> | |||
<td>name=commit</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>waitForElementPresent</td> | |||
<td>css=.js-user-authenticated</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>type</td> | |||
<td>id=input_prop_only_on_project</td> | |||
<td>foo</td> | |||
</tr> | |||
<tr> | |||
<td>click</td> | |||
<td>id=submit_settings</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>waitForValue</td> | |||
<td>id=input_prop_only_on_project</td> | |||
<td>foo</td> | |||
</tr> | |||
</tbody> | |||
</table> | |||
</body> | |||
</html> |
@@ -1,64 +0,0 @@ | |||
<?xml version="1.0" encoding="UTF-8"?> | |||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> | |||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> | |||
<head profile="http://selenium-ide.openqa.org/profiles/test-case"> | |||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> | |||
<title>override-global-settings</title> | |||
</head> | |||
<body> | |||
<table cellpadding="1" cellspacing="1" border="1"> | |||
<thead> | |||
<tr> | |||
<td rowspan="1" colspan="3">override-global-settings</td> | |||
</tr> | |||
</thead> | |||
<tbody> | |||
<tr> | |||
<td>open</td> | |||
<td>/sessions/logout</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>open</td> | |||
<td>/project/settings/sample?category=exclusions&subcategory=files</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>type</td> | |||
<td>id=login</td> | |||
<td>admin</td> | |||
</tr> | |||
<tr> | |||
<td>type</td> | |||
<td>id=password</td> | |||
<td>admin</td> | |||
</tr> | |||
<tr> | |||
<td>clickAndWait</td> | |||
<td>name=commit</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>waitForElementPresent</td> | |||
<td>css=.js-user-authenticated</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>type</td> | |||
<td>id=input_sonar.exclusions</td> | |||
<td>my-exclusions</td> | |||
</tr> | |||
<tr> | |||
<td>click</td> | |||
<td>id=submit_settings</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>waitForValue</td> | |||
<td>id=input_sonar.exclusions</td> | |||
<td>my-exclusions</td> | |||
</tr> | |||
</tbody> | |||
</table> | |||
</body> | |||
</html> |
@@ -60,22 +60,7 @@ | |||
</tr> | |||
<tr> | |||
<td>open</td> | |||
<td>/settings/index</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>clickAndWait</td> | |||
<td>link=Licenses</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>clickAndWait</td> | |||
<td>link=Server ID</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>selectFrame</td> | |||
<td>settings_iframe</td> | |||
<td>/server_id_configuration</td> | |||
<td></td> | |||
</tr> | |||
<tr> |
@@ -35,22 +35,7 @@ | |||
</tr> | |||
<tr> | |||
<td>open</td> | |||
<td>/settings/index</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>clickAndWait</td> | |||
<td>link=Licenses</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>clickAndWait</td> | |||
<td>link=Server ID</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>selectFrame</td> | |||
<td>settings_iframe</td> | |||
<td>/server_id_configuration</td> | |||
<td></td> | |||
</tr> | |||
<tr> |
@@ -40,27 +40,7 @@ | |||
</tr> | |||
<tr> | |||
<td>open</td> | |||
<td>/settings/index</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>clickAndWait</td> | |||
<td>link=Licenses</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>clickAndWait</td> | |||
<td>link=Server ID</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>waitForElementPresent</td> | |||
<td>settings_iframe</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>selectFrame</td> | |||
<td>settings_iframe</td> | |||
<td>/server_id_configuration</td> | |||
<td></td> | |||
</tr> | |||
<tr> |
@@ -1,84 +0,0 @@ | |||
<?xml version="1.0" encoding="UTF-8"?> | |||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> | |||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> | |||
<head profile="http://selenium-ide.openqa.org/profiles/test-case"> | |||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> | |||
<title>create</title> | |||
</head> | |||
<body> | |||
<table cellpadding="1" cellspacing="1" border="1"> | |||
<tbody> | |||
<tr> | |||
<td>open</td> | |||
<td>/sessions/new</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>type</td> | |||
<td>login</td> | |||
<td>admin</td> | |||
</tr> | |||
<tr> | |||
<td>type</td> | |||
<td>password</td> | |||
<td>admin</td> | |||
</tr> | |||
<tr> | |||
<td>clickAndWait</td> | |||
<td>commit</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>waitForElementPresent</td> | |||
<td>css=.js-user-authenticated</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>open</td> | |||
<td>/settings?category=DEV</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>waitForValue</td> | |||
<td>name=page_version</td> | |||
<td>1</td> | |||
</tr> | |||
<tr> | |||
<td>type</td> | |||
<td>id=input_value</td> | |||
<td>FIRST</td> | |||
</tr> | |||
<tr> | |||
<td>click</td> | |||
<td>css=button.add_value</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>type</td> | |||
<td>xpath=(//input[@id='input_value'])[2]</td> | |||
<td>SECOND</td> | |||
</tr> | |||
<tr> | |||
<td>click</td> | |||
<td>css=button.add_value</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>type</td> | |||
<td>xpath=(//input[@id='input_value'])[3]</td> | |||
<td>THIRD</td> | |||
</tr> | |||
<tr> | |||
<td>click</td> | |||
<td>id=submit_settings</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>waitForValue</td> | |||
<td>name=page_version</td> | |||
<td>2</td> | |||
</tr> | |||
</tbody> | |||
</table> | |||
</body> | |||
</html> |
@@ -1,69 +0,0 @@ | |||
<?xml version="1.0" encoding="UTF-8"?> | |||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> | |||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> | |||
<head profile="http://selenium-ide.openqa.org/profiles/test-case"> | |||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> | |||
<title>update</title> | |||
</head> | |||
<body> | |||
<table cellpadding="1" cellspacing="1" border="1"> | |||
<tbody> | |||
<tr> | |||
<td>open</td> | |||
<td>/sessions/new</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>type</td> | |||
<td>login</td> | |||
<td>admin</td> | |||
</tr> | |||
<tr> | |||
<td>type</td> | |||
<td>password</td> | |||
<td>admin</td> | |||
</tr> | |||
<tr> | |||
<td>clickAndWait</td> | |||
<td>commit</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>waitForElementPresent</td> | |||
<td>css=.js-user-authenticated</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>open</td> | |||
<td>/settings?category=DEV</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>waitForValue</td> | |||
<td>name=page_version</td> | |||
<td>1</td> | |||
</tr> | |||
<tr> | |||
<td>click</td> | |||
<td>link=Delete</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>waitForVisible</td> | |||
<td>id=submit_settings</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>click</td> | |||
<td>id=submit_settings</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>waitForValue</td> | |||
<td>name=page_version</td> | |||
<td>2</td> | |||
</tr> | |||
</tbody> | |||
</table> | |||
</body> | |||
</html> |
@@ -1,139 +0,0 @@ | |||
<?xml version="1.0" encoding="UTF-8"?> | |||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> | |||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> | |||
<head profile="http://selenium-ide.openqa.org/profiles/test-case"> | |||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> | |||
<title>all_types</title> | |||
</head> | |||
<body> | |||
<table cellpadding="1" cellspacing="1" border="1"> | |||
<tbody> | |||
<tr> | |||
<td>open</td> | |||
<td>/sessions/new</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>type</td> | |||
<td>login</td> | |||
<td>admin</td> | |||
</tr> | |||
<tr> | |||
<td>type</td> | |||
<td>password</td> | |||
<td>admin</td> | |||
</tr> | |||
<tr> | |||
<td>clickAndWait</td> | |||
<td>commit</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>waitForElementPresent</td> | |||
<td>css=.js-user-authenticated</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>open</td> | |||
<td>/settings?category=DEV</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>waitForValue</td> | |||
<td>name=page_version</td> | |||
<td>1</td> | |||
</tr> | |||
<tr> | |||
<td>type</td> | |||
<td>id=input_text</td> | |||
<td>text</td> | |||
</tr> | |||
<tr> | |||
<td>select</td> | |||
<td>id=input_boolean</td> | |||
<td>label=True</td> | |||
</tr> | |||
<tr> | |||
<td>type</td> | |||
<td>id=input_float</td> | |||
<td>42.0</td> | |||
</tr> | |||
<tr> | |||
<td>type</td> | |||
<td>id=input_license</td> | |||
<td>abc</td> | |||
</tr> | |||
<tr> | |||
<td>select</td> | |||
<td>id=input_metric</td> | |||
<td>label=Overall Condition Coverage</td> | |||
</tr> | |||
<tr> | |||
<td>type</td> | |||
<td>id=input_password</td> | |||
<td>abcde</td> | |||
</tr> | |||
<tr> | |||
<td>type</td> | |||
<td>id=input_regexp</td> | |||
<td>.*</td> | |||
</tr> | |||
<tr> | |||
<td>select</td> | |||
<td>id=input_list</td> | |||
<td>label=AAA</td> | |||
</tr> | |||
<tr> | |||
<td>click</td> | |||
<td>id=submit_settings</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>waitForValue</td> | |||
<td>name=page_version</td> | |||
<td>2</td> | |||
</tr> | |||
<tr> | |||
<td>assertValue</td> | |||
<td>id=input_text</td> | |||
<td>text</td> | |||
</tr> | |||
<tr> | |||
<td>assertValue</td> | |||
<td>id=input_boolean</td> | |||
<td>true</td> | |||
</tr> | |||
<tr> | |||
<td>assertValue</td> | |||
<td>id=input_float</td> | |||
<td>42.0</td> | |||
</tr> | |||
<tr> | |||
<td>assertValue</td> | |||
<td>id=input_license</td> | |||
<td>abc</td> | |||
</tr> | |||
<tr> | |||
<td>assertValue</td> | |||
<td>id=input_metric</td> | |||
<td>overall_branch_coverage</td> | |||
</tr> | |||
<tr> | |||
<td>assertValue</td> | |||
<td>id=input_password</td> | |||
<td>{{*******************}}</td> | |||
</tr> | |||
<tr> | |||
<td>assertValue</td> | |||
<td>id=input_regexp</td> | |||
<td>exact:.*</td> | |||
</tr> | |||
<tr> | |||
<td>assertValue</td> | |||
<td>id=input_list</td> | |||
<td>AAA</td> | |||
</tr> | |||
</tbody> | |||
</table> | |||
</body> | |||
</html> |
@@ -1,89 +0,0 @@ | |||
<?xml version="1.0" encoding="UTF-8"?> | |||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> | |||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> | |||
<head profile="http://selenium-ide.openqa.org/profiles/test-case"> | |||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> | |||
<title>create</title> | |||
</head> | |||
<body> | |||
<table cellpadding="1" cellspacing="1" border="1"> | |||
<tbody> | |||
<tr> | |||
<td>open</td> | |||
<td>/sessions/new</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>type</td> | |||
<td>login</td> | |||
<td>admin</td> | |||
</tr> | |||
<tr> | |||
<td>type</td> | |||
<td>password</td> | |||
<td>admin</td> | |||
</tr> | |||
<tr> | |||
<td>clickAndWait</td> | |||
<td>commit</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>waitForElementPresent</td> | |||
<td>css=.js-user-authenticated</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>open</td> | |||
<td>/settings?category=DEV</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>waitForValue</td> | |||
<td>name=page_version</td> | |||
<td>1</td> | |||
</tr> | |||
<tr> | |||
<td>type</td> | |||
<td>id=input_key</td> | |||
<td>jira1</td> | |||
</tr> | |||
<tr> | |||
<td>type</td> | |||
<td>id=input_url</td> | |||
<td>http://jira</td> | |||
</tr> | |||
<tr> | |||
<td>type</td> | |||
<td>id=input_port</td> | |||
<td>12345</td> | |||
</tr> | |||
<tr> | |||
<td>click</td> | |||
<td>id=submit_settings</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>waitForValue</td> | |||
<td>name=page_version</td> | |||
<td>2</td> | |||
</tr> | |||
<tr> | |||
<td>assertValue</td> | |||
<td>id=input_key</td> | |||
<td>jira1</td> | |||
</tr> | |||
<tr> | |||
<td>assertValue</td> | |||
<td>id=input_url</td> | |||
<td>exact:http://jira</td> | |||
</tr> | |||
<tr> | |||
<td>assertValue</td> | |||
<td>id=input_port</td> | |||
<td>12345</td> | |||
</tr> | |||
</tbody> | |||
</table> | |||
</body> | |||
</html> |
@@ -1,119 +0,0 @@ | |||
<?xml version="1.0" encoding="UTF-8"?> | |||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> | |||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> | |||
<head profile="http://selenium-ide.openqa.org/profiles/test-case"> | |||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> | |||
<title>delete</title> | |||
</head> | |||
<body> | |||
<table cellpadding="1" cellspacing="1" border="1"> | |||
<tbody> | |||
<tr> | |||
<td>open</td> | |||
<td>/sessions/new</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>type</td> | |||
<td>login</td> | |||
<td>admin</td> | |||
</tr> | |||
<tr> | |||
<td>type</td> | |||
<td>password</td> | |||
<td>admin</td> | |||
</tr> | |||
<tr> | |||
<td>clickAndWait</td> | |||
<td>commit</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>waitForElementPresent</td> | |||
<td>css=.js-user-authenticated</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>open</td> | |||
<td>/settings?category=DEV</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>waitForValue</td> | |||
<td>name=page_version</td> | |||
<td>1</td> | |||
</tr> | |||
<tr> | |||
<td>type</td> | |||
<td>id=input_key</td> | |||
<td>jira1</td> | |||
</tr> | |||
<tr> | |||
<td>type</td> | |||
<td>id=input_url</td> | |||
<td>http://jira1</td> | |||
</tr> | |||
<tr> | |||
<td>click</td> | |||
<td>css=#block_sonar\.test\.jira\.servers .add_value</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>type</td> | |||
<td>xpath=(//input[@id='input_key'])[2]</td> | |||
<td>jira2</td> | |||
</tr> | |||
<tr> | |||
<td>type</td> | |||
<td>xpath=(//input[@id='input_url'])[2]</td> | |||
<td>http://jira2</td> | |||
</tr> | |||
<tr> | |||
<td>click</td> | |||
<td>id=submit_settings</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>waitForValue</td> | |||
<td>name=page_version</td> | |||
<td>2</td> | |||
</tr> | |||
<tr> | |||
<td>assertValue</td> | |||
<td>xpath=(//input[@id='input_key'])[1]</td> | |||
<td>jira1</td> | |||
</tr> | |||
<tr> | |||
<td>assertValue</td> | |||
<td>xpath=(//input[@id='input_key'])[2]</td> | |||
<td>jira2</td> | |||
</tr> | |||
<tr> | |||
<td>click</td> | |||
<td>xpath=(//a[contains(text(),'Delete')])[3]</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>click</td> | |||
<td>id=submit_settings</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>waitForValue</td> | |||
<td>name=page_version</td> | |||
<td>3</td> | |||
</tr> | |||
<tr> | |||
<td>assertValue</td> | |||
<td>xpath=(//input[@id='input_key'])[1]</td> | |||
<td>jira1</td> | |||
</tr> | |||
<tr> | |||
<td>waitForNotText</td> | |||
<td>xpath=(//input[@id='input_key'])</td> | |||
<td>*jira2*</td> | |||
</tr> | |||
</tbody> | |||
</table> | |||
</body> | |||
</html> |
@@ -1,94 +0,0 @@ | |||
<?xml version="1.0" encoding="UTF-8"?> | |||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> | |||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> | |||
<head profile="http://selenium-ide.openqa.org/profiles/test-case"> | |||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> | |||
<title>reference</title> | |||
</head> | |||
<body> | |||
<table cellpadding="1" cellspacing="1" border="1"> | |||
<tbody> | |||
<tr> | |||
<td>open</td> | |||
<td>/sessions/new</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>type</td> | |||
<td>login</td> | |||
<td>admin</td> | |||
</tr> | |||
<tr> | |||
<td>type</td> | |||
<td>password</td> | |||
<td>admin</td> | |||
</tr> | |||
<tr> | |||
<td>clickAndWait</td> | |||
<td>commit</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>waitForElementPresent</td> | |||
<td>css=.js-user-authenticated</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>open</td> | |||
<td>/settings?category=DEV</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>waitForValue</td> | |||
<td>name=page_version</td> | |||
<td>1</td> | |||
</tr> | |||
<tr> | |||
<td>type</td> | |||
<td>xpath=(//input[@id='input_key'])[1]</td> | |||
<td>jira1</td> | |||
</tr> | |||
<tr> | |||
<td>click</td> | |||
<td>css=#block_sonar\.test\.jira\.servers .add_value</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>type</td> | |||
<td>xpath=(//input[@id='input_key'])[2]</td> | |||
<td>jira2</td> | |||
</tr> | |||
<tr> | |||
<td>click</td> | |||
<td>id=submit_settings</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>waitForValue</td> | |||
<td>name=page_version</td> | |||
<td>2</td> | |||
</tr> | |||
<tr> | |||
<td>assertSelectOptions</td> | |||
<td>id=input_sonar.test.jira</td> | |||
<td>Default,jira1,jira2</td> | |||
</tr> | |||
<tr> | |||
<td>click</td> | |||
<td>xpath=(//a[contains(text(),'Delete')])[2]</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>click</td> | |||
<td>id=submit_settings</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>waitForValue</td> | |||
<td>name=page_version</td> | |||
<td>3</td> | |||
</tr> | |||
</tbody> | |||
</table> | |||
</body> | |||
</html> |
@@ -15,7 +15,7 @@ | |||
</tr> | |||
<tr> | |||
<td>open</td> | |||
<td>/settings?category=security&subcategory=encryption</td> | |||
<td>/encryption_configuration</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
@@ -35,12 +35,7 @@ | |||
</tr> | |||
<tr> | |||
<td>waitForElementPresent</td> | |||
<td>css=.js-user-authenticated</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>selectFrame</td> | |||
<td>settings_iframe</td> | |||
<td>css=#submit_encrypt</td> | |||
<td></td> | |||
</tr> | |||
<tr> |
@@ -1,59 +0,0 @@ | |||
<?xml version="1.0" encoding="UTF-8"?> | |||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> | |||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> | |||
<head profile="http://selenium-ide.openqa.org/profiles/test-case"> | |||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> | |||
<title>settings_on_core_plugins</title> | |||
</head> | |||
<body> | |||
<table cellpadding="1" cellspacing="1" border="1"> | |||
<thead> | |||
<tr> | |||
<td rowspan="1" colspan="3">settings_on_core_plugins</td> | |||
</tr> | |||
</thead> | |||
<tbody> | |||
<tr> | |||
<td>open</td> | |||
<td>/sessions/logout</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>open</td> | |||
<td>/sessions/new</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>type</td> | |||
<td>login</td> | |||
<td>admin</td> | |||
</tr> | |||
<tr> | |||
<td>type</td> | |||
<td>password</td> | |||
<td>admin</td> | |||
</tr> | |||
<tr> | |||
<td>clickAndWait</td> | |||
<td>commit</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>waitForElementPresent</td> | |||
<td>css=.js-user-authenticated</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>open</td> | |||
<td>/settings/index</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>waitForText</td> | |||
<td>plugins</td> | |||
<td>*General*</td> | |||
</tr> | |||
</tbody> | |||
</table> | |||
</body> | |||
</html> |
@@ -15,7 +15,7 @@ | |||
</tr> | |||
<tr> | |||
<td>open</td> | |||
<td>/settings?category=security&subcategory=encryption</td> | |||
<td>/encryption_configuration</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
@@ -35,12 +35,7 @@ | |||
</tr> | |||
<tr> | |||
<td>waitForElementPresent</td> | |||
<td>css=.js-user-authenticated</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>selectFrame</td> | |||
<td>settings_iframe</td> | |||
<td>css=#submit_encrypt</td> | |||
<td></td> | |||
</tr> | |||
<tr> |
@@ -1,55 +0,0 @@ | |||
<?xml version="1.0" encoding="UTF-8"?> | |||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> | |||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> | |||
<head profile="http://selenium-ide.openqa.org/profiles/test-case"> | |||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> | |||
<title>global-extension-property</title> | |||
</head> | |||
<body> | |||
<table cellpadding="1" cellspacing="1" border="1"> | |||
<thead> | |||
<tr> | |||
<td rowspan="1" colspan="3">global-extension-property</td> | |||
</tr> | |||
</thead> | |||
<tbody> | |||
<tr> | |||
<td>open</td> | |||
<td>/sessions/new</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>type</td> | |||
<td>login</td> | |||
<td>admin</td> | |||
</tr> | |||
<tr> | |||
<td>type</td> | |||
<td>password</td> | |||
<td>admin</td> | |||
</tr> | |||
<tr> | |||
<td>clickAndWait</td> | |||
<td>commit</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>waitForElementPresent</td> | |||
<td>css=.js-user-authenticated</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>open</td> | |||
<td>/settings?category=Settings</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>assertNotText</td> | |||
<td>plugins</td> | |||
<td>glob:*Hidden*</td> | |||
</tr> | |||
</tbody> | |||
</table> | |||
</body> | |||
</html> |
@@ -1,55 +0,0 @@ | |||
<?xml version="1.0" encoding="UTF-8"?> | |||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> | |||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> | |||
<head profile="http://selenium-ide.openqa.org/profiles/test-case"> | |||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> | |||
<title>hidden-extension-property</title> | |||
</head> | |||
<body> | |||
<table cellpadding="1" cellspacing="1" border="1"> | |||
<thead> | |||
<tr> | |||
<td rowspan="1" colspan="3">hidden-extension-property</td> | |||
</tr> | |||
</thead> | |||
<tbody> | |||
<tr> | |||
<td>open</td> | |||
<td>/sessions/new</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>type</td> | |||
<td>login</td> | |||
<td>admin</td> | |||
</tr> | |||
<tr> | |||
<td>type</td> | |||
<td>password</td> | |||
<td>admin</td> | |||
</tr> | |||
<tr> | |||
<td>clickAndWait</td> | |||
<td>commit</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>waitForElementPresent</td> | |||
<td>css=.js-user-authenticated</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>open</td> | |||
<td>/settings?category=Settings</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>assertNotText</td> | |||
<td>plugins</td> | |||
<td>glob:*Hidden*</td> | |||
</tr> | |||
</tbody> | |||
</table> | |||
</body> | |||
</html> |
@@ -1,54 +0,0 @@ | |||
<?xml version="1.0" encoding="UTF-8"?> | |||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> | |||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> | |||
<head profile="http://selenium-ide.openqa.org/profiles/test-case"> | |||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> | |||
<title>hide-passwords</title> | |||
</head> | |||
<body> | |||
<table cellpadding="1" cellspacing="1" border="1"> | |||
<tbody> | |||
<tr> | |||
<td>open</td> | |||
<td>/sessions/logout</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>open</td> | |||
<td>/settings?category=Settings</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>type</td> | |||
<td>id=login</td> | |||
<td>admin</td> | |||
</tr> | |||
<tr> | |||
<td>type</td> | |||
<td>id=password</td> | |||
<td>admin</td> | |||
</tr> | |||
<tr> | |||
<td>clickAndWait</td> | |||
<td>name=commit</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>waitForElementPresent</td> | |||
<td>css=.js-user-authenticated</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>waitForText</td> | |||
<td>block_password</td> | |||
<td>*Default*</td> | |||
</tr> | |||
<tr> | |||
<td>assertNotText</td> | |||
<td>block_password</td> | |||
<td>*Default*sonar*</td> | |||
</tr> | |||
</tbody> | |||
</table> | |||
</body> | |||
</html> |
@@ -1,54 +0,0 @@ | |||
<?xml version="1.0" encoding="UTF-8"?> | |||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> | |||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> | |||
<head profile="http://selenium-ide.openqa.org/profiles/test-case"> | |||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> | |||
<title>property-relocation</title> | |||
</head> | |||
<body> | |||
<table cellpadding="1" cellspacing="1" border="1"> | |||
<tbody> | |||
<tr> | |||
<td>open</td> | |||
<td>/sessions/logout</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>open</td> | |||
<td>/settings/index?category=general</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>type</td> | |||
<td>id=login</td> | |||
<td>admin</td> | |||
</tr> | |||
<tr> | |||
<td>type</td> | |||
<td>id=password</td> | |||
<td>admin</td> | |||
</tr> | |||
<tr> | |||
<td>clickAndWait</td> | |||
<td>name=commit</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>waitForElementPresent</td> | |||
<td>css=.js-user-authenticated</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>waitForText</td> | |||
<td>properties</td> | |||
<td>*sonar.newKey*</td> | |||
</tr> | |||
<tr> | |||
<td>assertNotText</td> | |||
<td>properties</td> | |||
<td>*sonar.deprecatedKey*</td> | |||
</tr> | |||
</tbody> | |||
</table> | |||
</body> | |||
</html> |
@@ -1,79 +0,0 @@ | |||
<?xml version="1.0" encoding="UTF-8"?> | |||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> | |||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> | |||
<head profile="http://selenium-ide.openqa.org/profiles/test-case"> | |||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> | |||
<title>validate-property-type</title> | |||
</head> | |||
<body> | |||
<table cellpadding="1" cellspacing="1" border="1"> | |||
<tbody> | |||
<tr> | |||
<td>open</td> | |||
<td>/sessions/logout</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>open</td> | |||
<td>/settings?category=Settings</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>type</td> | |||
<td>id=login</td> | |||
<td>admin</td> | |||
</tr> | |||
<tr> | |||
<td>type</td> | |||
<td>id=password</td> | |||
<td>admin</td> | |||
</tr> | |||
<tr> | |||
<td>clickAndWait</td> | |||
<td>name=commit</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>waitForElementPresent</td> | |||
<td>css=.js-user-authenticated</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>type</td> | |||
<td>id=input_float</td> | |||
<td>abc</td> | |||
</tr> | |||
<tr> | |||
<td>type</td> | |||
<td>id=input_integer</td> | |||
<td>123</td> | |||
</tr> | |||
<tr> | |||
<td>click</td> | |||
<td>id=submit_settings</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>waitForText</td> | |||
<td>properties</td> | |||
<td>*Not a floating point number*</td> | |||
</tr> | |||
<tr> | |||
<td>assertValue</td> | |||
<td>input_integer</td> | |||
<td>123</td> | |||
</tr> | |||
<tr> | |||
<td>open</td> | |||
<td>/settings?category=Settings</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>assertValue</td> | |||
<td>input_float</td> | |||
<td></td> | |||
</tr> | |||
</tbody> | |||
</table> | |||
</body> | |||
</html> |
@@ -1,60 +0,0 @@ | |||
<?xml version="1.0" encoding="UTF-8"?> | |||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> | |||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> | |||
<head profile="http://selenium-ide.openqa.org/profiles/test-case"> | |||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> | |||
<title>global-subcategories</title> | |||
</head> | |||
<body> | |||
<table cellpadding="1" cellspacing="1" border="1"> | |||
<tbody> | |||
<tr> | |||
<td>open</td> | |||
<td>/sessions/new</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>type</td> | |||
<td>login</td> | |||
<td>admin</td> | |||
</tr> | |||
<tr> | |||
<td>type</td> | |||
<td>password</td> | |||
<td>admin</td> | |||
</tr> | |||
<tr> | |||
<td>clickAndWait</td> | |||
<td>commit</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>waitForElementPresent</td> | |||
<td>css=.js-user-authenticated</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>open</td> | |||
<td>/settings?category=Category 2</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>waitForValue</td> | |||
<td>name=page_version</td> | |||
<td>1</td> | |||
</tr> | |||
<!-- First subcategory should be selected by default --> | |||
<tr> | |||
<td>assertElementPresent</td> | |||
<td>id=input_prop2_1</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>assertElementNotPresent</td> | |||
<td>id=input_prop2_2</td> | |||
<td></td> | |||
</tr> | |||
</tbody> | |||
</table> | |||
</body> | |||
</html> |
@@ -1,156 +0,0 @@ | |||
<?xml version="1.0" encoding="UTF-8"?> | |||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> | |||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> | |||
<head profile="http://selenium-ide.openqa.org/profiles/test-case"> | |||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> | |||
<title>global-subcategories</title> | |||
</head> | |||
<body> | |||
<table cellpadding="1" cellspacing="1" border="1"> | |||
<tbody> | |||
<tr> | |||
<td>open</td> | |||
<td>/sessions/new</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>type</td> | |||
<td>login</td> | |||
<td>admin</td> | |||
</tr> | |||
<tr> | |||
<td>type</td> | |||
<td>password</td> | |||
<td>admin</td> | |||
</tr> | |||
<tr> | |||
<td>clickAndWait</td> | |||
<td>commit</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>waitForElementPresent</td> | |||
<td>css=.js-user-authenticated</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>open</td> | |||
<td>/settings?category=Category 1</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>waitForValue</td> | |||
<td>name=page_version</td> | |||
<td>1</td> | |||
</tr> | |||
<tr> | |||
<td>assertElementNotPresent</td> | |||
<td>id=input_prop1</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>assertElementNotPresent</td> | |||
<td>id=input_prop2</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>assertElementNotPresent</td> | |||
<td>id=input_prop3</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>assertElementPresent</td> | |||
<td>id=input_prop4</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>clickAndWait</td> | |||
<td>link=Sub category 1</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>assertElementPresent</td> | |||
<td>id=input_prop1</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>assertElementPresent</td> | |||
<td>id=input_prop2</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>assertElementNotPresent</td> | |||
<td>id=input_prop3</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>assertElementNotPresent</td> | |||
<td>id=input_prop4</td> | |||
<td></td> | |||
</tr> | |||
<!-- Verify index attribute is taken into account --> | |||
<tr> | |||
<td>assertElementPresent</td> | |||
<td>xpath=//.[@id='input_prop2']/following::input[@id='input_prop1']</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>clickAndWait</td> | |||
<td>link=Sub category 2</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>type</td> | |||
<td>id=input_prop3</td> | |||
<td>myValue</td> | |||
</tr> | |||
<tr> | |||
<td>click</td> | |||
<td>id=submit_settings</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>waitForValue</td> | |||
<td>name=page_version</td> | |||
<td>2</td> | |||
</tr> | |||
<tr> | |||
<td>assertElementNotPresent</td> | |||
<td>id=input_prop1</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>assertElementNotPresent</td> | |||
<td>id=input_prop2</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>assertElementPresent</td> | |||
<td>id=input_prop3</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>assertElementNotPresent</td> | |||
<td>id=input_prop4</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>assertValue</td> | |||
<td>id=input_prop3</td> | |||
<td>myValue</td> | |||
</tr> | |||
<!-- SONAR-4473 --> | |||
<tr> | |||
<td>clickAndWait</td> | |||
<td>link=Sub category 1</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>assertElementPresent</td> | |||
<td>id=input_prop1</td> | |||
<td></td> | |||
</tr> | |||
</tbody> | |||
</table> | |||
</body> | |||
</html> |
@@ -1,60 +0,0 @@ | |||
<?xml version="1.0" encoding="UTF-8"?> | |||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> | |||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> | |||
<head profile="http://selenium-ide.openqa.org/profiles/test-case"> | |||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> | |||
<title>create</title> | |||
</head> | |||
<body> | |||
<table cellpadding="1" cellspacing="1" border="1"> | |||
<tbody> | |||
<tr> | |||
<td>open</td> | |||
<td>/sessions/new</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>type</td> | |||
<td>login</td> | |||
<td>admin</td> | |||
</tr> | |||
<tr> | |||
<td>type</td> | |||
<td>password</td> | |||
<td>admin</td> | |||
</tr> | |||
<tr> | |||
<td>clickAndWait</td> | |||
<td>commit</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>waitForElementPresent</td> | |||
<td>css=.js-user-authenticated</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>open</td> | |||
<td>/project/settings/sample?category=Category 2</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>waitForValue</td> | |||
<td>name=page_version</td> | |||
<td>1</td> | |||
</tr> | |||
<!-- First subcategory should be selected by default --> | |||
<tr> | |||
<td>assertElementPresent</td> | |||
<td>id=input_prop2_1</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>assertElementNotPresent</td> | |||
<td>id=input_prop2_2</td> | |||
<td></td> | |||
</tr> | |||
</tbody> | |||
</table> | |||
</body> | |||
</html> |
@@ -1,150 +0,0 @@ | |||
<?xml version="1.0" encoding="UTF-8"?> | |||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> | |||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> | |||
<head profile="http://selenium-ide.openqa.org/profiles/test-case"> | |||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> | |||
<title>create</title> | |||
</head> | |||
<body> | |||
<table cellpadding="1" cellspacing="1" border="1"> | |||
<tbody> | |||
<tr> | |||
<td>open</td> | |||
<td>/sessions/new</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>type</td> | |||
<td>login</td> | |||
<td>admin</td> | |||
</tr> | |||
<tr> | |||
<td>type</td> | |||
<td>password</td> | |||
<td>admin</td> | |||
</tr> | |||
<tr> | |||
<td>clickAndWait</td> | |||
<td>commit</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>waitForElementPresent</td> | |||
<td>css=.js-user-authenticated</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>open</td> | |||
<td>/project/settings/sample?category=Category 1</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>waitForValue</td> | |||
<td>name=page_version</td> | |||
<td>1</td> | |||
</tr> | |||
<tr> | |||
<td>assertElementNotPresent</td> | |||
<td>id=input_prop1</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>assertElementNotPresent</td> | |||
<td>id=input_prop2</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>assertElementNotPresent</td> | |||
<td>id=input_prop3</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>assertElementPresent</td> | |||
<td>id=input_prop4</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>clickAndWait</td> | |||
<td>link=Sub category 1</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>assertElementPresent</td> | |||
<td>id=input_prop1</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>assertElementPresent</td> | |||
<td>id=input_prop2</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>assertElementNotPresent</td> | |||
<td>id=input_prop3</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>assertElementNotPresent</td> | |||
<td>id=input_prop4</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>clickAndWait</td> | |||
<td>link=Sub category 2</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>type</td> | |||
<td>id=input_prop3</td> | |||
<td>myValue2</td> | |||
</tr> | |||
<tr> | |||
<td>click</td> | |||
<td>id=submit_settings</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>waitForValue</td> | |||
<td>name=page_version</td> | |||
<td>2</td> | |||
</tr> | |||
<tr> | |||
<td>assertElementNotPresent</td> | |||
<td>id=input_prop1</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>assertElementNotPresent</td> | |||
<td>id=input_prop2</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>assertElementPresent</td> | |||
<td>id=input_prop3</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>assertElementNotPresent</td> | |||
<td>id=input_prop4</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>assertValue</td> | |||
<td>id=input_prop3</td> | |||
<td>myValue2</td> | |||
</tr> | |||
<!-- SONAR-4473 --> | |||
<tr> | |||
<td>clickAndWait</td> | |||
<td>link=Sub category 1</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>assertElementPresent</td> | |||
<td>id=input_prop1</td> | |||
<td></td> | |||
</tr> | |||
</tbody> | |||
</table> | |||
</body> | |||
</html> |
@@ -15,7 +15,7 @@ | |||
</tr> | |||
<tr> | |||
<td>open</td> | |||
<td>/settings</td> | |||
<td>/updatecenter</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
@@ -38,11 +38,6 @@ | |||
<td>css=.js-user-authenticated</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>open</td> | |||
<td>/updatecenter</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>waitForText</td> | |||
<td>content</td> |
@@ -14,7 +14,7 @@ | |||
</tr> | |||
<tr> | |||
<td>open</td> | |||
<td>/settings/index</td> | |||
<td>/settings</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
@@ -54,12 +54,7 @@ | |||
</tr> | |||
<tr> | |||
<td>assertLocation</td> | |||
<td>*/settings/index</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>assertElementPresent</td> | |||
<td>plugins</td> | |||
<td>*/settings</td> | |||
<td></td> | |||
</tr> | |||
</tbody> |
@@ -45,6 +45,7 @@ module.exports = { | |||
'projects': './src/main/js/apps/projects/app.js', | |||
'quality-gates': './src/main/js/apps/quality-gates/app.js', | |||
'quality-profiles': './src/main/js/apps/quality-profiles/app.js', | |||
'settings': './src/main/js/apps/settings/app.js', | |||
'source-viewer': './src/main/js/apps/source-viewer/app.js', | |||
'system': './src/main/js/apps/system/app.js', | |||
'update-center': './src/main/js/apps/update-center/app.js', |
@@ -121,14 +121,10 @@ function setupCompiler () { | |||
function runDevServer (port) { | |||
app.use(require('webpack-dev-middleware')(compiler, { | |||
noInfo: true, | |||
quiet: true, | |||
publicPath: config.output.publicPath | |||
})); | |||
app.use(require('webpack-hot-middleware')(compiler, { | |||
noInfo: true, | |||
quiet: true | |||
})); | |||
app.use(require('webpack-hot-middleware')(compiler)); | |||
app.all('*', proxy(API_HOST, { | |||
forwardPath: function (req) { |
@@ -0,0 +1,69 @@ | |||
/* | |||
* 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 omitBy from 'lodash/omitBy'; | |||
import { getJSON, post } from '../helpers/request'; | |||
import { TYPE_PROPERTY_SET } from '../apps/settings/constants'; | |||
export function getDefinitions (componentKey) { | |||
const url = '/api/settings/list_definitions'; | |||
const data = componentKey ? { componentKey } : {}; | |||
return getJSON(url, data).then(r => r.definitions); | |||
} | |||
export function getValues (keys, componentKey) { | |||
const url = '/api/settings/values'; | |||
const data = { keys }; | |||
if (componentKey) { | |||
data.componentKey = componentKey; | |||
} | |||
return getJSON(url, data).then(r => r.settings); | |||
} | |||
export function setSettingValue (definition, value, componentKey) { | |||
const url = '/api/settings/set'; | |||
const { key } = definition; | |||
const data = { key }; | |||
if (definition.multiValues) { | |||
data.values = value; | |||
} else if (definition.type === TYPE_PROPERTY_SET) { | |||
data.fieldValues = value | |||
.map(fields => omitBy(fields, value => value == null)) | |||
.map(JSON.stringify); | |||
} else { | |||
data.value = value; | |||
} | |||
if (componentKey) { | |||
data.componentKey = componentKey; | |||
} | |||
return post(url, data); | |||
} | |||
export function resetSettingValue (key, componentKey) { | |||
const url = '/api/settings/reset'; | |||
const data = { key }; | |||
if (componentKey) { | |||
data.componentKey = componentKey; | |||
} | |||
return post(url, data); | |||
} |
@@ -39,3 +39,9 @@ export function getIdentityProviders () { | |||
const url = '/api/users/identity_providers'; | |||
return getJSON(url); | |||
} | |||
export function searchUsers (query) { | |||
const url = '/api/users/search'; | |||
const data = { q: query }; | |||
return getJSON(url, data); | |||
} |
@@ -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 { expect } from 'chai'; | |||
import { getEmptyValue } from '../utils'; | |||
import { TYPE_PROPERTY_SET, TYPE_STRING, TYPE_SINGLE_SELECT_LIST, TYPE_BOOLEAN } from '../constants'; | |||
const fields = [ | |||
{ key: 'foo', type: TYPE_STRING }, | |||
{ key: 'bar', type: TYPE_SINGLE_SELECT_LIST } | |||
]; | |||
describe('Settings :: Utils', () => { | |||
describe('#getEmptyValue()', () => { | |||
it('should work for property sets', () => { | |||
const setting = { type: TYPE_PROPERTY_SET, fields }; | |||
expect(getEmptyValue(setting)).to.deep.equal([{ foo: '', bar: null }]); | |||
}); | |||
it('should work for multi values string', () => { | |||
const setting = { type: TYPE_STRING, multiValues: true }; | |||
expect(getEmptyValue(setting)).to.deep.equal(['']); | |||
}); | |||
it('should work for multi values boolean', () => { | |||
const setting = { type: TYPE_BOOLEAN, multiValues: true }; | |||
expect(getEmptyValue(setting)).to.deep.equal([null]); | |||
}); | |||
}); | |||
}); |
@@ -0,0 +1,50 @@ | |||
/* | |||
* 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 { render } from 'react-dom'; | |||
import { Provider } from 'react-redux'; | |||
import { Router, Route, Redirect, useRouterHistory } from 'react-router'; | |||
import { createHistory } from 'history'; | |||
import App from './components/App'; | |||
import rootReducer from './store/rootReducer'; | |||
import configureStore from '../../components/store/configureStore'; | |||
window.sonarqube.appStarted.then(options => { | |||
const el = document.querySelector(options.el); | |||
const controller = options.component ? '/project/settings' : '/settings'; | |||
const history = useRouterHistory(createHistory)({ | |||
basename: window.baseUrl + controller | |||
}); | |||
const store = configureStore(rootReducer); | |||
const withComponent = ComposedComponent => props => | |||
<ComposedComponent {...props} component={options.component}/>; | |||
render(( | |||
<Provider store={store}> | |||
<Router history={history}> | |||
<Redirect from="/index" to="/"/> | |||
<Route path="/" component={withComponent(App)}/> | |||
</Router> | |||
</Provider> | |||
), el); | |||
}); |
@@ -0,0 +1,37 @@ | |||
/* | |||
* 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 { connect } from 'react-redux'; | |||
import CategoriesList from './CategoriesList'; | |||
import { getAllCategories } from '../store/rootReducer'; | |||
class AllCategoriesList extends React.Component { | |||
render () { | |||
return <CategoriesList {...this.props}/>; | |||
} | |||
} | |||
const mapStateToProps = state => ({ | |||
categories: getAllCategories(state) | |||
}); | |||
export default connect( | |||
mapStateToProps | |||
)(AllCategoriesList); |
@@ -0,0 +1,101 @@ | |||
/* | |||
* 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 shallowCompare from 'react-addons-shallow-compare'; | |||
import { connect } from 'react-redux'; | |||
import PageHeader from './PageHeader'; | |||
import CategoryDefinitionsList from './CategoryDefinitionsList'; | |||
import AllCategoriesList from './AllCategoriesList'; | |||
import GlobalMessagesContainer from './GlobalMessagesContainer'; | |||
import { fetchSettings } from '../store/actions'; | |||
import { getDefaultCategory } from '../store/rootReducer'; | |||
import '../styles.css'; | |||
class App extends React.Component { | |||
static propTypes = { | |||
component: React.PropTypes.object, | |||
fetchSettings: React.PropTypes.func.isRequired, | |||
defaultCategory: React.PropTypes.string | |||
}; | |||
state = { loaded: false }; | |||
componentDidMount () { | |||
document.querySelector('html').classList.add('dashboard-page'); | |||
const componentKey = this.props.component ? this.props.component.key : null; | |||
this.props.fetchSettings(componentKey).then(() => { | |||
this.setState({ loaded: true }); | |||
}); | |||
} | |||
shouldComponentUpdate (nextProps, nextState) { | |||
return shallowCompare(this, nextProps, nextState); | |||
} | |||
componentDidUpdate (prevProps) { | |||
if (prevProps.component !== this.props.component) { | |||
const componentKey = this.props.component ? this.props.component.key : null; | |||
this.props.fetchSettings(componentKey); | |||
} | |||
} | |||
componentWillUnmount () { | |||
document.querySelector('html').classList.remove('dashboard-page'); | |||
} | |||
render () { | |||
if (!this.state.loaded) { | |||
return null; | |||
} | |||
const { query } = this.props.location; | |||
const selectedCategory = query.category || this.props.defaultCategory; | |||
return ( | |||
<div id="settings-page" className="page page-limited"> | |||
<PageHeader component={this.props.component}/> | |||
<GlobalMessagesContainer/> | |||
<div className="settings-layout"> | |||
<div className="settings-side"> | |||
<AllCategoriesList | |||
component={this.props.component} | |||
selectedCategory={selectedCategory} | |||
defaultCategory={this.props.defaultCategory}/> | |||
</div> | |||
<div className="settings-main"> | |||
<CategoryDefinitionsList | |||
component={this.props.component} | |||
category={selectedCategory}/> | |||
</div> | |||
</div> | |||
</div> | |||
); | |||
} | |||
} | |||
const mapStateToProps = state => ({ | |||
defaultCategory: getDefaultCategory(state) | |||
}); | |||
export default connect( | |||
mapStateToProps, | |||
{ fetchSettings } | |||
)(App); | |||
@@ -0,0 +1,71 @@ | |||
/* | |||
* 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 shallowCompare from 'react-addons-shallow-compare'; | |||
import sortBy from 'lodash/sortBy'; | |||
import { IndexLink } from 'react-router'; | |||
import { getCategoryName } from '../utils'; | |||
export default class CategoriesList extends React.Component { | |||
static propTypes = { | |||
categories: React.PropTypes.array.isRequired, | |||
selectedCategory: React.PropTypes.string.isRequired, | |||
defaultCategory: React.PropTypes.string.isRequired | |||
}; | |||
shouldComponentUpdate (nextProps, nextState) { | |||
return shallowCompare(this, nextProps, nextState); | |||
} | |||
renderLink (category) { | |||
const query = {}; | |||
if (category.key !== this.props.defaultCategory) { | |||
query.category = category.key.toLowerCase(); | |||
} | |||
if (this.props.component) { | |||
query.id = this.props.component.key; | |||
} | |||
const className = category.key.toLowerCase() === this.props.selectedCategory.toLowerCase() ? 'active' : ''; | |||
return ( | |||
<IndexLink to={{ pathname: '/', query }} className={className} title={category.name}> | |||
{category.name} | |||
</IndexLink> | |||
); | |||
} | |||
render () { | |||
const categoriesWithName = this.props.categories.map(key => ({ key, name: getCategoryName(key) })); | |||
const sortedCategories = sortBy(categoriesWithName, category => category.name.toLowerCase()); | |||
return ( | |||
<ul className="settings-menu"> | |||
{sortedCategories.map(category => ( | |||
<li key={category.key}> | |||
{this.renderLink(category)} | |||
</li> | |||
))} | |||
</ul> | |||
); | |||
} | |||
} |
@@ -0,0 +1,37 @@ | |||
/* | |||
* 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 { connect } from 'react-redux'; | |||
import SubCategoryDefinitionsList from './SubCategoryDefinitionsList'; | |||
import { getSettingsForCategory } from '../store/rootReducer'; | |||
class CategoryDefinitionsList extends React.Component { | |||
render () { | |||
return <SubCategoryDefinitionsList {...this.props}/>; | |||
} | |||
} | |||
const mapStateToProps = (state, ownProps) => ({ | |||
settings: getSettingsForCategory(state, ownProps.category) | |||
}); | |||
export default connect( | |||
mapStateToProps | |||
)(CategoryDefinitionsList); |
@@ -0,0 +1,195 @@ | |||
/* | |||
* 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 { connect } from 'react-redux'; | |||
import shallowCompare from 'react-addons-shallow-compare'; | |||
import classNames from 'classnames'; | |||
import Input from './inputs/Input'; | |||
import DefinitionDefaults from './DefinitionDefaults'; | |||
import DefinitionChanges from './DefinitionChanges'; | |||
import { getPropertyName, getPropertyDescription, isEmptyValue, getSettingValue, isDefaultOrInherited } from '../utils'; | |||
import { translateWithParameters, translate } from '../../../helpers/l10n'; | |||
import { resetValue, saveValue } from '../store/actions'; | |||
import { isLoading, getValidationMessage, getChangedValue } from '../store/rootReducer'; | |||
import { failValidation, passValidation } from '../store/settingsPage/validationMessages/actions'; | |||
import { cancelChange, changeValue } from '../store/settingsPage/changedValues/actions'; | |||
class Definition extends React.Component { | |||
static propTypes = { | |||
component: React.PropTypes.object, | |||
setting: React.PropTypes.object.isRequired, | |||
changedValue: React.PropTypes.any, | |||
loading: React.PropTypes.bool.isRequired, | |||
validationMessage: React.PropTypes.string, | |||
changeValue: React.PropTypes.func.isRequired, | |||
cancelChange: React.PropTypes.func.isRequired, | |||
saveValue: React.PropTypes.func.isRequired, | |||
resetValue: React.PropTypes.func.isRequired, | |||
failValidation: React.PropTypes.func.isRequired, | |||
passValidation: React.PropTypes.func.isRequired | |||
}; | |||
state = { | |||
success: false | |||
}; | |||
componentDidMount () { | |||
this.mounted = true; | |||
} | |||
shouldComponentUpdate (nextProps, nextState) { | |||
return shallowCompare(this, nextProps, nextState); | |||
} | |||
componentWillUnmount () { | |||
this.mounted = false; | |||
} | |||
safeSetState (changes) { | |||
if (this.mounted) { | |||
this.setState(changes); | |||
} | |||
} | |||
handleChange (value) { | |||
clearTimeout(this.timeout); | |||
return this.props.changeValue(this.props.setting.definition.key, value); | |||
} | |||
handleReset () { | |||
const componentKey = this.props.component ? this.props.component.key : null; | |||
const { definition } = this.props.setting; | |||
return this.props.resetValue(definition.key, componentKey).then(() => { | |||
this.safeSetState({ success: true }); | |||
this.timeout = setTimeout(() => this.safeSetState({ success: false }), 3000); | |||
}).catch(() => { /* do nothing */ }); | |||
} | |||
handleCancel () { | |||
this.props.cancelChange(this.props.setting.definition.key); | |||
this.props.passValidation(this.props.setting.definition.key); | |||
} | |||
handleSave () { | |||
this.safeSetState({ success: false }); | |||
const { definition } = this.props.setting; | |||
if (isEmptyValue(definition, this.props.changedValue)) { | |||
this.props.failValidation(definition.key, translate('settings.state.value_cant_be_empty')); | |||
return; | |||
} | |||
const componentKey = this.props.component ? this.props.component.key : null; | |||
this.props.saveValue(this.props.setting.definition.key, componentKey).then(() => { | |||
this.safeSetState({ success: true }); | |||
this.timeout = setTimeout(() => this.safeSetState({ success: false }), 3000); | |||
}).catch(() => { /* do nothing */ }); | |||
} | |||
render () { | |||
const { setting, changedValue, loading } = this.props; | |||
const { definition } = setting; | |||
const propertyName = getPropertyName(definition); | |||
const hasValueChanged = changedValue != null; | |||
const className = classNames('settings-definition', { | |||
'settings-definition-changed': hasValueChanged | |||
}); | |||
const effectiveValue = hasValueChanged ? changedValue : getSettingValue(setting); | |||
const isDefault = isDefaultOrInherited(setting) && !hasValueChanged; | |||
return ( | |||
<div className={className} data-key={definition.key}> | |||
<div className="settings-definition-left"> | |||
<h3 className="settings-definition-name" title={propertyName}> | |||
{propertyName} | |||
</h3> | |||
<div className="settings-definition-description markdown small spacer-top" | |||
dangerouslySetInnerHTML={{ __html: getPropertyDescription(definition) }}/> | |||
<div className="settings-definition-key note little-spacer-top"> | |||
{translateWithParameters('settings.key_x', definition.key)} | |||
</div> | |||
</div> | |||
<div className="settings-definition-right"> | |||
<Input setting={setting} value={effectiveValue} onChange={this.handleChange.bind(this)}/> | |||
{!hasValueChanged && ( | |||
<DefinitionDefaults | |||
setting={setting} | |||
isDefault={isDefault} | |||
onReset={() => this.handleReset()}/> | |||
)} | |||
{hasValueChanged && ( | |||
<DefinitionChanges | |||
onSave={this.handleSave.bind(this)} | |||
onCancel={this.handleCancel.bind(this)}/> | |||
)} | |||
<div className="settings-definition-state"> | |||
{loading && ( | |||
<span className="text-info"> | |||
<span className="settings-definition-state-icon"> | |||
<i className="spinner"/> | |||
</span> | |||
{translate('settings.state.saving')} | |||
</span> | |||
)} | |||
{!loading && (this.props.validationMessage != null) && ( | |||
<span className="text-danger"> | |||
<span className="settings-definition-state-icon"> | |||
<i className="icon-alert-error"/> | |||
</span> | |||
{translateWithParameters('settings.state.validation_failed', this.props.validationMessage)} | |||
</span> | |||
)} | |||
{!loading && this.state.success && ( | |||
<span className="text-success"> | |||
<span className="settings-definition-state-icon"> | |||
<i className="icon-check"/> | |||
</span> | |||
{translate('settings.state.saved')} | |||
</span> | |||
)} | |||
</div> | |||
</div> | |||
</div> | |||
); | |||
} | |||
} | |||
const mapStateToProps = (state, ownProps) => ({ | |||
changedValue: getChangedValue(state, ownProps.setting.definition.key), | |||
loading: isLoading(state, ownProps.setting.definition.key), | |||
validationMessage: getValidationMessage(state, ownProps.setting.definition.key) | |||
}); | |||
export default connect( | |||
mapStateToProps, | |||
{ changeValue, saveValue, resetValue, failValidation, passValidation, cancelChange } | |||
)(Definition); |
@@ -0,0 +1,59 @@ | |||
/* | |||
* 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 shallowCompare from 'react-addons-shallow-compare'; | |||
import { translate } from '../../../helpers/l10n'; | |||
export default class DefinitionChanges extends React.Component { | |||
static propTypes = { | |||
onSave: React.PropTypes.func.isRequired, | |||
onCancel: React.PropTypes.func.isRequired | |||
}; | |||
shouldComponentUpdate (nextProps, nextState) { | |||
return shallowCompare(this, nextProps, nextState); | |||
} | |||
handleSaveClick (e) { | |||
e.preventDefault(); | |||
e.target.blur(); | |||
this.props.onSave(); | |||
} | |||
handleCancelChange (e) { | |||
e.preventDefault(); | |||
e.target.blur(); | |||
this.props.onCancel(); | |||
} | |||
render () { | |||
return ( | |||
<div className="settings-definition-changes"> | |||
<button className="js-save-changes button-success" onClick={e => this.handleSaveClick(e)}> | |||
{translate('save')} | |||
</button> | |||
<button className="js-cancel-changes big-spacer-left button-link" onClick={e => this.handleCancelChange(e)}> | |||
{translate('cancel')} | |||
</button> | |||
</div> | |||
); | |||
} | |||
} |
@@ -0,0 +1,60 @@ | |||
/* | |||
* 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 { getSettingValue, isEmptyValue, getDefaultValue } from '../utils'; | |||
import { translate } from '../../../helpers/l10n'; | |||
export default class DefinitionDefaults extends React.Component { | |||
static propTypes = { | |||
setting: React.PropTypes.object.isRequired, | |||
isDefault: React.PropTypes.bool.isRequired, | |||
onReset: React.PropTypes.func.isRequired | |||
}; | |||
handleReset (e) { | |||
e.preventDefault(); | |||
e.target.blur(); | |||
this.props.onReset(); | |||
} | |||
render () { | |||
const { setting, isDefault } = this.props; | |||
const { definition } = setting; | |||
const isExplicitlySet = !isDefault && !isEmptyValue(definition, getSettingValue(setting)); | |||
return ( | |||
<div> | |||
{isDefault && ( | |||
<div className="spacer-top note" style={{ lineHeight: '24px' }}> | |||
{translate('settings._default')} | |||
</div> | |||
)} | |||
{isExplicitlySet && ( | |||
<div className="spacer-top nowrap"> | |||
<button onClick={e => this.handleReset(e)}>{translate('reset_verb')}</button> | |||
<span className="spacer-left note">{translate('default')}{': '}{getDefaultValue(setting)}</span> | |||
</div> | |||
)} | |||
</div> | |||
); | |||
} | |||
} |
@@ -0,0 +1,45 @@ | |||
/* | |||
* 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 shallowCompare from 'react-addons-shallow-compare'; | |||
import Definition from './Definition'; | |||
export default class DefinitionsList extends React.Component { | |||
static propTypes = { | |||
component: React.PropTypes.object, | |||
settings: React.PropTypes.array.isRequired | |||
}; | |||
shouldComponentUpdate (nextProps, nextState) { | |||
return shallowCompare(this, nextProps, nextState); | |||
} | |||
render () { | |||
return ( | |||
<ul className="settings-definitions-list"> | |||
{this.props.settings.map(setting => ( | |||
<li key={setting.definition.key}> | |||
<Definition component={this.props.component} setting={setting}/> | |||
</li> | |||
))} | |||
</ul> | |||
); | |||
} | |||
} |
@@ -0,0 +1,28 @@ | |||
/* | |||
* 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 { connect } from 'react-redux'; | |||
import GlobalMessages from '../../../components/controls/GlobalMessages'; | |||
import { getGlobalMessages } from '../store/rootReducer'; | |||
const mapStateToProps = state => ({ | |||
messages: getGlobalMessages(state) | |||
}); | |||
export default connect(mapStateToProps)(GlobalMessages); |
@@ -0,0 +1,44 @@ | |||
/* | |||
* 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 { translate } from '../../../helpers/l10n'; | |||
export default class PageHeader extends React.Component { | |||
static propTypes = { | |||
component: React.PropTypes.object | |||
}; | |||
render () { | |||
const title = this.props.component != null ? | |||
translate('project_settings.page') : | |||
translate('settings.page'); | |||
const description = this.props.component != null ? | |||
translate('project_settings.page.description') : | |||
translate('settings.page.description'); | |||
return ( | |||
<header className="page-header"> | |||
<h1 className="page-title">{title}</h1> | |||
<div className="page-description">{description}</div> | |||
</header> | |||
); | |||
} | |||
} |
@@ -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 shallowCompare from 'react-addons-shallow-compare'; | |||
import groupBy from 'lodash/groupBy'; | |||
import sortBy from 'lodash/sortBy'; | |||
import DefinitionsList from './DefinitionsList'; | |||
import { getSubCategoryName, getSubCategoryDescription } from '../utils'; | |||
export default class SubCategoryDefinitionsList extends React.Component { | |||
static propTypes = { | |||
component: React.PropTypes.object, | |||
settings: React.PropTypes.array.isRequired | |||
}; | |||
shouldComponentUpdate (nextProps, nextState) { | |||
return shallowCompare(this, nextProps, nextState); | |||
} | |||
render () { | |||
const bySubCategory = groupBy(this.props.settings, setting => setting.definition.subCategory); | |||
const subCategories = Object.keys(bySubCategory).map(key => ({ | |||
key, | |||
name: getSubCategoryName(bySubCategory[key][0].definition.category, key), | |||
description: getSubCategoryDescription(bySubCategory[key][0].definition.category, key) | |||
})); | |||
const sortedSubCategories = sortBy(subCategories, subCategory => subCategory.name.toLowerCase()); | |||
return ( | |||
<ul className="settings-sub-categories-list"> | |||
{sortedSubCategories.map(subCategory => ( | |||
<li key={subCategory.key}> | |||
<h2 className="settings-sub-category-name">{subCategory.name}</h2> | |||
{subCategory.description != null && ( | |||
<div className="settings-sub-category-description markdown"> | |||
{subCategory.description} | |||
</div> | |||
)} | |||
<DefinitionsList settings={bySubCategory[subCategory.key]} component={this.props.component}/> | |||
</li> | |||
))} | |||
</ul> | |||
); | |||
} | |||
} |
@@ -0,0 +1,51 @@ | |||
/* | |||
* 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 shallowCompare from 'react-addons-shallow-compare'; | |||
import PropertySetInput from './PropertySetInput'; | |||
import MultiValueInput from './MultiValueInput'; | |||
import PrimitiveInput from './PrimitiveInput'; | |||
import { TYPE_PROPERTY_SET } from '../../constants'; | |||
export default class Input extends React.Component { | |||
static propTypes = { | |||
setting: React.PropTypes.object.isRequired, | |||
value: React.PropTypes.any, | |||
onChange: React.PropTypes.func.isRequired | |||
}; | |||
shouldComponentUpdate (nextProps, nextState) { | |||
return shallowCompare(this, nextProps, nextState); | |||
} | |||
render () { | |||
const { definition } = this.props.setting; | |||
if (definition.multiValues) { | |||
return <MultiValueInput {...this.props}/>; | |||
} | |||
if (definition.type === TYPE_PROPERTY_SET) { | |||
return <PropertySetInput {...this.props}/>; | |||
} | |||
return <PrimitiveInput {...this.props}/>; | |||
} | |||
} |
@@ -0,0 +1,48 @@ | |||
/* | |||
* 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 Toggle from '../../../../components/controls/Toggle'; | |||
import { defaultInputPropTypes } from '../../propTypes'; | |||
import { translate } from '../../../../helpers/l10n'; | |||
export default class InputForBoolean extends React.Component { | |||
static propTypes = { | |||
...defaultInputPropTypes, | |||
value: React.PropTypes.oneOfType([React.PropTypes.bool, React.PropTypes.string]) | |||
}; | |||
render () { | |||
const hasValue = this.props.value != null; | |||
const displayedValue = hasValue ? this.props.value : false; | |||
return ( | |||
<div className="display-inline-block text-top"> | |||
<Toggle | |||
name={this.props.name} | |||
value={displayedValue} | |||
onChange={this.props.onChange}/> | |||
{!hasValue && ( | |||
<span className="spacer-left note">{translate('settings.not_set')}</span> | |||
)} | |||
</div> | |||
); | |||
} | |||
} |
@@ -0,0 +1,29 @@ | |||
/* | |||
* 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 SimpleInput from './SimpleInput'; | |||
export default class InputForNumber extends React.Component { | |||
render () { | |||
return ( | |||
<SimpleInput {...this.props} className="input-small" type="text"/> | |||
); | |||
} | |||
} |
@@ -0,0 +1,89 @@ | |||
/* | |||
* 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 { translate } from '../../../../helpers/l10n'; | |||
import { defaultInputPropTypes } from '../../propTypes'; | |||
export default class InputForPassword extends React.Component { | |||
static propTypes = defaultInputPropTypes; | |||
state = { | |||
changing: false | |||
}; | |||
handleChangeClick (e) { | |||
e.preventDefault(); | |||
e.target.blur(); | |||
this.setState({ changing: true }); | |||
} | |||
handleCancelChangeClick (e) { | |||
e.preventDefault(); | |||
e.target.blur(); | |||
this.setState({ changing: false }); | |||
} | |||
handleFormSubmit (e) { | |||
e.preventDefault(); | |||
this.props.onChange(this.refs.input.value); | |||
this.setState({ changing: false }); | |||
} | |||
renderInput () { | |||
return ( | |||
<div> | |||
<form onSubmit={e => this.handleFormSubmit(e)}> | |||
<input className="hidden" type="password"/> | |||
<input | |||
ref="input" | |||
name={this.props.name} | |||
className="input-large text-top" | |||
type="password" | |||
autoFocus={true} | |||
autoComplete={false}/> | |||
<button className="spacer-left">{translate('set')}</button> | |||
<a className="spacer-left" href="#" onClick={e => this.handleCancelChangeClick(e)}> | |||
{translate('cancel')} | |||
</a> | |||
</form> | |||
</div> | |||
); | |||
} | |||
render () { | |||
if (this.state.changing) { | |||
return this.renderInput(); | |||
} | |||
const hasValue = !!this.props.value; | |||
return ( | |||
<div> | |||
{hasValue && ( | |||
<i className="big-spacer-right icon-lock icon-gray"/> | |||
)} | |||
<button onClick={e => this.handleChangeClick(e)}> | |||
{hasValue ? translate('change_verb') : translate('set')} | |||
</button> | |||
</div> | |||
); | |||
} | |||
} |
@@ -0,0 +1,50 @@ | |||
/* | |||
* 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 { defaultInputPropTypes } from '../../propTypes'; | |||
export default class InputForSingleSelectList extends React.Component { | |||
static propTypes = { | |||
...defaultInputPropTypes, | |||
options: React.PropTypes.arrayOf(React.PropTypes.string).isRequired | |||
}; | |||
handleInputChange (option) { | |||
this.props.onChange(option.value); | |||
} | |||
render () { | |||
const options = this.props.options.map(option => ({ | |||
label: option, | |||
value: option | |||
})); | |||
return ( | |||
<Select | |||
name={this.props.name} | |||
className="input-large" | |||
options={options} | |||
clearable={false} | |||
value={this.props.value} | |||
onChange={option => this.handleInputChange(option)}/> | |||
); | |||
} | |||
} |
@@ -0,0 +1,29 @@ | |||
/* | |||
* 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 SimpleInput from './SimpleInput'; | |||
export default class InputForString extends React.Component { | |||
render () { | |||
return ( | |||
<SimpleInput {...this.props} className="input-large" type="text"/> | |||
); | |||
} | |||
} |
@@ -0,0 +1,40 @@ | |||
/* | |||
* 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 { defaultInputPropTypes } from '../../propTypes'; | |||
export default class InputForText extends React.Component { | |||
static propTypes = defaultInputPropTypes; | |||
handleInputChange (e) { | |||
this.props.onChange(e.target.value); | |||
} | |||
render () { | |||
return ( | |||
<textarea | |||
name={this.props.name} | |||
className="input-super-large text-top" | |||
rows="5" | |||
value={this.props.value} | |||
onChange={e => this.handleInputChange(e)}/> | |||
); | |||
} | |||
} |
@@ -0,0 +1,90 @@ | |||
/* | |||
* 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 PrimitiveInput from './PrimitiveInput'; | |||
import { getEmptyValue } from '../../utils'; | |||
export default class MultiValueInput extends React.Component { | |||
static propTypes = { | |||
setting: React.PropTypes.object.isRequired, | |||
value: React.PropTypes.array, | |||
onChange: React.PropTypes.func.isRequired | |||
}; | |||
ensureValue () { | |||
return this.props.value || []; | |||
} | |||
handleSingleInputChange (index, value) { | |||
const newValue = [...this.ensureValue()]; | |||
newValue.splice(index, 1, value); | |||
this.props.onChange(newValue); | |||
} | |||
handleDeleteValue (e, index) { | |||
e.preventDefault(); | |||
e.target.blur(); | |||
const newValue = [...this.ensureValue()]; | |||
newValue.splice(index, 1); | |||
this.props.onChange(newValue); | |||
} | |||
prepareSetting () { | |||
const { setting } = this.props; | |||
const newDefinition = { ...setting.definition, multiValues: false }; | |||
return { | |||
...setting, | |||
definition: newDefinition, | |||
values: undefined | |||
}; | |||
} | |||
renderInput (value, index, isLast) { | |||
return ( | |||
<li key={index} className="spacer-bottom"> | |||
<PrimitiveInput | |||
setting={this.prepareSetting()} | |||
value={value} | |||
onChange={this.handleSingleInputChange.bind(this, index)}/> | |||
{!isLast && ( | |||
<div className="display-inline-block spacer-left"> | |||
<button className="js-remove-value button-clean" onClick={e => this.handleDeleteValue(e, index)}> | |||
<i className="icon-delete"/> | |||
</button> | |||
</div> | |||
)} | |||
</li> | |||
); | |||
} | |||
render () { | |||
const displayedValue = [...this.ensureValue(), ...getEmptyValue(this.props.setting.definition)]; | |||
return ( | |||
<div> | |||
<ul> | |||
{displayedValue.map((value, index) => this.renderInput(value, index, index === displayedValue.length - 1))} | |||
</ul> | |||
</div> | |||
); | |||
} | |||
} |
@@ -0,0 +1,75 @@ | |||
/* | |||
* 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 InputForString from './InputForString'; | |||
import InputForText from './InputForText'; | |||
import InputForPassword from './InputForPassword'; | |||
import InputForBoolean from './InputForBoolean'; | |||
import InputForNumber from './InputForNumber'; | |||
import InputForSingleSelectList from './InputForSingleSelectList'; | |||
import { getUniqueName, isDefaultOrInherited } from '../../utils'; | |||
import * as types from '../../constants'; | |||
const typeMapping = { | |||
[types.TYPE_STRING]: InputForString, | |||
[types.TYPE_TEXT]: InputForText, | |||
[types.TYPE_PASSWORD]: InputForPassword, | |||
[types.TYPE_BOOLEAN]: InputForBoolean, | |||
[types.TYPE_INTEGER]: InputForNumber, | |||
[types.TYPE_LONG]: InputForNumber, | |||
[types.TYPE_FLOAT]: InputForNumber | |||
}; | |||
export default class PrimitiveInput extends React.Component { | |||
static propTypes = { | |||
setting: React.PropTypes.object.isRequired, | |||
value: React.PropTypes.any, | |||
onChange: React.PropTypes.func.isRequired | |||
}; | |||
render () { | |||
const { setting, value, onChange, ...other } = this.props; | |||
const { definition } = setting; | |||
const name = getUniqueName(definition); | |||
if (definition.type === types.TYPE_SINGLE_SELECT_LIST) { | |||
return ( | |||
<InputForSingleSelectList | |||
name={name} | |||
value={value} | |||
isDefault={isDefaultOrInherited(setting)} | |||
options={definition.options} | |||
onChange={onChange} | |||
{...other}/> | |||
); | |||
} | |||
const InputComponent = typeMapping[definition.type] || InputForString; | |||
return ( | |||
<InputComponent | |||
name={name} | |||
value={value} | |||
isDefault={isDefaultOrInherited(setting)} | |||
onChange={onChange} | |||
{...other}/> | |||
); | |||
} | |||
} |
@@ -0,0 +1,110 @@ | |||
/* | |||
* 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 PrimitiveInput from './PrimitiveInput'; | |||
import { getEmptyValue, getUniqueName } from '../../utils'; | |||
export default class PropertySetInput extends React.Component { | |||
static propTypes = { | |||
setting: React.PropTypes.object.isRequired, | |||
value: React.PropTypes.array, | |||
onChange: React.PropTypes.func.isRequired | |||
}; | |||
ensureValue () { | |||
return this.props.value || []; | |||
} | |||
getFieldName (field) { | |||
return getUniqueName(this.props.setting.definition, field.key); | |||
} | |||
handleDeleteValue (e, index) { | |||
e.preventDefault(); | |||
e.target.blur(); | |||
const newValue = [...this.ensureValue()]; | |||
newValue.splice(index, 1); | |||
this.props.onChange(newValue); | |||
} | |||
handleInputChange (index, fieldKey, value) { | |||
const emptyValue = getEmptyValue(this.props.setting.definition)[0]; | |||
const newValue = [...this.ensureValue()]; | |||
const newFields = { ...emptyValue, ...newValue[index], [fieldKey]: value }; | |||
newValue.splice(index, 1, newFields); | |||
return this.props.onChange(newValue); | |||
} | |||
renderFields (fieldValues, index, isLast) { | |||
const { setting } = this.props; | |||
return ( | |||
<tr key={index}> | |||
{setting.definition.fields.map(field => ( | |||
<td key={field.key}> | |||
<PrimitiveInput | |||
name={this.getFieldName(field)} | |||
setting={{ definition: field, value: fieldValues[field.key] }} | |||
value={fieldValues[field.key]} | |||
onChange={this.handleInputChange.bind(this, index, field.key)}/> | |||
</td> | |||
))} | |||
<td className="thin nowrap"> | |||
{!isLast && ( | |||
<button className="js-remove-value button-link" onClick={e => this.handleDeleteValue(e, index)}> | |||
<i className="icon-delete"/> | |||
</button> | |||
)} | |||
</td> | |||
</tr> | |||
); | |||
} | |||
render () { | |||
const { setting } = this.props; | |||
const displayedValue = [...this.ensureValue(), ...getEmptyValue(this.props.setting.definition)]; | |||
return ( | |||
<div> | |||
<table className="data zebra-hover no-outer-padding" style={{ width: 'auto', minWidth: 480, marginTop: -12 }}> | |||
<thead> | |||
<tr> | |||
{setting.definition.fields.map(field => ( | |||
<th key={field.key}> | |||
{field.name} | |||
{field.description != null && ( | |||
<span className="spacer-top small">{field.description}</span> | |||
)} | |||
</th> | |||
))} | |||
<th> </th> | |||
</tr> | |||
</thead> | |||
<tbody> | |||
{displayedValue.map((fieldValues, index) => | |||
this.renderFields(fieldValues, index, index === displayedValue.length - 1))} | |||
</tbody> | |||
</table> | |||
</div> | |||
); | |||
} | |||
} |
@@ -0,0 +1,45 @@ | |||
/* | |||
* 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 { defaultInputPropTypes } from '../../propTypes'; | |||
export default class SimpleInput extends React.Component { | |||
static propTypes = { | |||
...defaultInputPropTypes, | |||
value: React.PropTypes.oneOfType([React.PropTypes.string, React.PropTypes.number]), | |||
type: React.PropTypes.string.isRequired, | |||
className: React.PropTypes.string.isRequired | |||
}; | |||
handleInputChange (e) { | |||
this.props.onChange(e.target.value); | |||
} | |||
render () { | |||
return ( | |||
<input | |||
name={this.props.name} | |||
className={this.props.className + ' text-top'} | |||
type={this.props.type} | |||
value={this.props.value} | |||
onChange={e => this.handleInputChange(e)}/> | |||
); | |||
} | |||
} |
@@ -0,0 +1,60 @@ | |||
/* | |||
* 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 { expect } from 'chai'; | |||
import { shallow } from 'enzyme'; | |||
import sinon from 'sinon'; | |||
import Input from '../Input'; | |||
import PrimitiveInput from '../PrimitiveInput'; | |||
import MultiValueInput from '../MultiValueInput'; | |||
import PropertySetInput from '../PropertySetInput'; | |||
import { TYPE_STRING, TYPE_PROPERTY_SET } from '../../../constants'; | |||
describe('Settings :: Inputs :: Input', () => { | |||
it('should render PrimitiveInput', () => { | |||
const setting = { definition: { key: 'example', type: TYPE_STRING } }; | |||
const onChange = sinon.spy(); | |||
const input = shallow(<Input setting={setting} value="foo" onChange={onChange}/>).find(PrimitiveInput); | |||
expect(input).to.have.length(1); | |||
expect(input.prop('setting')).to.equal(setting); | |||
expect(input.prop('value')).to.equal('foo'); | |||
expect(input.prop('onChange')).to.equal(onChange); | |||
}); | |||
it('should render MultiValueInput', () => { | |||
const setting = { definition: { key: 'example', type: TYPE_STRING, multiValues: true } }; | |||
const onChange = sinon.spy(); | |||
const input = shallow(<Input setting={setting} value="foo" onChange={onChange}/>).find(MultiValueInput); | |||
expect(input).to.have.length(1); | |||
expect(input.prop('setting')).to.equal(setting); | |||
expect(input.prop('value')).to.equal('foo'); | |||
expect(input.prop('onChange')).to.equal(onChange); | |||
}); | |||
it('should render PropertySetInput', () => { | |||
const setting = { definition: { key: 'example', type: TYPE_PROPERTY_SET, fields: [] } }; | |||
const onChange = sinon.spy(); | |||
const input = shallow(<Input setting={setting} value="foo" onChange={onChange}/>).find(PropertySetInput); | |||
expect(input).to.have.length(1); | |||
expect(input.prop('setting')).to.equal(setting); | |||
expect(input.prop('value')).to.equal('foo'); | |||
expect(input.prop('onChange')).to.equal(onChange); | |||
}); | |||
}); |
@@ -0,0 +1,77 @@ | |||
/* | |||
* 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 { expect } from 'chai'; | |||
import { shallow } from 'enzyme'; | |||
import sinon from 'sinon'; | |||
import InputForBoolean from '../InputForBoolean'; | |||
import Toggle from '../../../../../components/controls/Toggle'; | |||
describe('Settings :: Inputs :: InputForBoolean', () => { | |||
it('should render Toggle', () => { | |||
const onChange = sinon.spy(); | |||
const toggle = shallow( | |||
<InputForBoolean | |||
name="foo" | |||
value={true} | |||
isDefault={false} | |||
onChange={onChange}/> | |||
).find(Toggle); | |||
expect(toggle).to.have.length(1); | |||
expect(toggle.prop('name')).to.equal('foo'); | |||
expect(toggle.prop('value')).to.equal(true); | |||
expect(toggle.prop('onChange')).to.be.a('function'); | |||
}); | |||
it('should render Toggle without value', () => { | |||
const onChange = sinon.spy(); | |||
const input = shallow( | |||
<InputForBoolean | |||
name="foo" | |||
isDefault={false} | |||
onChange={onChange}/> | |||
); | |||
const toggle = input.find(Toggle); | |||
expect(toggle).to.have.length(1); | |||
expect(toggle.prop('name')).to.equal('foo'); | |||
expect(toggle.prop('value')).to.equal(false); | |||
expect(toggle.prop('onChange')).to.be.a('function'); | |||
expect(input.find('.note')).to.have.length(1); | |||
}); | |||
it('should call onChange', () => { | |||
const onChange = sinon.spy(); | |||
const input = shallow( | |||
<InputForBoolean | |||
name="foo" | |||
value={true} | |||
isDefault={false} | |||
onChange={onChange}/> | |||
); | |||
const toggle = input.find(Toggle); | |||
expect(toggle).to.have.length(1); | |||
expect(toggle.prop('onChange')).to.be.a('function'); | |||
toggle.prop('onChange')(false); | |||
expect(onChange.called).to.equal(true); | |||
expect(onChange.lastCall.args).to.deep.equal([false]); | |||
}); | |||
}); |
@@ -0,0 +1,43 @@ | |||
/* | |||
* 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 { expect } from 'chai'; | |||
import { shallow } from 'enzyme'; | |||
import sinon from 'sinon'; | |||
import InputForNumber from '../InputForNumber'; | |||
import SimpleInput from '../SimpleInput'; | |||
describe('Settings :: Inputs :: InputForNumber', () => { | |||
it('should render SimpleInput', () => { | |||
const onChange = sinon.spy(); | |||
const simpleInput = shallow( | |||
<InputForNumber | |||
name="foo" | |||
value={17} | |||
isDefault={false} | |||
onChange={onChange}/> | |||
).find(SimpleInput); | |||
expect(simpleInput).to.have.length(1); | |||
expect(simpleInput.prop('name')).to.equal('foo'); | |||
expect(simpleInput.prop('value')).to.equal(17); | |||
expect(simpleInput.prop('type')).to.equal('text'); | |||
expect(simpleInput.prop('onChange')).to.be.a('function'); | |||
}); | |||
}); |
@@ -0,0 +1,97 @@ | |||
/* | |||
* 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 { expect } from 'chai'; | |||
import { shallow, mount } from 'enzyme'; | |||
import sinon from 'sinon'; | |||
import InputForPassword from '../InputForPassword'; | |||
import { click, submit } from '../../../../../../../../tests/utils'; | |||
describe('Settings :: Inputs :: InputForPassword', () => { | |||
it('should render lock icon, but no form', () => { | |||
const onChange = sinon.spy(); | |||
const input = shallow( | |||
<InputForPassword | |||
name="foo" | |||
value="bar" | |||
isDefault={false} | |||
onChange={onChange}/> | |||
); | |||
expect(input.find('.icon-lock')).to.have.length(1); | |||
expect(input.find('form')).to.have.length(0); | |||
}); | |||
it('should open form', () => { | |||
const onChange = sinon.spy(); | |||
const input = shallow( | |||
<InputForPassword | |||
name="foo" | |||
value="bar" | |||
isDefault={false} | |||
onChange={onChange}/> | |||
); | |||
const button = input.find('button'); | |||
expect(button).to.have.length(1); | |||
click(button); | |||
expect(input.find('form')).to.have.length(1); | |||
}); | |||
it('should close form', () => { | |||
const onChange = sinon.spy(); | |||
const input = shallow( | |||
<InputForPassword | |||
name="foo" | |||
value="bar" | |||
isDefault={false} | |||
onChange={onChange}/> | |||
); | |||
const button = input.find('button'); | |||
expect(button).to.have.length(1); | |||
click(button); | |||
expect(input.find('form')).to.have.length(1); | |||
click(input.find('form').find('a')); | |||
expect(input.find('form')).to.have.length(0); | |||
}); | |||
it('should set value', () => { | |||
const onChange = sinon.stub().returns(Promise.resolve()); | |||
const input = mount( | |||
<InputForPassword | |||
name="foo" | |||
value="bar" | |||
isDefault={false} | |||
onChange={onChange}/> | |||
); | |||
const button = input.find('button'); | |||
expect(button).to.have.length(1); | |||
click(button); | |||
const form = input.find('form'); | |||
expect(form).to.have.length(1); | |||
input.ref('input').value = 'secret'; | |||
submit(form); | |||
expect(onChange.called).to.equal(true); | |||
}); | |||
}); |
@@ -0,0 +1,66 @@ | |||
/* | |||
* 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 { expect } from 'chai'; | |||
import { shallow } from 'enzyme'; | |||
import sinon from 'sinon'; | |||
import Select from 'react-select'; | |||
import InputForSingleSelectList from '../InputForSingleSelectList'; | |||
describe('Settings :: Inputs :: InputForSingleSelectList', () => { | |||
it('should render Select', () => { | |||
const onChange = sinon.spy(); | |||
const select = shallow( | |||
<InputForSingleSelectList | |||
name="foo" | |||
value="bar" | |||
options={['foo', 'bar', 'baz']} | |||
isDefault={false} | |||
onChange={onChange}/> | |||
).find(Select); | |||
expect(select).to.have.length(1); | |||
expect(select.prop('name')).to.equal('foo'); | |||
expect(select.prop('value')).to.equal('bar'); | |||
expect(select.prop('options')).to.deep.equal([ | |||
{ value: 'foo', label: 'foo' }, | |||
{ value: 'bar', label: 'bar' }, | |||
{ value: 'baz', label: 'baz' } | |||
]); | |||
expect(select.prop('onChange')).to.be.a('function'); | |||
}); | |||
it('should call onChange', () => { | |||
const onChange = sinon.spy(); | |||
const select = shallow( | |||
<InputForSingleSelectList | |||
name="foo" | |||
value="bar" | |||
options={['foo', 'bar', 'baz']} | |||
isDefault={false} | |||
onChange={onChange}/> | |||
).find(Select); | |||
expect(select).to.have.length(1); | |||
expect(select.prop('onChange')).to.be.a('function'); | |||
select.prop('onChange')({ value: 'baz', label: 'baz' }); | |||
expect(onChange.called).to.equal(true); | |||
expect(onChange.lastCall.args).to.deep.equal(['baz']); | |||
}); | |||
}); |
@@ -0,0 +1,43 @@ | |||
/* | |||
* 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 { expect } from 'chai'; | |||
import { shallow } from 'enzyme'; | |||
import sinon from 'sinon'; | |||
import InputForString from '../InputForString'; | |||
import SimpleInput from '../SimpleInput'; | |||
describe('Settings :: Inputs :: InputForString', () => { | |||
it('should render SimpleInput', () => { | |||
const onChange = sinon.spy(); | |||
const simpleInput = shallow( | |||
<InputForString | |||
name="foo" | |||
value="bar" | |||
isDefault={false} | |||
onChange={onChange}/> | |||
).find(SimpleInput); | |||
expect(simpleInput).to.have.length(1); | |||
expect(simpleInput.prop('name')).to.equal('foo'); | |||
expect(simpleInput.prop('value')).to.equal('bar'); | |||
expect(simpleInput.prop('type')).to.equal('text'); | |||
expect(simpleInput.prop('onChange')).to.be.a('function'); | |||
}); | |||
}); |
@@ -0,0 +1,60 @@ | |||
/* | |||
* 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 { expect } from 'chai'; | |||
import { shallow } from 'enzyme'; | |||
import sinon from 'sinon'; | |||
import InputForText from '../InputForText'; | |||
import { change } from '../../../../../../../../tests/utils'; | |||
describe('Settings :: Inputs :: InputForText', () => { | |||
it('should render textarea', () => { | |||
const onChange = sinon.spy(); | |||
const textarea = shallow( | |||
<InputForText | |||
name="foo" | |||
value="bar" | |||
isDefault={false} | |||
onChange={onChange}/> | |||
).find('textarea'); | |||
expect(textarea).to.have.length(1); | |||
expect(textarea.prop('name')).to.equal('foo'); | |||
expect(textarea.prop('value')).to.equal('bar'); | |||
expect(textarea.prop('onChange')).to.be.a('function'); | |||
}); | |||
it('should call onChange', () => { | |||
const onChange = sinon.spy(); | |||
const textarea = shallow( | |||
<InputForText | |||
name="foo" | |||
value="bar" | |||
isDefault={false} | |||
onChange={onChange}/> | |||
).find('textarea'); | |||
expect(textarea).to.have.length(1); | |||
expect(textarea.prop('onChange')).to.be.a('function'); | |||
change(textarea, 'qux'); | |||
expect(onChange.called).to.equal(true); | |||
expect(onChange.lastCall.args).to.deep.equal(['qux']); | |||
}); | |||
}); |
@@ -0,0 +1,103 @@ | |||
/* | |||
* 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 { expect } from 'chai'; | |||
import { shallow, mount } from 'enzyme'; | |||
import sinon from 'sinon'; | |||
import MultiValueInput from '../MultiValueInput'; | |||
import InputForString from '../InputForString'; | |||
import { click, change } from '../../../../../../../../tests/utils'; | |||
const definition = { multiValues: true }; | |||
const assertValues = (inputs, values) => { | |||
values.forEach((value, index) => { | |||
const input = inputs.at(index); | |||
expect(input.prop('value')).to.equal(value); | |||
}); | |||
}; | |||
describe('Settings :: Inputs :: MultiValueInput', () => { | |||
it('should render one value', () => { | |||
const multiValueInput = mount( | |||
<MultiValueInput | |||
setting={{ definition }} | |||
value={['foo']} | |||
onChange={sinon.stub()}/> | |||
); | |||
const stringInputs = multiValueInput.find(InputForString); | |||
expect(stringInputs).to.have.length(1 + 1); | |||
assertValues(stringInputs, ['foo', '']); | |||
}); | |||
it('should render several values', () => { | |||
const multiValueInput = mount( | |||
<MultiValueInput | |||
setting={{ definition }} | |||
value={['foo', 'bar', 'baz']} | |||
onChange={sinon.stub()}/> | |||
); | |||
const stringInputs = multiValueInput.find(InputForString); | |||
expect(stringInputs).to.have.length(3 + 1); | |||
assertValues(stringInputs, ['foo', 'bar', 'baz', '']); | |||
}); | |||
it('should remove value', () => { | |||
const onChange = sinon.spy(); | |||
const multiValueInput = mount( | |||
<MultiValueInput | |||
setting={{ definition }} | |||
value={['foo', 'bar', 'baz']} | |||
onChange={onChange}/> | |||
); | |||
click(multiValueInput.find('.js-remove-value').at(1)); | |||
expect(onChange.called).to.equal(true); | |||
expect(onChange.lastCall.args).to.deep.equal([['foo', 'baz']]); | |||
}); | |||
it('should change existing value', () => { | |||
const onChange = sinon.spy(); | |||
const multiValueInput = mount( | |||
<MultiValueInput | |||
setting={{ definition }} | |||
value={['foo', 'bar', 'baz']} | |||
onChange={onChange}/> | |||
); | |||
change(multiValueInput.find(InputForString).at(1).find('input'), 'qux'); | |||
expect(onChange.called).to.equal(true); | |||
expect(onChange.lastCall.args).to.deep.equal([['foo', 'qux', 'baz']]); | |||
}); | |||
it('should add new value', () => { | |||
const onChange = sinon.spy(); | |||
const multiValueInput = mount( | |||
<MultiValueInput | |||
setting={{ definition }} | |||
value={['foo']} | |||
onChange={onChange}/> | |||
); | |||
change(multiValueInput.find(InputForString).at(1).find('input'), 'bar'); | |||
expect(onChange.called).to.equal(true); | |||
expect(onChange.lastCall.args).to.deep.equal([['foo', 'bar']]); | |||
}); | |||
}); |
@@ -0,0 +1,66 @@ | |||
/* | |||
* 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 { expect } from 'chai'; | |||
import { shallow } from 'enzyme'; | |||
import sinon from 'sinon'; | |||
import SimpleInput from '../SimpleInput'; | |||
import { change } from '../../../../../../../../tests/utils'; | |||
describe('Settings :: Inputs :: SimpleInput', () => { | |||
it('should render input', () => { | |||
const onChange = sinon.spy(); | |||
const input = shallow( | |||
<SimpleInput | |||
type="text" | |||
className="input-large" | |||
name="foo" | |||
value="bar" | |||
isDefault={false} | |||
onChange={onChange}/> | |||
).find('input'); | |||
expect(input).to.have.length(1); | |||
expect(input.prop('type')).to.equal('text'); | |||
expect(input.prop('className')).to.include('input-large'); | |||
expect(input.prop('name')).to.equal('foo'); | |||
expect(input.prop('value')).to.equal('bar'); | |||
expect(input.prop('onChange')).to.be.a('function'); | |||
}); | |||
it('should call onChange', () => { | |||
const onChange = sinon.spy(); | |||
const input = shallow( | |||
<SimpleInput | |||
type="text" | |||
className="input-large" | |||
name="foo" | |||
value="bar" | |||
isDefault={false} | |||
onChange={onChange}/> | |||
).find('input'); | |||
expect(input).to.have.length(1); | |||
expect(input.prop('onChange')).to.be.a('function'); | |||
change(input, 'qux'); | |||
expect(onChange.called).to.equal(true); | |||
expect(onChange.lastCall.args).to.deep.equal(['qux']); | |||
}); | |||
}); |
@@ -0,0 +1,28 @@ | |||
/* | |||
* 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. | |||
*/ | |||
export const TYPE_STRING = 'STRING'; | |||
export const TYPE_TEXT = 'TEXT'; | |||
export const TYPE_PASSWORD = 'PASSWORD'; | |||
export const TYPE_BOOLEAN = 'BOOLEAN'; | |||
export const TYPE_FLOAT = 'FLOAT'; | |||
export const TYPE_INTEGER = 'INTEGER'; | |||
export const TYPE_LONG = 'LONG'; | |||
export const TYPE_SINGLE_SELECT_LIST = 'SINGLE_SELECT_LIST'; | |||
export const TYPE_PROPERTY_SET = 'PROPERTY_SET'; |
@@ -0,0 +1,27 @@ | |||
/* | |||
* 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 { PropTypes } from 'react'; | |||
export const defaultInputPropTypes = { | |||
name: PropTypes.string.isRequired, | |||
value: PropTypes.any, | |||
isDefault: PropTypes.bool.isRequired, | |||
onChange: PropTypes.func.isRequired | |||
}; |
@@ -0,0 +1,85 @@ | |||
/* | |||
* 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 { getDefinitions, getValues, setSettingValue, resetSettingValue } from '../../../api/settings'; | |||
import { receiveValues } from './values/actions'; | |||
import { receiveDefinitions } from './definitions/actions'; | |||
import { startLoading, stopLoading } from './settingsPage/loading/actions'; | |||
import { parseError } from '../../code/utils'; | |||
import { addGlobalErrorMessage, closeAllGlobalMessages } from '../../../components/store/globalMessages'; | |||
import { passValidation, failValidation } from './settingsPage/validationMessages/actions'; | |||
import { cancelChange } from './settingsPage/changedValues/actions'; | |||
import { getDefinition, getChangedValue } from './rootReducer'; | |||
export const fetchSettings = componentKey => dispatch => { | |||
return getDefinitions(componentKey) | |||
.then(definitions => { | |||
dispatch(receiveDefinitions(definitions)); | |||
const keys = definitions.map(definition => definition.key).join(); | |||
return getValues(keys, componentKey); | |||
}) | |||
.then(settings => { | |||
dispatch(receiveValues(settings)); | |||
dispatch(closeAllGlobalMessages()); | |||
}) | |||
.catch(e => parseError(e).then(message => dispatch(addGlobalErrorMessage(message)))); | |||
}; | |||
export const saveValue = (key, componentKey) => (dispatch, getState) => { | |||
dispatch(startLoading(key)); | |||
const state = getState(); | |||
const definition = getDefinition(state, key); | |||
const value = getChangedValue(state, key); | |||
return setSettingValue(definition, value, componentKey) | |||
.then(() => getValues(key, componentKey)) | |||
.then(values => { | |||
dispatch(receiveValues(values)); | |||
dispatch(cancelChange(key)); | |||
dispatch(passValidation(key)); | |||
dispatch(stopLoading(key)); | |||
}) | |||
.catch(e => { | |||
dispatch(stopLoading(key)); | |||
parseError(e).then(message => dispatch(failValidation(key, message))); | |||
return Promise.reject(); | |||
}); | |||
}; | |||
export const resetValue = (key, componentKey) => dispatch => { | |||
dispatch(startLoading(key)); | |||
return resetSettingValue(key, componentKey) | |||
.then(() => getValues(key, componentKey)) | |||
.then(values => { | |||
if (values.length > 0) { | |||
dispatch(receiveValues(values)); | |||
} else { | |||
dispatch(receiveValues([{ key }])); | |||
} | |||
dispatch(passValidation(key)); | |||
dispatch(stopLoading(key)); | |||
}) | |||
.catch(e => { | |||
dispatch(stopLoading(key)); | |||
parseError(e).then(message => dispatch(failValidation(key, message))); | |||
return Promise.reject(); | |||
}); | |||
}; |
@@ -0,0 +1,30 @@ | |||
/* | |||
* 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. | |||
*/ | |||
export const RECEIVE_DEFINITIONS = 'RECEIVE_DEFINITIONS'; | |||
/** | |||
* Receive definitions action creator | |||
* @param {Array} definitions | |||
* @returns {Object} | |||
*/ | |||
export const receiveDefinitions = definitions => ({ | |||
type: RECEIVE_DEFINITIONS, | |||
definitions | |||
}); |
@@ -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 keyBy from 'lodash/keyBy'; | |||
import sortBy from 'lodash/sortBy'; | |||
import uniqBy from 'lodash/uniqBy'; | |||
import { RECEIVE_DEFINITIONS } from './actions'; | |||
import { DEFAULT_CATEGORY, getCategoryName } from '../../utils'; | |||
const reducer = (state = {}, action = {}) => { | |||
if (action.type === RECEIVE_DEFINITIONS) { | |||
const definitionsByKey = keyBy(action.definitions, 'key'); | |||
return { ...state, ...definitionsByKey }; | |||
} | |||
return state; | |||
}; | |||
export default reducer; | |||
export const getDefinition = (state, key) => state[key]; | |||
export const getAllDefinitions = state => Object.values(state); | |||
export const getDefinitionsForCategory = (state, category) => | |||
getAllDefinitions(state).filter(definition => definition.category.toLowerCase() === category.toLowerCase()); | |||
export const getAllCategories = state => uniqBy( | |||
getAllDefinitions(state).map(definition => definition.category), | |||
category => category.toLowerCase()); | |||
export const getDefaultCategory = state => { | |||
const categories = getAllCategories(state); | |||
if (categories.includes(DEFAULT_CATEGORY)) { | |||
return DEFAULT_CATEGORY; | |||
} else { | |||
const sortedCategories = sortBy(categories, category => getCategoryName(category).toLowerCase()); | |||
return sortedCategories[0]; | |||
} | |||
}; |
@@ -0,0 +1,55 @@ | |||
/* | |||
* 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 { combineReducers } from 'redux'; | |||
import definitions, * as fromDefinitions from './definitions/reducer'; | |||
import values, * as fromValues from './values/reducer'; | |||
import settingsPage, * as fromSettingsPage from './settingsPage/reducer'; | |||
import globalMessages, * as fromGlobalMessages from '../../../components/store/globalMessages'; | |||
const rootReducer = combineReducers({ | |||
definitions, | |||
values, | |||
settingsPage, | |||
globalMessages | |||
}); | |||
export default rootReducer; | |||
export const getDefinition = (state, key) => fromDefinitions.getDefinition(state.definitions, key); | |||
export const getAllCategories = state => fromDefinitions.getAllCategories(state.definitions); | |||
export const getDefaultCategory = state => fromDefinitions.getDefaultCategory(state.definitions); | |||
export const getValue = (state, key) => fromValues.getValue(state.values, key); | |||
export const getSettingsForCategory = (state, category) => | |||
fromDefinitions.getDefinitionsForCategory(state.definitions, category).map(definition => ({ | |||
...getValue(state, definition.key), | |||
definition | |||
})); | |||
export const getChangedValue = (state, key) => fromSettingsPage.getChangedValue(state.settingsPage, key); | |||
export const isLoading = (state, key) => fromSettingsPage.isLoading(state.settingsPage, key); | |||
export const getValidationMessage = (state, key) => fromSettingsPage.getValidationMessage(state.settingsPage, key); | |||
export const getGlobalMessages = state => fromGlobalMessages.getGlobalMessages(state.globalMessages); |
@@ -0,0 +1,33 @@ | |||
/* | |||
* 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. | |||
*/ | |||
export const CHANGE_VALUE = 'settingsPage/CHANGE_VALUE'; | |||
export const changeValue = (key, value) => ({ | |||
type: CHANGE_VALUE, | |||
key, | |||
value | |||
}); | |||
export const CANCEL_CHANGE = 'settingsPage/CANCEL_CHANGE'; | |||
export const cancelChange = key => ({ | |||
type: CANCEL_CHANGE, | |||
key | |||
}); |
@@ -0,0 +1,37 @@ | |||
/* | |||
* 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 omit from 'lodash/omit'; | |||
import { CHANGE_VALUE, CANCEL_CHANGE } from './actions'; | |||
const reducer = (state = {}, action = {}) => { | |||
if (action.type === CHANGE_VALUE) { | |||
return { ...state, [action.key]: action.value }; | |||
} | |||
if (action.type === CANCEL_CHANGE) { | |||
return omit(state, action.key); | |||
} | |||
return state; | |||
}; | |||
export default reducer; | |||
export const getChangedValue = (state, key) => state[key]; |
@@ -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. | |||
*/ | |||
export const START_LOADING = 'settingsPage/START_LOADING'; | |||
export const startLoading = key => ({ | |||
type: START_LOADING, | |||
key | |||
}); | |||
export const STOP_LOADING = 'settingsPage/STOP_LOADING'; | |||
export const stopLoading = key => ({ | |||
type: STOP_LOADING, | |||
key | |||
}); |
@@ -0,0 +1,36 @@ | |||
/* | |||
* 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 { START_LOADING, STOP_LOADING } from './actions'; | |||
const reducer = (state = {}, action = {}) => { | |||
if (action.type === START_LOADING) { | |||
return { ...state, [action.key]: true }; | |||
} | |||
if (action.type === STOP_LOADING) { | |||
return { ...state, [action.key]: false }; | |||
} | |||
return state; | |||
}; | |||
export default reducer; | |||
export const isLoading = (state, key) => !!state[key]; |
@@ -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 { combineReducers } from 'redux'; | |||
import changedValues, * as fromChangedValues from './changedValues/reducer'; | |||
import validationMessages, * as fromValidationMessages from './validationMessages/reducer'; | |||
import loading, * as fromLoading from './loading/reducer'; | |||
export default combineReducers({ | |||
changedValues, | |||
validationMessages, | |||
loading | |||
}); | |||
export const getChangedValue = (state, key) => | |||
fromChangedValues.getChangedValue(state.changedValues, key); | |||
export const getValidationMessage = (state, key) => | |||
fromValidationMessages.getValidationMessage(state.validationMessages, key); | |||
export const isLoading = (state, key) => | |||
fromLoading.isLoading(state.loading, key); |
@@ -0,0 +1,33 @@ | |||
/* | |||
* 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. | |||
*/ | |||
export const FAIL_VALIDATION = 'settingsPage/FAIL_VALIDATION'; | |||
export const failValidation = (key, message) => ({ | |||
type: FAIL_VALIDATION, | |||
key, | |||
message | |||
}); | |||
export const PASS_VALIDATION = 'settingsPage/PASS_VALIDATION'; | |||
export const passValidation = key => ({ | |||
type: PASS_VALIDATION, | |||
key | |||
}); |
@@ -0,0 +1,36 @@ | |||
/* | |||
* 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 { FAIL_VALIDATION, PASS_VALIDATION } from './actions'; | |||
const reducer = (state = {}, action = {}) => { | |||
if (action.type === FAIL_VALIDATION) { | |||
return { ...state, [action.key]: action.message }; | |||
} | |||
if (action.type === PASS_VALIDATION) { | |||
return { ...state, [action.key]: null }; | |||
} | |||
return state; | |||
}; | |||
export default reducer; | |||
export const getValidationMessage = (state, key) => state[key]; |
@@ -0,0 +1,30 @@ | |||
/* | |||
* 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. | |||
*/ | |||
export const RECEIVE_VALUES = 'RECEIVE_VALUES'; | |||
/** | |||
* Receive settings action creator | |||
* @param {Array} settings | |||
* @returns {Object} | |||
*/ | |||
export const receiveValues = settings => ({ | |||
type: RECEIVE_VALUES, | |||
settings | |||
}); |
@@ -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 keyBy from 'lodash/keyBy'; | |||
import { RECEIVE_VALUES } from './actions'; | |||
const reducer = (state = {}, action = {}) => { | |||
if (action.type === RECEIVE_VALUES) { | |||
const settingsByKey = keyBy(action.settings, 'key'); | |||
return { ...state, ...settingsByKey }; | |||
} | |||
return state; | |||
}; | |||
export default reducer; | |||
export const getValue = (state, key) => state[key]; |
@@ -0,0 +1,157 @@ | |||
.settings-layout { | |||
display: flex; | |||
justify-content: space-between; | |||
align-items: stretch; | |||
margin-bottom: 60px; | |||
} | |||
.settings-main { | |||
position: relative; | |||
z-index: 2; | |||
flex-grow: 1; | |||
padding: 15px 20px; | |||
border: 1px solid #e6e6e6; | |||
box-sizing: border-box; | |||
background-color: #fff; | |||
} | |||
.settings-side { | |||
position: relative; | |||
z-index: 3; | |||
width: 160px; | |||
flex-shrink: 0; | |||
padding: 10px 0; | |||
box-sizing: border-box; | |||
transform: translateX(1px); | |||
} | |||
.settings-menu { | |||
} | |||
.settings-menu > li { | |||
margin-bottom: 4px; | |||
} | |||
.settings-menu > li > a { | |||
display: block; | |||
padding: 10px 10px; | |||
line-height: 1.5; | |||
border-top-left-radius: 3px; | |||
border-bottom-left-radius: 3px; | |||
border: 1px solid #e6e6e6; | |||
border-right: none; | |||
overflow: hidden; | |||
text-overflow: ellipsis; | |||
transition: color 0.3s ease, background-color 0.3s ease; | |||
} | |||
.settings-menu > li > a:hover, | |||
.settings-menu > li > a:focus, | |||
.settings-menu > li > a.active { | |||
background-color: #fff; | |||
} | |||
.settings-menu > li > a.active { | |||
color: #444; | |||
cursor: default; | |||
} | |||
.settings-definitions-list > li + li { | |||
margin-top: 30px; | |||
} | |||
.settings-definition { | |||
display: flex; | |||
align-items: stretch; | |||
} | |||
.settings-definition-changed { | |||
margin: -10px -20px; | |||
padding: 9px 20px; | |||
border-top: 1px solid #faebcc; | |||
border-bottom: 1px solid #faebcc; | |||
background-color: #fcf8e3; | |||
} | |||
.settings-definition-left { | |||
width: 330px; | |||
padding-right: 30px; | |||
box-sizing: border-box; | |||
} | |||
.settings-definition-right { | |||
position: relative; | |||
width: calc(100% - 330px); | |||
padding-top: 35px; | |||
box-sizing: border-box; | |||
} | |||
.settings-definition-name { | |||
text-overflow: ellipsis; | |||
} | |||
.settings-definition-key { | |||
line-height: 1.5; | |||
overflow: hidden; | |||
text-overflow: ellipsis; | |||
white-space: nowrap; | |||
} | |||
.settings-definition-key:hover { | |||
overflow: visible; | |||
} | |||
.settings-definition-state { | |||
position: absolute; | |||
top: 0; | |||
left: 0; | |||
right: 0; | |||
line-height: 24px; | |||
overflow: hidden; | |||
text-overflow: ellipsis; | |||
white-space: nowrap; | |||
} | |||
.settings-definition-state-icon { | |||
display: inline-block; | |||
vertical-align: middle; | |||
width: 24px; | |||
height: 24px; | |||
margin-right: 8px; | |||
text-align: center; | |||
} | |||
.settings-definition-state-icon > .icon-alert-error, | |||
.settings-definition-state-icon > .spinner { | |||
position: relative; | |||
top: -2px; | |||
} | |||
.settings-definition-changes { | |||
margin-top: 20px; | |||
padding-top: 20px; | |||
border-top: 1px dotted #e6e6e6; | |||
} | |||
.settings-sub-categories-list { | |||
} | |||
.settings-sub-categories-list > li { | |||
} | |||
.settings-sub-categories-list > li + li { | |||
margin: 30px -20px 0; | |||
padding: 30px 20px; | |||
border-top: 1px solid #e6e6e6; | |||
} | |||
.settings-sub-category-name { | |||
margin-bottom: 20px; | |||
font-size: 16px; | |||
} | |||
.settings-sub-category-description { | |||
margin-top: -15px; | |||
margin-bottom: 20px; | |||
color: #777; | |||
} |
@@ -0,0 +1,140 @@ | |||
/* | |||
* 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 { translate, hasMessage } from '../../helpers/l10n'; | |||
import { TYPE_PROPERTY_SET, TYPE_BOOLEAN, TYPE_SINGLE_SELECT_LIST, TYPE_PASSWORD } from './constants'; | |||
export const DEFAULT_CATEGORY = 'general'; | |||
export function getPropertyName (definition) { | |||
const key = `property.${definition.key}.name`; | |||
return hasMessage(key) ? translate(key) : definition.name; | |||
} | |||
export function getPropertyDescription (definition) { | |||
const key = `property.${definition.key}.description`; | |||
return hasMessage(key) ? translate(key) : definition.description; | |||
} | |||
export function getCategoryName (category) { | |||
const key = `property.category.${category}`; | |||
return hasMessage(key) ? translate(key) : category; | |||
} | |||
export function getSubCategoryName (category, subCategory) { | |||
const key = `property.category.${category}.${subCategory}`; | |||
return hasMessage(key) ? translate(key) : getCategoryName(subCategory); | |||
} | |||
export function getSubCategoryDescription (category, subCategory) { | |||
const key = `property.category.${category}.${subCategory}.description`; | |||
return hasMessage(key) ? translate(key) : null; | |||
} | |||
export function getUniqueName (definition, index = null) { | |||
const indexSuffix = index != null ? `[${index}]` : ''; | |||
return `settings[${definition.key}]${indexSuffix}`; | |||
} | |||
export function getSettingValue (setting) { | |||
if (setting.definition.multiValues) { | |||
return setting.values; | |||
} else if (setting.definition.type === TYPE_PROPERTY_SET) { | |||
return setting.fieldValues; | |||
} else { | |||
return setting.value; | |||
} | |||
} | |||
export function isEmptyValue (definition, value) { | |||
if (value == null) { | |||
return true; | |||
} else if (definition.type === TYPE_BOOLEAN) { | |||
return false; | |||
} else { | |||
return value.length === 0; | |||
} | |||
} | |||
export function getEmptyValue (definition) { | |||
if (definition.multiValues) { | |||
return [getEmptyValue({ ...definition, multiValues: false })]; | |||
} | |||
if (definition.type === TYPE_PROPERTY_SET) { | |||
const value = {}; | |||
definition.fields.forEach(field => value[field.key] = getEmptyValue(field)); | |||
return [value]; | |||
} | |||
if (definition.type === TYPE_BOOLEAN || definition.type === TYPE_SINGLE_SELECT_LIST) { | |||
return null; | |||
} | |||
return ''; | |||
} | |||
export function isDefaultOrInherited (setting) { | |||
return !!setting.default || !!setting.inherited; | |||
} | |||
function getParentValue (setting) { | |||
if (setting.definition.multiValues) { | |||
return setting.parentValues; | |||
} else if (setting.definition.type === TYPE_PROPERTY_SET) { | |||
return setting.parentFieldValues; | |||
} else { | |||
return setting.parentValue; | |||
} | |||
} | |||
/** | |||
* Get and format the default value | |||
* @param setting | |||
* @returns {string} | |||
*/ | |||
export function getDefaultValue (setting) { | |||
const parentValue = getParentValue(setting); | |||
if (parentValue == null) { | |||
return translate('settings.default.no_value'); | |||
} | |||
if (setting.definition.multiValues) { | |||
return parentValue.length > 0 ? | |||
parentValue.join(', ') : | |||
translate('settings.default.no_value'); | |||
} | |||
if (setting.definition.type === TYPE_PROPERTY_SET) { | |||
return parentValue.length > 0 ? | |||
translate('settings.default.complex_value') : | |||
translate('settings.default.no_value'); | |||
} | |||
if (setting.definition.type === TYPE_PASSWORD) { | |||
return translate('settings.default.password'); | |||
} | |||
if (setting.definition.type === TYPE_BOOLEAN) { | |||
return parentValue ? translate('settings.boolean.true') : translate('settings.boolean.false'); | |||
} | |||
return parentValue; | |||
} |
@@ -0,0 +1,51 @@ | |||
/* | |||
* 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 classNames from 'classnames'; | |||
import './styles.css'; | |||
export default class Toggle extends React.Component { | |||
static propTypes = { | |||
value: React.PropTypes.oneOfType([React.PropTypes.string, React.PropTypes.bool]).isRequired, | |||
name: React.PropTypes.string, | |||
onChange: React.PropTypes.func | |||
}; | |||
handleClick (e, value) { | |||
e.preventDefault(); | |||
e.currentTarget.blur(); | |||
if (this.props.onChange) { | |||
this.props.onChange(!value); | |||
} | |||
} | |||
render () { | |||
const { value } = this.props; | |||
const booleanValue = typeof value === 'string' ? value === 'true' : value; | |||
const className = classNames('boolean-toggle', { 'boolean-toggle-on': booleanValue }); | |||
return ( | |||
<button className={className} name={this.props.name} onClick={e => this.handleClick(e, booleanValue)}> | |||
<div className="boolean-toggle-handle"/> | |||
</button> | |||
); | |||
} | |||
} |
@@ -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 chai, { expect } from 'chai'; | |||
import { shallow } from 'enzyme'; | |||
import sinon from 'sinon'; | |||
import sinonChai from 'sinon-chai'; | |||
import React from 'react'; | |||
import Toggle from '../Toggle'; | |||
chai.use(sinonChai); | |||
function getSample (props) { | |||
return ( | |||
<Toggle value={true} onChange={() => true} {...props}/>); | |||
} | |||
function click (element) { | |||
return element.simulate('click', { | |||
currentTarget: { blur () {} }, | |||
preventDefault () {} | |||
}); | |||
} | |||
describe('Components :: Controls :: Toggle', () => { | |||
it('should render', () => { | |||
const Toggle = shallow(getSample()); | |||
expect(Toggle.is('button')).to.equal(true); | |||
}); | |||
it('should call onChange', () => { | |||
const onChange = sinon.spy(); | |||
const Toggle = shallow(getSample({ onChange })); | |||
click(Toggle); | |||
expect(onChange).to.have.been.calledWith(false); | |||
}); | |||
}); |
@@ -24,3 +24,54 @@ | |||
.date-input-control-input:focus + .date-input-control-icon path { | |||
fill: #4b9fd5; | |||
} | |||
.boolean-toggle { | |||
display: inline-block; | |||
vertical-align: middle; | |||
width: 48px; | |||
height: 24px; | |||
padding: 1px; | |||
border: 1px solid #cdcdcd; | |||
border-radius: 24px; | |||
box-sizing: border-box; | |||
background-color: #fff; | |||
cursor: pointer; | |||
transition: all 0.3s ease; | |||
} | |||
.boolean-toggle:hover { | |||
background-color: #fff; | |||
} | |||
.boolean-toggle:focus { | |||
border-color: #4b9fd5; | |||
background-color: #f6f6f6; | |||
} | |||
.boolean-toggle-handle { | |||
width: 20px; | |||
height: 20px; | |||
border: 1px solid #cdcdcd; | |||
border-radius: 22px; | |||
box-sizing: border-box; | |||
background-color: #f6f6f6; | |||
transition: transform 0.3s cubic-bezier(.87,-.41,.19,1.44), border 0.3s ease; | |||
} | |||
.boolean-toggle-on { | |||
border-color: #236a97; | |||
background-color: #236a97; | |||
} | |||
.boolean-toggle-on:hover { | |||
background-color: #236a97; | |||
} | |||
.boolean-toggle-on:focus { | |||
background-color: #236a97; | |||
} | |||
.boolean-toggle-on .boolean-toggle-handle { | |||
border-color: #f6f6f6; | |||
transform: translateX(24px); | |||
} |
@@ -36,6 +36,11 @@ export function translateWithParameters (messageKey, ...parameters) { | |||
} | |||
} | |||
export function hasMessage (...keys) { | |||
const messageKey = keys.join('.'); | |||
return messages[messageKey] != null; | |||
} | |||
function getCurrentLocale () { | |||
return window.navigator.languages ? window.navigator.languages[0] : window.navigator.language; | |||
} |
@@ -201,5 +201,5 @@ export function requestDelete (url, data) { | |||
* @returns {Promise} | |||
*/ | |||
export function delay (response) { | |||
return new Promise(resolve => setTimeout(() => resolve(response), 3000)); | |||
return new Promise(resolve => setTimeout(() => resolve(response), 500)); | |||
} |
@@ -92,7 +92,7 @@ | |||
left: 0; | |||
line-height: @formControlHeight; | |||
padding-left: 8px; | |||
padding-right: 8px; | |||
padding-right: 24px; | |||
position: absolute; | |||
right: 0; | |||
top: 0; |