From 2a91ab92dac4203e4410f5b2ab0ffbd1a6efac0e Mon Sep 17 00:00:00 2001 From: Stas Vilchik Date: Mon, 19 Dec 2016 14:07:32 +0100 Subject: [PATCH] SONAR-7674 Add Activity Stream interface (#1459) --- .../src/test/java/it/Category4Suite.java | 2 + .../ProjectAdministrationTest.java | 2 +- .../test/java/it/projectEvent/EventTest.java | 12 +- .../ProjectActivityPageTest.java} | 66 +- .../it/qualityGate/QualityGateUiTest.java | 9 +- .../src/test/java/pageobjects/Navigation.java | 12 +- ...toryPage.java => ProjectActivityPage.java} | 35 +- .../java/pageobjects/ProjectAnalysisItem.java | 104 +++ .../create_delete_standard_event.html | 114 ---- server/sonar-web/package.json | 3 +- .../src/main/js/api/projectActivity.js | 99 +++ .../nav/component/ComponentNavMenu.js | 28 +- .../app/components/nav/global/SearchView.js | 2 +- .../src/main/js/app/utils/startReactApp.js | 2 + .../src/main/js/apps/overview/actions.js | 32 + .../js/apps/overview/events/AnalysesList.js | 118 ++++ .../overview/events/{Event.js => Analysis.js} | 59 +- .../js/apps/overview/events/EventsList.js | 149 ----- .../src/main/js/apps/overview/meta/Meta.js | 8 +- .../src/main/js/apps/overview/styles.css | 10 + .../main/js/apps/projectActivity/actions.js | 87 +++ .../projectActivity/components/ChangeIcon.js | 33 + .../projectActivity/components/DeleteIcon.js | 33 + .../apps/projectActivity/components/Event.css | 7 + .../apps/projectActivity/components/Event.js | 118 ++++ .../components/EventInner.js} | 50 +- .../apps/projectActivity/components/Events.js | 56 ++ .../components/ProjectActivityAnalysesList.js | 87 +++ .../components/ProjectActivityAnalysis.js | 88 +++ .../components/ProjectActivityApp.js | 91 +++ .../components/ProjectActivityPageFooter.js | 61 ++ .../components/ProjectActivityPageHeader.js | 63 ++ .../components/forms/AddCustomEventForm.js | 34 + .../components/forms/AddEventForm.js | 146 ++++ .../components/forms/AddVersionForm.js | 34 + .../components/forms/ChangeCustomEventForm.js | 36 + .../components/forms/ChangeEventForm.js | 135 ++++ .../components/forms/ChangeVersionForm.js | 36 + .../components/forms/RemoveAnalysisForm.js | 136 ++++ .../components/forms/RemoveCustomEventForm.js | 37 + .../components/forms/RemoveEventForm.js | 113 ++++ .../components/forms/RemoveVersionForm.js | 37 + .../components/projectActivity.css | 121 ++++ .../main/js/apps/projectActivity/routes.js | 27 + .../main/js/components/ui/FormattedDate.js | 50 +- .../__snapshots__/analyses-test.js.snap | 93 +++ .../analysesByProject-test.js.snap | 55 ++ .../__tests__/__snapshots__/duck-test.js.snap | 75 +++ .../__snapshots__/events-test.js.snap | 71 ++ .../__snapshots__/paging-test.js.snap | 21 + .../__tests__/analyses-test.js | 90 +++ .../__tests__/analysesByProject-test.js | 80 +++ .../projectActivity/__tests__/duck-test.js | 100 +++ .../projectActivity/__tests__/events-test.js | 90 +++ .../projectActivity/__tests__/paging-test.js | 49 ++ .../main/js/store/projectActivity/analyses.js | 89 +++ .../projectActivity/analysesByProject.js | 53 ++ .../src/main/js/store/projectActivity/duck.js | 148 ++++ .../main/js/store/projectActivity/events.js | 79 +++ .../main/js/store/projectActivity/paging.js | 34 + .../src/main/js/store/rootActions.js | 2 +- .../src/main/js/store/rootReducer.js | 6 + .../src/main/js/store/utils/configureStore.js | 4 + .../src/main/less/components/modals.less | 28 +- .../sonar-web/src/main/less/init/forms.less | 18 +- server/sonar-web/yarn.lock | 631 +++++++----------- .../resources/org/sonar/l10n/core.properties | 25 +- 67 files changed, 3579 insertions(+), 844 deletions(-) rename it/it-tests/src/test/java/it/{projectAdministration/ProjectHistoryPageTest.java => projectEvent/ProjectActivityPageTest.java} (59%) rename it/it-tests/src/test/java/pageobjects/{ProjectHistoryPage.java => ProjectActivityPage.java} (54%) create mode 100644 it/it-tests/src/test/java/pageobjects/ProjectAnalysisItem.java delete mode 100644 it/it-tests/src/test/resources/projectEvent/EventTest/create_delete_standard_event.html create mode 100644 server/sonar-web/src/main/js/api/projectActivity.js create mode 100644 server/sonar-web/src/main/js/apps/overview/actions.js create mode 100644 server/sonar-web/src/main/js/apps/overview/events/AnalysesList.js rename server/sonar-web/src/main/js/apps/overview/events/{Event.js => Analysis.js} (52%) delete mode 100644 server/sonar-web/src/main/js/apps/overview/events/EventsList.js create mode 100644 server/sonar-web/src/main/js/apps/projectActivity/actions.js create mode 100644 server/sonar-web/src/main/js/apps/projectActivity/components/ChangeIcon.js create mode 100644 server/sonar-web/src/main/js/apps/projectActivity/components/DeleteIcon.js create mode 100644 server/sonar-web/src/main/js/apps/projectActivity/components/Event.css create mode 100644 server/sonar-web/src/main/js/apps/projectActivity/components/Event.js rename server/sonar-web/src/main/js/apps/{overview/events/EventsListFilter.js => projectActivity/components/EventInner.js} (55%) create mode 100644 server/sonar-web/src/main/js/apps/projectActivity/components/Events.js create mode 100644 server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityAnalysesList.js create mode 100644 server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityAnalysis.js create mode 100644 server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityApp.js create mode 100644 server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityPageFooter.js create mode 100644 server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityPageHeader.js create mode 100644 server/sonar-web/src/main/js/apps/projectActivity/components/forms/AddCustomEventForm.js create mode 100644 server/sonar-web/src/main/js/apps/projectActivity/components/forms/AddEventForm.js create mode 100644 server/sonar-web/src/main/js/apps/projectActivity/components/forms/AddVersionForm.js create mode 100644 server/sonar-web/src/main/js/apps/projectActivity/components/forms/ChangeCustomEventForm.js create mode 100644 server/sonar-web/src/main/js/apps/projectActivity/components/forms/ChangeEventForm.js create mode 100644 server/sonar-web/src/main/js/apps/projectActivity/components/forms/ChangeVersionForm.js create mode 100644 server/sonar-web/src/main/js/apps/projectActivity/components/forms/RemoveAnalysisForm.js create mode 100644 server/sonar-web/src/main/js/apps/projectActivity/components/forms/RemoveCustomEventForm.js create mode 100644 server/sonar-web/src/main/js/apps/projectActivity/components/forms/RemoveEventForm.js create mode 100644 server/sonar-web/src/main/js/apps/projectActivity/components/forms/RemoveVersionForm.js create mode 100644 server/sonar-web/src/main/js/apps/projectActivity/components/projectActivity.css create mode 100644 server/sonar-web/src/main/js/apps/projectActivity/routes.js rename it/it-tests/src/test/java/pageobjects/ProjectHistorySnapshotItem.java => server/sonar-web/src/main/js/components/ui/FormattedDate.js (52%) create mode 100644 server/sonar-web/src/main/js/store/projectActivity/__tests__/__snapshots__/analyses-test.js.snap create mode 100644 server/sonar-web/src/main/js/store/projectActivity/__tests__/__snapshots__/analysesByProject-test.js.snap create mode 100644 server/sonar-web/src/main/js/store/projectActivity/__tests__/__snapshots__/duck-test.js.snap create mode 100644 server/sonar-web/src/main/js/store/projectActivity/__tests__/__snapshots__/events-test.js.snap create mode 100644 server/sonar-web/src/main/js/store/projectActivity/__tests__/__snapshots__/paging-test.js.snap create mode 100644 server/sonar-web/src/main/js/store/projectActivity/__tests__/analyses-test.js create mode 100644 server/sonar-web/src/main/js/store/projectActivity/__tests__/analysesByProject-test.js create mode 100644 server/sonar-web/src/main/js/store/projectActivity/__tests__/duck-test.js create mode 100644 server/sonar-web/src/main/js/store/projectActivity/__tests__/events-test.js create mode 100644 server/sonar-web/src/main/js/store/projectActivity/__tests__/paging-test.js create mode 100644 server/sonar-web/src/main/js/store/projectActivity/analyses.js create mode 100644 server/sonar-web/src/main/js/store/projectActivity/analysesByProject.js create mode 100644 server/sonar-web/src/main/js/store/projectActivity/duck.js create mode 100644 server/sonar-web/src/main/js/store/projectActivity/events.js create mode 100644 server/sonar-web/src/main/js/store/projectActivity/paging.js diff --git a/it/it-tests/src/test/java/it/Category4Suite.java b/it/it-tests/src/test/java/it/Category4Suite.java index 4e6e08af980..db87ef57d3c 100644 --- a/it/it-tests/src/test/java/it/Category4Suite.java +++ b/it/it-tests/src/test/java/it/Category4Suite.java @@ -30,6 +30,7 @@ import it.duplication.CrossProjectDuplicationsTest; import it.duplication.DuplicationsTest; import it.duplication.NewDuplicationsTest; import it.projectEvent.EventTest; +import it.projectEvent.ProjectActivityPageTest; import it.projectSearch.SearchProjectsTest; import it.qualityProfile.QualityProfilesPageTest; import it.serverSystem.HttpHeadersTest; @@ -80,6 +81,7 @@ import static util.ItUtils.xooPlugin; PurgeTest.class, // project event EventTest.class, + ProjectActivityPageTest.class, // project search SearchProjectsTest.class, // http diff --git a/it/it-tests/src/test/java/it/projectAdministration/ProjectAdministrationTest.java b/it/it-tests/src/test/java/it/projectAdministration/ProjectAdministrationTest.java index 044e342a07c..e9aa4ba0f99 100644 --- a/it/it-tests/src/test/java/it/projectAdministration/ProjectAdministrationTest.java +++ b/it/it-tests/src/test/java/it/projectAdministration/ProjectAdministrationTest.java @@ -128,7 +128,7 @@ public class ProjectAdministrationTest { // SONAR-4203 @Test - @Ignore("history page is not available yet") + @Ignore("refactor with wsClient") public void delete_version_of_multimodule_project() { GregorianCalendar today = new GregorianCalendar(); SonarScanner build = SonarScanner.create(projectDir("shared/xoo-multi-modules-sample")) diff --git a/it/it-tests/src/test/java/it/projectEvent/EventTest.java b/it/it-tests/src/test/java/it/projectEvent/EventTest.java index 062e2666966..749e27a1ec6 100644 --- a/it/it-tests/src/test/java/it/projectEvent/EventTest.java +++ b/it/it-tests/src/test/java/it/projectEvent/EventTest.java @@ -37,9 +37,8 @@ import util.ItUtils; import static org.assertj.core.api.Assertions.assertThat; import static util.ItUtils.projectDir; -import static util.selenium.Selenese.runSelenese; -@Ignore("history page is not available yet") +@Ignore("refactor using wsClient") public class EventTest { @ClassRule @@ -50,7 +49,6 @@ public class EventTest { orchestrator.resetData(); } - @Ignore("UUID column of Events is not handled with Ruby pages and WS") @Test public void old_ws_events_does_not_allow_creating_events_on_modules() { SonarScanner sampleProject = SonarScanner.create(projectDir("shared/xoo-multi-modules-sample")); @@ -72,14 +70,6 @@ public class EventTest { .setParam("category", "Foo"); } - @Ignore("UUID column of Events is not handled with Ruby pages and WS") - @Test - public void delete_standard_event() { - executeAnalysis(); - - runSelenese(orchestrator, "/projectEvent/EventTest/create_delete_standard_event.html"); - } - /** * SONAR-3308 */ diff --git a/it/it-tests/src/test/java/it/projectAdministration/ProjectHistoryPageTest.java b/it/it-tests/src/test/java/it/projectEvent/ProjectActivityPageTest.java similarity index 59% rename from it/it-tests/src/test/java/it/projectAdministration/ProjectHistoryPageTest.java rename to it/it-tests/src/test/java/it/projectEvent/ProjectActivityPageTest.java index f7e2afdcd49..cc2d7063078 100644 --- a/it/it-tests/src/test/java/it/projectAdministration/ProjectHistoryPageTest.java +++ b/it/it-tests/src/test/java/it/projectEvent/ProjectActivityPageTest.java @@ -17,7 +17,7 @@ * 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.projectAdministration; +package it.projectEvent; import com.sonar.orchestrator.Orchestrator; import com.sonar.orchestrator.build.SonarScanner; @@ -28,15 +28,12 @@ import org.junit.ClassRule; import org.junit.Rule; import org.junit.Test; import pageobjects.Navigation; -import pageobjects.ProjectHistoryPage; -import pageobjects.ProjectHistorySnapshotItem; +import pageobjects.ProjectActivityPage; +import pageobjects.ProjectAnalysisItem; -import static com.codeborne.selenide.Condition.exist; -import static com.codeborne.selenide.Condition.text; -import static com.codeborne.selenide.Selenide.confirm; import static util.ItUtils.projectDir; -public class ProjectHistoryPageTest { +public class ProjectActivityPageTest { @ClassRule public static Orchestrator ORCHESTRATOR = Category1Suite.ORCHESTRATOR; @@ -45,47 +42,54 @@ public class ProjectHistoryPageTest { public Navigation nav = Navigation.get(ORCHESTRATOR); @Before - public void setUp() { + public void setUp() throws Exception { ORCHESTRATOR.resetData(); - analyzeProject("shared/xoo-history-v1", "2014-10-19"); - analyzeProject("shared/xoo-history-v2", "2014-11-13"); } @Test public void should_list_snapshots() { - ProjectHistoryPage page = openPage(); - - page.getSnapshots().shouldHaveSize(2); + analyzeProject("shared/xoo-history-v1", "2014-10-19"); + analyzeProject("shared/xoo-history-v2", "2014-11-13"); - List snapshots = page.getSnapshotsAsItems(); + ProjectActivityPage page = openPage(); + page.getAnalyses().shouldHaveSize(2); - snapshots.get(0).getVersionText().shouldBe(text("1.0-SNAPSHOT")); - snapshots.get(0).getDeleteButton().shouldNot(exist); + List analyses = page.getAnalysesAsItems(); + analyses.get(0) + .shouldHaveEventWithText("1.0-SNAPSHOT") + .shouldNotHaveDeleteButton(); - snapshots.get(1).getVersionText().shouldBe(text("0.9-SNAPSHOT")); - snapshots.get(1).getDeleteButton().should(exist); + analyses.get(1) + .shouldHaveEventWithText("0.9-SNAPSHOT") + .shouldHaveDeleteButton(); } @Test - public void should_delete_snapshot() { - ProjectHistoryPage page = openPage(); - - page.getSnapshots().shouldHaveSize(2); - - page.getSnapshotsAsItems().get(1).clickDelete(); - confirm(); + public void add_change_delete_custom_event() { + analyzeProject(); + openPage().getLastAnalysis() + .addCustomEvent("foo") + .changeLastEvent("bar") + .deleteLastEvent(); + } - page.checkAlertDisplayed(); - page.getSnapshots().shouldHaveSize(1); + @Test + public void delete_analysis() { + analyzeProject(); + analyzeProject(); + openPage().getFirstAnalysis().delete(); } - private ProjectHistoryPage openPage() { + private ProjectActivityPage openPage() { nav.logIn().submitCredentials("admin", "admin"); - return nav.openProjectHistory("sample"); + return nav.openProjectActivity("sample"); + } + + private static void analyzeProject() { + ORCHESTRATOR.executeBuild(SonarScanner.create(projectDir("shared/xoo-sample"))); } private static void analyzeProject(String path, String date) { - ORCHESTRATOR.executeBuild(SonarScanner.create(projectDir(path)) - .setProperties("sonar.projectDate", date)); + ORCHESTRATOR.executeBuild(SonarScanner.create(projectDir(path)).setProperties("sonar.projectDate", date)); } } diff --git a/it/it-tests/src/test/java/it/qualityGate/QualityGateUiTest.java b/it/it-tests/src/test/java/it/qualityGate/QualityGateUiTest.java index ef5fdf25a82..5ee509687fb 100644 --- a/it/it-tests/src/test/java/it/qualityGate/QualityGateUiTest.java +++ b/it/it-tests/src/test/java/it/qualityGate/QualityGateUiTest.java @@ -27,13 +27,14 @@ import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; import org.junit.ClassRule; -import org.junit.Ignore; import org.junit.Test; import org.sonar.wsclient.qualitygate.NewCondition; import org.sonar.wsclient.qualitygate.QualityGate; import org.sonar.wsclient.qualitygate.QualityGateClient; import org.sonar.wsclient.qualitygate.QualityGateCondition; import org.sonar.wsclient.qualitygate.UpdateCondition; +import pageobjects.Navigation; +import pageobjects.ProjectActivityPage; import util.ItUtils; import static util.ItUtils.projectDir; @@ -70,7 +71,6 @@ public class QualityGateUiTest { * SONAR-3326 */ @Test - @Ignore("history page is not available yet") public void display_alerts_correctly_in_history_page() { QualityGateClient qgClient = qgClient(); QualityGate qGate = qgClient.create("AlertsForHistory"); @@ -83,7 +83,10 @@ public class QualityGateUiTest { qgClient.updateCondition(UpdateCondition.create(lowThresholds.id()).metricKey("lines").operator("GT").warningThreshold("5000").errorThreshold("5000")); scanSampleWithDate("2012-01-02"); - runSelenese(orchestrator, "/qualityGate/QualityGateUiTest/should-display-alerts-correctly-history-page.html"); + ProjectActivityPage page = Navigation.get(orchestrator).openProjectActivity("sample"); + page + .assertFirstAnalysisOfTheDayHasText("2012-01-02", "Green (was Orange)") + .assertFirstAnalysisOfTheDayHasText("2012-01-01", "Orange"); qgClient.unsetDefault(); qgClient.destroy(qGate.id()); diff --git a/it/it-tests/src/test/java/pageobjects/Navigation.java b/it/it-tests/src/test/java/pageobjects/Navigation.java index 840f4b2f658..e9c23d63f14 100644 --- a/it/it-tests/src/test/java/pageobjects/Navigation.java +++ b/it/it-tests/src/test/java/pageobjects/Navigation.java @@ -79,18 +79,18 @@ public class Navigation extends ExternalResource { return open(url, ProjectQualityGatePage.class); } - public ProjectHistoryPage openProjectHistory(String projectKey) { - // TODO encode projectKey - String url = "/project/history?id=" + projectKey; - return open(url, ProjectHistoryPage.class); - } - public ProjectKeyPage openProjectKey(String projectKey) { // TODO encode projectKey String url = "/project/key?id=" + projectKey; return open(url, ProjectKeyPage.class); } + public ProjectActivityPage openProjectActivity(String projectKey) { + // TODO encode projectKey + String url = "/project/activity?id=" + projectKey; + return open(url, ProjectActivityPage.class); + } + public BackgroundTasksPage openBackgroundTasksPage() { return open("/background_tasks", BackgroundTasksPage.class); } diff --git a/it/it-tests/src/test/java/pageobjects/ProjectHistoryPage.java b/it/it-tests/src/test/java/pageobjects/ProjectActivityPage.java similarity index 54% rename from it/it-tests/src/test/java/pageobjects/ProjectHistoryPage.java rename to it/it-tests/src/test/java/pageobjects/ProjectActivityPage.java index 83b0f5c9241..8acf8920a2b 100644 --- a/it/it-tests/src/test/java/pageobjects/ProjectHistoryPage.java +++ b/it/it-tests/src/test/java/pageobjects/ProjectActivityPage.java @@ -19,32 +19,45 @@ */ package pageobjects; +import com.codeborne.selenide.Condition; import com.codeborne.selenide.ElementsCollection; import java.util.List; import java.util.stream.Collectors; -import static com.codeborne.selenide.Condition.exist; +import static com.codeborne.selenide.Condition.hasText; import static com.codeborne.selenide.Selenide.$; import static com.codeborne.selenide.Selenide.$$; -public class ProjectHistoryPage { +public class ProjectActivityPage { - public ProjectHistoryPage() { - $("#project-history").should(exist); + public ProjectActivityPage() { + $("#project-activity").should(Condition.exist); } - public ElementsCollection getSnapshots() { - return $$("tr.snapshot"); + public ElementsCollection getAnalyses() { + return $$(".project-activity-analysis"); } - public List getSnapshotsAsItems() { - return getSnapshots() + public List getAnalysesAsItems() { + return getAnalyses() .stream() - .map(ProjectHistorySnapshotItem::new) + .map(ProjectAnalysisItem::new) .collect(Collectors.toList()); } - public void checkAlertDisplayed() { - $("#info:not(.hidden)").should(exist); + public ProjectAnalysisItem getLastAnalysis() { + return new ProjectAnalysisItem($(".project-activity-analysis")); + } + + public ProjectAnalysisItem getFirstAnalysis() { + return new ProjectAnalysisItem($$(".project-activity-analysis").last()); + } + + public ProjectActivityPage assertFirstAnalysisOfTheDayHasText(String day, String text) { + $("#project-activity") + .find(".project-activity-day[data-day=\"" + day + "\"]") + .find(".project-activity-analysis") + .should(hasText(text)); + return this; } } diff --git a/it/it-tests/src/test/java/pageobjects/ProjectAnalysisItem.java b/it/it-tests/src/test/java/pageobjects/ProjectAnalysisItem.java new file mode 100644 index 00000000000..84de55eea95 --- /dev/null +++ b/it/it-tests/src/test/java/pageobjects/ProjectAnalysisItem.java @@ -0,0 +1,104 @@ +/* + * 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; + +import com.codeborne.selenide.Condition; +import com.codeborne.selenide.SelenideElement; + +import static com.codeborne.selenide.Condition.text; +import static com.codeborne.selenide.Condition.visible; +import static com.codeborne.selenide.Selenide.$; + +public class ProjectAnalysisItem { + + private final SelenideElement elt; + + public ProjectAnalysisItem(SelenideElement elt) { + this.elt = elt; + } + + public ProjectAnalysisItem shouldHaveEventWithText(String text) { + elt.find(".project-activity-events").shouldHave(Condition.text(text)); + return this; + } + + public ProjectAnalysisItem shouldHaveDeleteButton() { + elt.find(".js-delete-analysis").shouldBe(visible); + return this; + } + + public ProjectAnalysisItem shouldNotHaveDeleteButton() { + elt.find(".js-delete-analysis").shouldNotBe(visible); + return this; + } + + public void delete() { + elt.find(".js-delete-analysis").click(); + + SelenideElement modal = $(".modal"); + modal.shouldBe(visible); + modal.find("button[type=\"submit\"]").click(); + + elt.shouldNotBe(visible); + } + + public ProjectAnalysisItem addCustomEvent(String name) { + elt.find(".js-create").click(); + elt.find(".js-add-event").click(); + + SelenideElement modal = $(".modal"); + modal.shouldBe(visible); + modal.find("input").setValue(name); + modal.find("button[type=\"submit\"]").click(); + + elt.find(".project-activity-event:last-child").shouldHave(text(name)); + + return this; + } + + public ProjectAnalysisItem changeLastEvent(String newName) { + SelenideElement lastEvent = elt.find(".project-activity-event:last-child"); + lastEvent.find(".js-change-event").click(); + + SelenideElement modal = $(".modal"); + modal.shouldBe(visible); + modal.find("input").setValue(newName); + modal.find("button[type=\"submit\"]").click(); + + lastEvent.shouldHave(text(newName)); + + return this; + } + + public ProjectAnalysisItem deleteLastEvent() { + int eventsCount = elt.findAll(".project-activity-event").size(); + + SelenideElement lastEvent = elt.find(".project-activity-event:last-child"); + lastEvent.find(".js-delete-event").click(); + + SelenideElement modal = $(".modal"); + modal.shouldBe(visible); + modal.find("button[type=\"submit\"]").click(); + + elt.findAll(".project-activity-event").shouldHaveSize(eventsCount - 1); + + return this; + } +} diff --git a/it/it-tests/src/test/resources/projectEvent/EventTest/create_delete_standard_event.html b/it/it-tests/src/test/resources/projectEvent/EventTest/create_delete_standard_event.html deleted file mode 100644 index ae697da4326..00000000000 --- a/it/it-tests/src/test/resources/projectEvent/EventTest/create_delete_standard_event.html +++ /dev/null @@ -1,114 +0,0 @@ - - - - - - create_delete_standard_event - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
create_delete_standard_event
open/sessions/logout
open/sessions/login
typeloginadmin
typepasswordadmin
clickAndWaitcommit
waitForElementPresentcss=.js-user-authenticated
open/project/history?id=sample
clicklink=Create
waitForElementPresentcreate_event_name_0
typecreate_event_name_0EventToBeDeleted
clickAndWaitcreate_save_event_0
waitForElementPresentinfomsg
waitForTextinfomsgEvent 'EventToBeDeleted' was created.
assertElementPresent//td[text()='EventToBeDeleted']
clickAndWaitlink=Remove
assertConfirmationAre you sure you want to remove 'EventToBeDeleted' from this snapshot?
waitForElementPresentinfomsg
waitForTextinfomsgEvent 'EventToBeDeleted' was deleted.
assertElementNotPresent//td[text()='EventToBeDeleted']
- - diff --git a/server/sonar-web/package.json b/server/sonar-web/package.json index 36c49704e41..7f343115d4b 100644 --- a/server/sonar-web/package.json +++ b/server/sonar-web/package.json @@ -66,6 +66,7 @@ "react-dev-utils": "0.2.1", "react-dom": "15.3.2", "react-helmet": "3.1.0", + "react-modal": "^1.6.4", "react-redux": "4.4.1", "react-router": "2.8.1", "react-router-redux": "4.0.2", @@ -93,7 +94,7 @@ "test": "node scripts/test.js", "coverage": "npm test -- --coverage", "lint": "eslint src/main/js", - "typecheck": "flow check src/main/js" + "typecheck": "flow src/main/js" }, "engines": { "node": ">=4" diff --git a/server/sonar-web/src/main/js/api/projectActivity.js b/server/sonar-web/src/main/js/api/projectActivity.js new file mode 100644 index 00000000000..9131cb904f9 --- /dev/null +++ b/server/sonar-web/src/main/js/api/projectActivity.js @@ -0,0 +1,99 @@ +/* + * 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. + */ +// @flow +import { getJSON, postJSON, post } from '../helpers/request'; + +type GetProjectActivityResponse = { + analyses: Array, + paging: { + total: number, + pageIndex: number, + pageSize: number + } +}; + +type GetProjectActivityOptions = { + category?: ?string, + pageIndex?: ?number, + pageSize?: ?number +}; + +export const getProjectActivity = ( + project: string, + options?: GetProjectActivityOptions +): Promise => { + const data: Object = { project }; + if (options) { + if (options.category) { + data.category = options.category; + } + if (options.pageIndex) { + data.p = options.pageIndex; + } + if (options.pageSize) { + data.ps = options.pageSize; + } + } + + return getJSON('/api/project_analyses/search', data); +}; + +type CreateEventResponse = { + analysis: string, + key: string, + name: string, + category: string, + description?: string +}; + +export const createEvent = ( + analysis: string, + name: string, + category?: string, + description?: string +): Promise => { + const data: Object = { analysis, name }; + if (category) { + data.category = category; + } + if (description) { + data.description = description; + } + return postJSON('/api/project_analyses/create_event', data).then(r => r.event); +}; + +export const deleteEvent = (event: string): Promise<*> => ( + post('/api/project_analyses/delete_event', { event }) +); + +export const changeEvent = (event: string, name: ?string, description: ?string): Promise => { + const data: Object = { event }; + if (name) { + data.name = name; + } + if (description) { + data.description = description; + } + return postJSON('/api/project_analyses/update_event', data).then(r => r.event); +}; + +export const deleteAnalysis = (analysis: string): Promise<*> => ( + post('/api/project_analyses/delete', { analysis }) +); diff --git a/server/sonar-web/src/main/js/app/components/nav/component/ComponentNavMenu.js b/server/sonar-web/src/main/js/app/components/nav/component/ComponentNavMenu.js index c348e186615..205e203b3d5 100644 --- a/server/sonar-web/src/main/js/app/components/nav/component/ComponentNavMenu.js +++ b/server/sonar-web/src/main/js/app/components/nav/component/ComponentNavMenu.js @@ -95,6 +95,17 @@ export default class ComponentNavMenu extends React.Component { ); } + renderActivityLink () { + return ( +
  • + + {translate('project_activity.page')} + +
  • + ); + } + renderComponentIssuesLink () { return (
  • @@ -138,7 +149,6 @@ export default class ComponentNavMenu extends React.Component { {this.renderCustomMeasuresLink()} {this.renderLinksLink()} {this.renderPermissionsLink()} - {this.renderHistoryLink()} {this.renderBackgroundTasksLink()} {this.renderUpdateKeyLink()} {this.renderExtensions()} @@ -238,21 +248,6 @@ export default class ComponentNavMenu extends React.Component { ); } - renderHistoryLink () { - if (!this.props.conf.showHistory) { - return null; - } - const url = `/project/history?id=${encodeURIComponent(this.props.component.key)}`; - // return this.renderLink(url, translate('project_history.page'), '/project/history'); - return ( -
  • - - {translate('project_history.page')} - -
  • - ); - } - renderBackgroundTasksLink () { if (!this.props.conf.showBackgroundTasks) { return null; @@ -336,6 +331,7 @@ export default class ComponentNavMenu extends React.Component { {this.renderComponentIssuesLink()} {this.renderComponentMeasuresLink()} {this.renderCodeLink()} + {this.renderActivityLink()} {this.renderTools()} {this.renderAdministration()} diff --git a/server/sonar-web/src/main/js/app/components/nav/global/SearchView.js b/server/sonar-web/src/main/js/app/components/nav/global/SearchView.js index 6d30a446290..9edb27a8ff2 100644 --- a/server/sonar-web/src/main/js/app/components/nav/global/SearchView.js +++ b/server/sonar-web/src/main/js/app/components/nav/global/SearchView.js @@ -98,7 +98,7 @@ export default Marionette.LayoutView.extend({ }, events: { - 'submit': 'onSubmit', + 'submit': 'handleSubmit', 'keydown .js-search-input': 'onKeyDown', 'keyup .js-search-input': 'onKeyUp' }, diff --git a/server/sonar-web/src/main/js/app/utils/startReactApp.js b/server/sonar-web/src/main/js/app/utils/startReactApp.js index e92ba5d8996..2c04125c885 100644 --- a/server/sonar-web/src/main/js/app/utils/startReactApp.js +++ b/server/sonar-web/src/main/js/app/utils/startReactApp.js @@ -45,6 +45,7 @@ import issuesRoutes from '../../apps/issues/routes'; import metricsRoutes from '../../apps/metrics/routes'; import overviewRoutes from '../../apps/overview/routes'; import permissionTemplatesRoutes from '../../apps/permission-templates/routes'; +import projectActivityRoutes from '../../apps/projectActivity/routes'; import projectAdminRoutes from '../../apps/project-admin/routes'; import projectsRoutes from '../../apps/projects/routes'; import projectsAdminRoutes from '../../apps/projects-admin/routes'; @@ -109,6 +110,7 @@ const startReactApp = () => { {customMeasuresRoutes} {overviewRoutes} + {projectActivityRoutes} {backgroundTasksRoutes} {settingsRoutes} {projectAdminRoutes} diff --git a/server/sonar-web/src/main/js/apps/overview/actions.js b/server/sonar-web/src/main/js/apps/overview/actions.js new file mode 100644 index 00000000000..99136099f50 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/overview/actions.js @@ -0,0 +1,32 @@ +/* + * 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. + */ +// @flow +import * as api from '../../api/projectActivity'; +import { receiveProjectActivity } from '../../store/projectActivity/duck'; +import { onFail } from '../../store/rootActions'; + +const PAGE_SIZE = 5; + +export const fetchRecentProjectActivity = (project: string) => (dispatch: Function) => ( + api.getProjectActivity(project, { pageSize: PAGE_SIZE }).then( + ({ analyses, paging }) => dispatch(receiveProjectActivity(project, analyses, paging)), + onFail(dispatch) + ) +); diff --git a/server/sonar-web/src/main/js/apps/overview/events/AnalysesList.js b/server/sonar-web/src/main/js/apps/overview/events/AnalysesList.js new file mode 100644 index 00000000000..842a9680310 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/overview/events/AnalysesList.js @@ -0,0 +1,118 @@ +/* + * 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. + */ +// @flow +import React from 'react'; +import { Link } from 'react-router'; +import { connect } from 'react-redux'; +import Analysis from './Analysis'; +import { translate } from '../../../helpers/l10n'; +import { fetchRecentProjectActivity } from '../actions'; +import { getProjectActivity } from '../../../store/rootReducer'; +import { getAnalyses } from '../../../store/projectActivity/duck'; + +type Props = { + analyses?: Array<*>, + project: string; + fetchRecentProjectActivity: (project: string) => Promise<*>; +} + +class AnalysesList extends React.Component { + mounted: boolean; + props: Props; + + state = { + loading: true + }; + + componentDidMount () { + this.mounted = true; + this.fetchData(); + } + + componentDidUpdate (prevProps: Props) { + if (prevProps.project !== this.props.project) { + this.fetchData(); + } + } + + componentWillUnmount () { + this.mounted = false; + } + + fetchData () { + this.setState({ loading: true }); + this.props.fetchRecentProjectActivity(this.props.project).then(() => { + if (this.mounted) { + this.setState({ loading: false }); + } + }); + } + + renderList (analyses) { + if (!analyses.length) { + return ( +

    + {translate('no_results')} +

    + ); + } + + return ( +
      + {analyses.map(analysis => ( + + ))} +
    + ); + } + + render () { + const { analyses } = this.props; + const { loading } = this.state; + + if (loading || !analyses) { + return null; + } + + return ( +
    +

    + {translate('project_activity.page')} +

    + + {this.renderList(analyses)} + +
    + + {translate('show_more')} + +
    +
    + ); + } +} + +const mapStateToProps = (state, ownProps: Props) => ({ + analyses: getAnalyses(getProjectActivity(state), ownProps.project) +}); + +const mapDispatchToProps = { fetchRecentProjectActivity }; + +export default connect(mapStateToProps, mapDispatchToProps)(AnalysesList); diff --git a/server/sonar-web/src/main/js/apps/overview/events/Event.js b/server/sonar-web/src/main/js/apps/overview/events/Analysis.js similarity index 52% rename from server/sonar-web/src/main/js/apps/overview/events/Event.js rename to server/sonar-web/src/main/js/apps/overview/events/Analysis.js index acef6b789cb..a168b08329d 100644 --- a/server/sonar-web/src/main/js/apps/overview/events/Event.js +++ b/server/sonar-web/src/main/js/apps/overview/events/Analysis.js @@ -18,39 +18,36 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import React from 'react'; -import moment from 'moment'; - -import { EventType } from '../propTypes'; +import Events from '../../projectActivity/components/Events'; +import FormattedDate from '../../../components/ui/FormattedDate'; import { TooltipsContainer } from '../../../components/mixins/tooltips-mixin'; import { translate } from '../../../helpers/l10n'; +import type { Analysis as AnalysisType } from '../../../store/projectActivity/duck'; -const Event = ({ event }) => { - return ( - -
  • -

    - - {translate('event.category', event.type)} - - {': '} - {event.name} - {event.text && ( - - )} -

    -

    - {moment(event.date).format('LL')} -

    -
  • -
    - ); -}; +export default class Analysis extends React.Component { + props: { + analysis: AnalysisType + }; -Event.propTypes = { - event: EventType.isRequired -}; + render () { + const { analysis } = this.props; -export default Event; + return ( + +
  • +
    + + + +
    + + {analysis.events.length > 0 ? ( + + ) : ( + {translate('project_activity.project_analyzed')} + )} +
  • +
    + ); + } +} diff --git a/server/sonar-web/src/main/js/apps/overview/events/EventsList.js b/server/sonar-web/src/main/js/apps/overview/events/EventsList.js deleted file mode 100644 index 3b35a24d690..00000000000 --- a/server/sonar-web/src/main/js/apps/overview/events/EventsList.js +++ /dev/null @@ -1,149 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2016 SonarSource SA - * mailto:contact AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import moment from 'moment'; -import React from 'react'; -import shallowCompare from 'react-addons-shallow-compare'; - -import Event from './Event'; -import EventsListFilter from './EventsListFilter'; -import { getEvents } from '../../../api/events'; -import { translate } from '../../../helpers/l10n'; - -const LIMIT = 5; - -export default class EventsList extends React.Component { - state = { - events: [], - limited: true, - filter: 'All' - }; - - componentDidMount () { - this.mounted = true; - this.fetchEvents(); - } - - shouldComponentUpdate (nextProps, nextState) { - return shallowCompare(this, nextProps, nextState); - } - - componentDidUpdate (nextProps) { - if (nextProps.component !== this.props.component) { - this.fetchEvents(); - } - } - - componentWillUnmount () { - this.mounted = false; - } - - fetchEvents () { - getEvents(this.props.component.key).then(events => { - if (this.mounted) { - const nextEvents = events.map(event => { - return { - id: event.id, - date: moment(event.dt).toDate(), - type: event.c, - name: event.n, - text: event.ds - }; - }); - - this.setState({ events: nextEvents }); - } - }); - } - - limitEvents (events) { - return this.state.limited ? events.slice(0, LIMIT) : events; - } - - filterEvents (events) { - if (this.state.filter === 'All') { - return events; - } else { - return events.filter(event => event.type === this.state.filter); - } - } - - handleClick (e) { - e.preventDefault(); - this.setState({ limited: !this.state.limited }); - } - - handleFilter (filter) { - this.setState({ filter }); - } - - renderMoreLink () { - const text = this.state.limited ? - translate('widget.events.show_all') : - translate('hide'); - - return ( -

    - {text} -

    - ); - } - - renderList (events) { - if (events.length) { - return ( -
      - {events.map(event => ( - - ))} -
    - ); - } else { - return ( -

    - {translate('no_results')} -

    - ); - } - } - - render () { - const filteredEvents = this.filterEvents(this.state.events); - const events = this.limitEvents(filteredEvents); - - return ( -
    -
    -

    - {translate('widget.events.name')} -

    -
    - -
    -
    - - {this.renderList(events)} - - {filteredEvents.length > LIMIT && this.renderMoreLink()} -
    - ); - } -} diff --git a/server/sonar-web/src/main/js/apps/overview/meta/Meta.js b/server/sonar-web/src/main/js/apps/overview/meta/Meta.js index c034da4452b..26be7ed8ea2 100644 --- a/server/sonar-web/src/main/js/apps/overview/meta/Meta.js +++ b/server/sonar-web/src/main/js/apps/overview/meta/Meta.js @@ -23,7 +23,7 @@ import MetaKey from './MetaKey'; import MetaLinks from './MetaLinks'; import MetaQualityGate from './MetaQualityGate'; import MetaQualityProfiles from './MetaQualityProfiles'; -import EventsList from './../events/EventsList'; +import AnalysesList from '../events/AnalysesList'; import MetaSize from './MetaSize'; const Meta = ({ component, measures }) => { @@ -40,7 +40,7 @@ const Meta = ({ component, measures }) => { const shouldShowQualityProfiles = !isView && !isDeveloper && hasQualityProfiles; const shouldShowQualityGate = !isView && !isDeveloper && hasQualityGate; - const showShowEvents = isProject || isView || isDeveloper; + const showShowAnalyses = isProject || isView || isDeveloper; return (
    @@ -64,8 +64,8 @@ const Meta = ({ component, measures }) => { - {showShowEvents && ( - + {showShowAnalyses && ( + )}
    ); diff --git a/server/sonar-web/src/main/js/apps/overview/styles.css b/server/sonar-web/src/main/js/apps/overview/styles.css index cb9c344b814..088b19ca7e2 100644 --- a/server/sonar-web/src/main/js/apps/overview/styles.css +++ b/server/sonar-web/src/main/js/apps/overview/styles.css @@ -319,6 +319,16 @@ box-sizing: border-box; } +.overview-analysis { + +} + +.overview-analysis + .overview-analysis { + margin-top: 8px; + padding-top: 8px; + border-top: 1px solid #e6e6e6; +} + /* * Other */ diff --git a/server/sonar-web/src/main/js/apps/projectActivity/actions.js b/server/sonar-web/src/main/js/apps/projectActivity/actions.js new file mode 100644 index 00000000000..83115bd1800 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/projectActivity/actions.js @@ -0,0 +1,87 @@ +/* + * 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. + */ +// @flow +import * as api from '../../api/projectActivity'; +import { + receiveProjectActivity, + addEvent, + deleteEvent as deleteEventAction, + changeEvent as changeEventAction, + deleteAnalysis as deleteAnalysisAction, + getPaging +} from '../../store/projectActivity/duck'; +import { onFail } from '../../store/rootActions'; +import { getProjectActivity } from '../../store/rootReducer'; + +const rejectOnFail = (dispatch: Function) => (error: any) => { + onFail(dispatch)(error); + return Promise.reject(); +}; + +export const fetchProjectActivity = (project: string, filter: ?string) => (dispatch: Function): void => { + api.getProjectActivity(project, { category: filter }).then( + ({ analyses, paging }) => dispatch(receiveProjectActivity(project, analyses, paging)), + onFail(dispatch) + ); +}; + +export const fetchMoreProjectActivity = (project: string, filter: ?string) => + (dispatch: Function, getState: Function): void => { + const projectActivity = getProjectActivity(getState()); + const { pageIndex } = getPaging(projectActivity, project); + + api.getProjectActivity(project, { category: filter, pageIndex: pageIndex + 1 }).then( + ({ analyses, paging }) => dispatch(receiveProjectActivity(project, analyses, paging)), + onFail(dispatch) + ); + }; + +export const addCustomEvent = (analysis: string, name: string, category?: string) => + (dispatch: Function): Promise<*> => { + return api.createEvent(analysis, name, category).then( + ({ analysis, ...event }) => dispatch(addEvent(analysis, event)), + rejectOnFail(dispatch) + ); + }; + +export const deleteEvent = (analysis: string, event: string) => (dispatch: Function): Promise<*> => { + return api.deleteEvent(event).then( + () => dispatch(deleteEventAction(analysis, event)), + rejectOnFail(dispatch) + ); +}; + +export const addVersion = (analysis: string, version: string) => (dispatch: Function): Promise<*> => { + return dispatch(addCustomEvent(analysis, version, 'VERSION')); +}; + +export const changeEvent = (event: string, name: string) => (dispatch: Function): Promise<*> => { + return api.changeEvent(event, name).then( + () => dispatch(changeEventAction(event, { name })), + rejectOnFail(dispatch) + ); +}; + +export const deleteAnalysis = (project: string, analysis: string) => (dispatch: Function): Promise<*> => { + return api.deleteAnalysis(analysis).then( + () => dispatch(deleteAnalysisAction(project, analysis)), + rejectOnFail(dispatch) + ); +}; diff --git a/server/sonar-web/src/main/js/apps/projectActivity/components/ChangeIcon.js b/server/sonar-web/src/main/js/apps/projectActivity/components/ChangeIcon.js new file mode 100644 index 00000000000..c9a0862e094 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/projectActivity/components/ChangeIcon.js @@ -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. + */ +// @flow +import React from 'react'; + +export default class ChangeIcon extends React.Component { + render () { + /* eslint-disable max-len */ + return ( + + + + ); + } +} diff --git a/server/sonar-web/src/main/js/apps/projectActivity/components/DeleteIcon.js b/server/sonar-web/src/main/js/apps/projectActivity/components/DeleteIcon.js new file mode 100644 index 00000000000..fc0ea426cd8 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/projectActivity/components/DeleteIcon.js @@ -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. + */ +// @flow +import React from 'react'; + +export default class DeleteIcon extends React.Component { + render () { + /* eslint-disable max-len */ + return ( + + + + ); + } +} diff --git a/server/sonar-web/src/main/js/apps/projectActivity/components/Event.css b/server/sonar-web/src/main/js/apps/projectActivity/components/Event.css new file mode 100644 index 00000000000..0a28479b429 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/projectActivity/components/Event.css @@ -0,0 +1,7 @@ +.project-activity-event { + +} + +.project-activity-event + .project-activity-event { + margin-top: 4px; +} diff --git a/server/sonar-web/src/main/js/apps/projectActivity/components/Event.js b/server/sonar-web/src/main/js/apps/projectActivity/components/Event.js new file mode 100644 index 00000000000..cb0f23613a6 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/projectActivity/components/Event.js @@ -0,0 +1,118 @@ +/* + * 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. + */ +// @flow +import React from 'react'; +import EventInner from './EventInner'; +import ChangeCustomEventForm from './forms/ChangeCustomEventForm'; +import RemoveCustomEventForm from './forms/RemoveCustomEventForm'; +import DeleteIcon from './DeleteIcon'; +import ChangeIcon from './ChangeIcon'; +import type { Event as EventType } from '../../../store/projectActivity/duck'; + +type Props = { + analysis: string, + event: EventType, + isFirst: boolean, + canAdmin: boolean +}; + +type State = { + changing: boolean, + deleting: boolean +}; + +export default class Event extends React.Component { + mounted: boolean; + props: Props; + + state: State = { + changing: false, + deleting: false + }; + + componentDidMount () { + this.mounted = true; + } + + componentWillUnmount () { + this.mounted = false; + } + + startChanging = () => { + this.setState({ changing: true }); + }; + + stopChanging = () => { + if (this.mounted) { + this.setState({ changing: false }); + } + }; + + startDeleting = () => { + this.setState({ deleting: true }); + }; + + stopDeleting = () => { + if (this.mounted) { + this.setState({ deleting: false }); + } + }; + + render () { + const { event, canAdmin } = this.props; + const canChange = ['OTHER', 'VERSION'].includes(event.category); + const canDelete = event.category === 'OTHER' || (event.category === 'VERSION' && !this.props.isFirst); + const showActions = canAdmin && (canChange || canDelete); + + return ( +
    + + + {showActions && ( +
    + {canChange && ( + + )} + {canDelete && ( + + )} +
    + )} + + {this.state.changing && ( + + )} + + {this.state.deleting && ( + + )} +
    + ); + } +} diff --git a/server/sonar-web/src/main/js/apps/overview/events/EventsListFilter.js b/server/sonar-web/src/main/js/apps/projectActivity/components/EventInner.js similarity index 55% rename from server/sonar-web/src/main/js/apps/overview/events/EventsListFilter.js rename to server/sonar-web/src/main/js/apps/projectActivity/components/EventInner.js index cfd142fd3e8..61dbfa32124 100644 --- a/server/sonar-web/src/main/js/apps/overview/events/EventsListFilter.js +++ b/server/sonar-web/src/main/js/apps/projectActivity/components/EventInner.js @@ -17,36 +17,32 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +// @flow import React from 'react'; -import Select from 'react-select'; +import type { Event as EventType } from '../../../store/projectActivity/duck'; import { translate } from '../../../helpers/l10n'; +import './Event.css'; -const TYPES = ['All', 'Version', 'Alert', 'Profile', 'Other']; +export default class EventInner extends React.Component { + props: { + event: EventType + }; -const EventsListFilter = ({ currentFilter, onFilter }) => { - const handleChange = selected => onFilter(selected.value); + render () { + const { event } = this.props; - const options = TYPES.map(type => { - return { - value: type, - label: translate('event.category', type) - }; - }); + if (event.category === 'VERSION') { + return ( + {this.props.event.name} + ); + } - return ( - + + +
    + {translate('project_activity.page.description')} +
    + + ); + } +} diff --git a/server/sonar-web/src/main/js/apps/projectActivity/components/forms/AddCustomEventForm.js b/server/sonar-web/src/main/js/apps/projectActivity/components/forms/AddCustomEventForm.js new file mode 100644 index 00000000000..4d4f287e6f2 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/projectActivity/components/forms/AddCustomEventForm.js @@ -0,0 +1,34 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +// @flow +import React from 'react'; +import { connect } from 'react-redux'; +import { addCustomEvent } from '../../actions'; +import AddEventForm from './AddEventForm'; + +const AddCustomEventForm = props => ( + +); + +const mapStateToProps = null; + +const mapDispatchToProps = { addEvent: addCustomEvent }; + +export default connect(mapStateToProps, mapDispatchToProps)(AddCustomEventForm); diff --git a/server/sonar-web/src/main/js/apps/projectActivity/components/forms/AddEventForm.js b/server/sonar-web/src/main/js/apps/projectActivity/components/forms/AddEventForm.js new file mode 100644 index 00000000000..da895b642b4 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/projectActivity/components/forms/AddEventForm.js @@ -0,0 +1,146 @@ +/* + * 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. + */ +// @flow +import React from 'react'; +import Modal from 'react-modal'; +import type { Analysis } from '../../../../store/projectActivity/duck'; +import { translate } from '../../../../helpers/l10n'; + +type Props = { + addEvent: () => Promise<*>, + analysis: Analysis, + addEventButtonText: string +}; + +type State = { + open: boolean, + processing: boolean; + name: string; +} + +export default class AddEventForm extends React.Component { + mounted: boolean; + props: Props; + + state: State = { + open: false, + processing: false, + name: '' + }; + + componentDidMount () { + this.mounted = true; + } + + componentWillUnmount () { + this.mounted = false; + } + + openForm = (e: Object) => { + e.preventDefault(); + if (this.mounted) { + this.setState({ open: true }); + } + }; + + closeForm = () => { + if (this.mounted) { + this.setState({ open: false, name: '' }); + } + }; + + changeInput = (e: Object) => { + if (this.mounted) { + this.setState({ name: e.target.value }); + } + }; + + stopProcessing = () => { + if (this.mounted) { + this.setState({ processing: false }); + } + }; + + stopProcessingAndClose = () => { + if (this.mounted) { + this.setState({ open: false, processing: false, name: '' }); + } + }; + + handleSubmit = (e: Object) => { + e.preventDefault(); + this.setState({ processing: true }); + this.props.addEvent(this.props.analysis.key, this.state.name) + .then(this.stopProcessingAndClose, this.stopProcessing); + }; + + renderModal () { + return ( + + +
    +

    {translate(this.props.addEventButtonText)}

    +
    + +
    +
    +
    + + +
    +
    + +
    + {this.state.processing ? ( + + ) : ( +
    + + +
    + )} +
    + + +
    + ); + } + + render () { + return ( + + {translate(this.props.addEventButtonText)} + {this.state.open && this.renderModal()} + + ); + } +} diff --git a/server/sonar-web/src/main/js/apps/projectActivity/components/forms/AddVersionForm.js b/server/sonar-web/src/main/js/apps/projectActivity/components/forms/AddVersionForm.js new file mode 100644 index 00000000000..8443d0b45b0 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/projectActivity/components/forms/AddVersionForm.js @@ -0,0 +1,34 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +// @flow +import React from 'react'; +import { connect } from 'react-redux'; +import { addVersion } from '../../actions'; +import AddEventForm from './AddEventForm'; + +const AddVersionForm = props => ( + +); + +const mapStateToProps = null; + +const mapDispatchToProps = { addEvent: addVersion }; + +export default connect(mapStateToProps, mapDispatchToProps)(AddVersionForm); diff --git a/server/sonar-web/src/main/js/apps/projectActivity/components/forms/ChangeCustomEventForm.js b/server/sonar-web/src/main/js/apps/projectActivity/components/forms/ChangeCustomEventForm.js new file mode 100644 index 00000000000..df4a93ebee8 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/projectActivity/components/forms/ChangeCustomEventForm.js @@ -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. + */ +// @flow +import React from 'react'; +import { connect } from 'react-redux'; +import ChangeEventForm from './ChangeEventForm'; +import { changeEvent } from '../../actions'; + +const ChangeCustomEventForm = props => ( + +); + +const mapStateToProps = null; + +const mapDispatchToProps = { changeEvent }; + +export default connect(mapStateToProps, mapDispatchToProps)(ChangeCustomEventForm); diff --git a/server/sonar-web/src/main/js/apps/projectActivity/components/forms/ChangeEventForm.js b/server/sonar-web/src/main/js/apps/projectActivity/components/forms/ChangeEventForm.js new file mode 100644 index 00000000000..8ae9e6b1cb4 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/projectActivity/components/forms/ChangeEventForm.js @@ -0,0 +1,135 @@ +/* + * 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. + */ +// @flow +import React from 'react'; +import Modal from 'react-modal'; +import type { Event } from '../../../../store/projectActivity/duck'; +import { translate } from '../../../../helpers/l10n'; + +type Props = { + changeEvent: () => Promise<*>, + changeEventButtonText: string, + event: Event, + onClose: () => void +}; + +type State = { + processing: boolean, + name: string +} + +export default class ChangeEventForm extends React.Component { + mounted: boolean; + props: Props; + state: State; + + constructor (props: Props) { + super(props); + this.state = { + processing: false, + name: props.event.name + }; + } + + componentDidMount () { + this.mounted = true; + } + + componentWillUnmount () { + this.mounted = false; + } + + closeForm = () => { + if (this.mounted) { + this.setState({ name: this.props.event.name }); + } + this.props.onClose(); + }; + + changeInput = (e: Object) => { + if (this.mounted) { + this.setState({ name: e.target.value }); + } + }; + + stopProcessing = () => { + if (this.mounted) { + this.setState({ processing: false }); + } + }; + + stopProcessingAndClose = () => { + if (this.mounted) { + this.setState({ processing: false }); + } + this.props.onClose(); + }; + + handleSubmit = (e: Object) => { + e.preventDefault(); + this.setState({ processing: true }); + this.props.changeEvent(this.props.event.key, this.state.name) + .then(this.stopProcessingAndClose, this.stopProcessing); + }; + + render () { + return ( + + +
    +

    {translate(this.props.changeEventButtonText)}

    +
    + +
    +
    +
    + + +
    +
    + +
    + {this.state.processing ? ( + + ) : ( +
    + + +
    + )} +
    + + +
    + ); + } +} diff --git a/server/sonar-web/src/main/js/apps/projectActivity/components/forms/ChangeVersionForm.js b/server/sonar-web/src/main/js/apps/projectActivity/components/forms/ChangeVersionForm.js new file mode 100644 index 00000000000..e4a088dbc68 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/projectActivity/components/forms/ChangeVersionForm.js @@ -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. + */ +// @flow +import React from 'react'; +import { connect } from 'react-redux'; +import ChangeEventForm from './ChangeEventForm'; +import { changeEvent } from '../../actions'; + +const ChangeVersionForm = props => ( + +); + +const mapStateToProps = null; + +const mapDispatchToProps = { changeEvent }; + +export default connect(mapStateToProps, mapDispatchToProps)(ChangeVersionForm); diff --git a/server/sonar-web/src/main/js/apps/projectActivity/components/forms/RemoveAnalysisForm.js b/server/sonar-web/src/main/js/apps/projectActivity/components/forms/RemoveAnalysisForm.js new file mode 100644 index 00000000000..482362772ff --- /dev/null +++ b/server/sonar-web/src/main/js/apps/projectActivity/components/forms/RemoveAnalysisForm.js @@ -0,0 +1,136 @@ +/* + * 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. + */ +// @flow +import React from 'react'; +import { connect } from 'react-redux'; +import Modal from 'react-modal'; +import type { Analysis } from '../../../../store/projectActivity/duck'; +import { translate } from '../../../../helpers/l10n'; +import { deleteAnalysis } from '../../actions'; + +type Props = { + analysis: Analysis, + deleteAnalysis: () => Promise<*>, + project: string +}; + +type State = { + open: boolean, + processing: boolean +} + +class RemoveAnalysisForm extends React.Component { + mounted: boolean; + props: Props; + + state: State = { + open: false, + processing: false + }; + + componentDidMount () { + this.mounted = true; + } + + componentWillUnmount () { + this.mounted = false; + } + + openForm = () => { + if (this.mounted) { + this.setState({ open: true }); + } + }; + + closeForm = () => { + if (this.mounted) { + this.setState({ open: false }); + } + }; + + stopProcessing = () => { + if (this.mounted) { + this.setState({ processing: false }); + } + }; + + stopProcessingAndClose = () => { + if (this.mounted) { + this.setState({ open: false, processing: false }); + } + }; + + handleSubmit = (e: Object) => { + e.preventDefault(); + this.setState({ processing: true }); + this.props.deleteAnalysis(this.props.project, this.props.analysis.key) + .then(this.stopProcessingAndClose, this.stopProcessing); + }; + + renderModal () { + return ( + + +
    +

    {translate('project_activity.delete_analysis')}

    +
    + +
    +
    + {translate('project_activity.delete_analysis.question')} +
    + +
    + {this.state.processing ? ( + + ) : ( +
    + + +
    + )} +
    + + +
    + ); + } + + render () { + return ( + + ); + } +} + +const mapStateToProps = null; + +const mapDispatchToProps = { deleteAnalysis }; + +export default connect(mapStateToProps, mapDispatchToProps)(RemoveAnalysisForm); diff --git a/server/sonar-web/src/main/js/apps/projectActivity/components/forms/RemoveCustomEventForm.js b/server/sonar-web/src/main/js/apps/projectActivity/components/forms/RemoveCustomEventForm.js new file mode 100644 index 00000000000..e9679b08207 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/projectActivity/components/forms/RemoveCustomEventForm.js @@ -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. + */ +// @flow +import React from 'react'; +import { connect } from 'react-redux'; +import RemoveEventForm from './RemoveEventForm'; +import { deleteEvent } from '../../actions'; + +const RemoveCustomEventForm = props => ( + +); + +const mapStateToProps = null; + +const mapDispatchToProps = { deleteEvent }; + +export default connect(mapStateToProps, mapDispatchToProps)(RemoveCustomEventForm); diff --git a/server/sonar-web/src/main/js/apps/projectActivity/components/forms/RemoveEventForm.js b/server/sonar-web/src/main/js/apps/projectActivity/components/forms/RemoveEventForm.js new file mode 100644 index 00000000000..893d164b7af --- /dev/null +++ b/server/sonar-web/src/main/js/apps/projectActivity/components/forms/RemoveEventForm.js @@ -0,0 +1,113 @@ +/* + * 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. + */ +// @flow +import React from 'react'; +import Modal from 'react-modal'; +import type { Analysis, Event } from '../../../../store/projectActivity/duck'; +import { translate } from '../../../../helpers/l10n'; + +type Props = { + analysis: Analysis, + deleteEvent: () => Promise<*>, + event: Event, + removeEventButtonText: string, + removeEventQuestion: string, + onClose: () => void +}; + +type State = { + processing: boolean +} + +export default class RemoveVersionForm extends React.Component { + mounted: boolean; + props: Props; + + state: State = { + processing: false + }; + + componentDidMount () { + this.mounted = true; + } + + componentWillUnmount () { + this.mounted = false; + } + + closeForm = () => { + this.props.onClose(); + }; + + stopProcessing = () => { + if (this.mounted) { + this.setState({ processing: false }); + } + }; + + stopProcessingAndClose = () => { + if (this.mounted) { + this.setState({ processing: false }); + } + this.props.onClose(); + }; + + handleSubmit = (e: Object) => { + e.preventDefault(); + this.setState({ processing: true }); + this.props.deleteEvent(this.props.analysis, this.props.event.key) + .then(this.stopProcessingAndClose, this.stopProcessing); + }; + + render () { + return ( + + +
    +

    {translate(this.props.removeEventButtonText)}

    +
    + +
    +
    + {translate(this.props.removeEventQuestion)} +
    + +
    + {this.state.processing ? ( + + ) : ( +
    + + +
    + )} +
    + + +
    + ); + } +} diff --git a/server/sonar-web/src/main/js/apps/projectActivity/components/forms/RemoveVersionForm.js b/server/sonar-web/src/main/js/apps/projectActivity/components/forms/RemoveVersionForm.js new file mode 100644 index 00000000000..8d1d6bc3e50 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/projectActivity/components/forms/RemoveVersionForm.js @@ -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. + */ +// @flow +import React from 'react'; +import { connect } from 'react-redux'; +import RemoveEventForm from './RemoveEventForm'; +import { deleteEvent } from '../../actions'; + +const RemoveVersionForm = props => ( + +); + +const mapStateToProps = null; + +const mapDispatchToProps = { deleteEvent }; + +export default connect(mapStateToProps, mapDispatchToProps)(RemoveVersionForm); diff --git a/server/sonar-web/src/main/js/apps/projectActivity/components/projectActivity.css b/server/sonar-web/src/main/js/apps/projectActivity/components/projectActivity.css new file mode 100644 index 00000000000..79e426e0172 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/projectActivity/components/projectActivity.css @@ -0,0 +1,121 @@ +.project-activity-days-list { + +} + +.project-activity-day { + margin-bottom: 40px; +} + +.project-activity-date { + margin-bottom: 16px; + font-size: 15px; + font-weight: bold; +} + +.project-activity-analyses-list { + +} + +.project-activity-analysis { + position: relative; + min-height: 20px; + padding-top: 6px; + padding-bottom: 6px; + border-top: 1px solid #e6e6e6; + border-bottom: 1px solid #e6e6e6; +} + +.project-activity-analysis:hover { + background-color: #ecf6fe; +} + +.project-activity-analysis + .project-activity-analysis { + border-top: none; +} + +.project-activity-analysis-actions { + float: right; + padding-right: 10px; +} + +.project-activity-analysis-actions:first-child, +.project-activity-analysis-actions:empty { + margin-top: 0; +} + +.project-activity-analysis-actions > button + button, +.project-activity-analysis-actions > button + form, +.project-activity-analysis-actions > form + button, +.project-activity-analysis-actions > form + form { + margin-left: 8px; +} + +.project-activity-analysis-form { + display: inline-block; + vertical-align: top; + line-height: 20px; + margin-bottom: 10px; + padding: 9px; + border: 1px solid #faebcc; + border-radius: 2px; + background-color: #fcf8e3; +} + +.project-activity-analysis-form + .project-activity-analysis-form { + margin-left: 8px; +} + +.project-activity-time { + float: left; + width: 130px; + line-height: 20px; + padding-right: 50px; + box-sizing: border-box; + font-size: 12px; + font-weight: bold; + text-align: right; +} + +.project-activity-time::after { + position: absolute; + z-index: 21; + top: 11px; + left: 100px; + display: block; + width: 10px; + height: 10px; + border: 2px solid #4b9fd5; + border-radius: 10px; + box-sizing: border-box; + content: ""; +} + +.project-activity-events { + overflow: hidden; +} + +.project-activity-event { + line-height: 20px; +} + +.project-activity-event-actions { + display: inline-block; + margin-left: 8px; +} + +.project-activity-event-actions button { + height: 20px; +} + +.project-activity-event-actions button + button { + margin-left: 4px; +} + +.project-activity-version-badge { + vertical-align: middle; + padding: 4px 8px; + border-radius: 2px; + font-weight: bold; + font-size: 12px; + letter-spacing: 0; +} diff --git a/server/sonar-web/src/main/js/apps/projectActivity/routes.js b/server/sonar-web/src/main/js/apps/projectActivity/routes.js new file mode 100644 index 00000000000..a6bb1db8211 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/projectActivity/routes.js @@ -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. + */ +// @flow +import React from 'react'; +import { IndexRoute } from 'react-router'; +import ProjectActivityApp from './components/ProjectActivityApp'; + +export default ( + +); diff --git a/it/it-tests/src/test/java/pageobjects/ProjectHistorySnapshotItem.java b/server/sonar-web/src/main/js/components/ui/FormattedDate.js similarity index 52% rename from it/it-tests/src/test/java/pageobjects/ProjectHistorySnapshotItem.java rename to server/sonar-web/src/main/js/components/ui/FormattedDate.js index d265e98f00b..77949764c73 100644 --- a/it/it-tests/src/test/java/pageobjects/ProjectHistorySnapshotItem.java +++ b/server/sonar-web/src/main/js/components/ui/FormattedDate.js @@ -17,40 +17,32 @@ * 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; +// @flow +import React from 'react'; +import moment from 'moment'; -import com.codeborne.selenide.SelenideElement; -import org.openqa.selenium.NoSuchElementException; +export default class FormattedDate extends React.Component { + props: { + date: string | number, + format?: string, + tooltipFormat?: string + }; -public class ProjectHistorySnapshotItem { + static defaultProps = { + format: 'LLL' + }; - private final SelenideElement elt; + render () { + const { date, format, tooltipFormat } = this.props; - public ProjectHistorySnapshotItem(SelenideElement elt) { - this.elt = elt; - } - - public SelenideElement getVersionText() { - return elt.$("td:nth-child(5) table td:nth-child(1)"); - } - - public SelenideElement getType() { - try { - return elt.$(".js-type"); - } catch (NoSuchElementException e) { - return null; - } - } - - public SelenideElement getUrl() { - return elt.$(".js-url"); - } + const m = moment(date); - public SelenideElement getDeleteButton() { - return elt.$("td:nth-child(9) input[type=\"submit\"]"); - } + const title = tooltipFormat ? m.format(tooltipFormat) : undefined; - public void clickDelete() { - getDeleteButton().click(); + return ( + + ); } } diff --git a/server/sonar-web/src/main/js/store/projectActivity/__tests__/__snapshots__/analyses-test.js.snap b/server/sonar-web/src/main/js/store/projectActivity/__tests__/__snapshots__/analyses-test.js.snap new file mode 100644 index 00000000000..2f807df6231 --- /dev/null +++ b/server/sonar-web/src/main/js/store/projectActivity/__tests__/__snapshots__/analyses-test.js.snap @@ -0,0 +1,93 @@ +exports[`test reducer 1`] = `Object {}`; + +exports[`test reducer 2`] = ` +Object { + "AVgAgC1Vdo07z3PUnnkt": Object { + "date": "2016-10-26T12:17:29+0200", + "events": Array [ + "AVkWNYNYr4pSN7TrXcjY" + ], + "key": "AVgAgC1Vdo07z3PUnnkt" + }, + "AVgFqeOSKpGuA48ADATE": Object { + "date": "2016-10-27T12:21:15+0200", + "events": Array [], + "key": "AVgFqeOSKpGuA48ADATE" + }, + "AVgGkRvCrrTJiPpCD-rG": Object { + "date": "2016-10-27T16:33:50+0200", + "events": Array [ + "AVjUDBiSiXOcXjpycvde" + ], + "key": "AVgGkRvCrrTJiPpCD-rG" + } +} +`; + +exports[`test reducer 3`] = ` +Object { + "AVgAgC1Vdo07z3PUnnkt": Object { + "date": "2016-10-26T12:17:29+0200", + "events": Array [ + "AVkWNYNYr4pSN7TrXcjY" + ], + "key": "AVgAgC1Vdo07z3PUnnkt" + }, + "AVgFqeOSKpGuA48ADATE": Object { + "date": "2016-10-27T12:21:15+0200", + "events": Array [], + "key": "AVgFqeOSKpGuA48ADATE" + }, + "AVgGkRvCrrTJiPpCD-rG": Object { + "date": "2016-10-27T16:33:50+0200", + "events": Array [ + "AVjUDBiSiXOcXjpycvde", + "AVkWcQ8Hr4pSN7TrXcjZ" + ], + "key": "AVgGkRvCrrTJiPpCD-rG" + } +} +`; + +exports[`test reducer 4`] = ` +Object { + "AVgAgC1Vdo07z3PUnnkt": Object { + "date": "2016-10-26T12:17:29+0200", + "events": Array [ + "AVkWNYNYr4pSN7TrXcjY" + ], + "key": "AVgAgC1Vdo07z3PUnnkt" + }, + "AVgFqeOSKpGuA48ADATE": Object { + "date": "2016-10-27T12:21:15+0200", + "events": Array [], + "key": "AVgFqeOSKpGuA48ADATE" + }, + "AVgGkRvCrrTJiPpCD-rG": Object { + "date": "2016-10-27T16:33:50+0200", + "events": Array [ + "AVjUDBiSiXOcXjpycvde" + ], + "key": "AVgGkRvCrrTJiPpCD-rG" + } +} +`; + +exports[`test reducer 5`] = ` +Object { + "AVgAgC1Vdo07z3PUnnkt": Object { + "date": "2016-10-26T12:17:29+0200", + "events": Array [ + "AVkWNYNYr4pSN7TrXcjY" + ], + "key": "AVgAgC1Vdo07z3PUnnkt" + }, + "AVgGkRvCrrTJiPpCD-rG": Object { + "date": "2016-10-27T16:33:50+0200", + "events": Array [ + "AVjUDBiSiXOcXjpycvde" + ], + "key": "AVgGkRvCrrTJiPpCD-rG" + } +} +`; diff --git a/server/sonar-web/src/main/js/store/projectActivity/__tests__/__snapshots__/analysesByProject-test.js.snap b/server/sonar-web/src/main/js/store/projectActivity/__tests__/__snapshots__/analysesByProject-test.js.snap new file mode 100644 index 00000000000..f4fafe25e16 --- /dev/null +++ b/server/sonar-web/src/main/js/store/projectActivity/__tests__/__snapshots__/analysesByProject-test.js.snap @@ -0,0 +1,55 @@ +exports[`test reducer 1`] = `Object {}`; + +exports[`test reducer 2`] = ` +Object { + "project-foo": Array [ + "AVgFqeOSKpGuA48ADATE", + "AVgAgC1Vdo07z3PUnnkt" + ] +} +`; + +exports[`test reducer 3`] = ` +Object { + "project-foo": Array [ + "AVgFqeOSKpGuA48ADATE", + "AVgAgC1Vdo07z3PUnnkt", + "AVgFqeOSKpGuA48ADATX" + ] +} +`; + +exports[`test reducer 4`] = ` +Object { + "project-bar": Array [ + "AVgGkRvCrrTJiPpCD-rG" + ], + "project-foo": Array [ + "AVgFqeOSKpGuA48ADATE", + "AVgAgC1Vdo07z3PUnnkt", + "AVgFqeOSKpGuA48ADATX" + ] +} +`; + +exports[`test reducer 5`] = ` +Object { + "project-bar": Array [ + "AVgGkRvCrrTJiPpCD-rG" + ], + "project-foo": Array [ + "AVgAgC1Vdo07z3PUnnkt", + "AVgFqeOSKpGuA48ADATX" + ] +} +`; + +exports[`test reducer 6`] = ` +Object { + "project-bar": Array [], + "project-foo": Array [ + "AVgAgC1Vdo07z3PUnnkt", + "AVgFqeOSKpGuA48ADATX" + ] +} +`; diff --git a/server/sonar-web/src/main/js/store/projectActivity/__tests__/__snapshots__/duck-test.js.snap b/server/sonar-web/src/main/js/store/projectActivity/__tests__/__snapshots__/duck-test.js.snap new file mode 100644 index 00000000000..c547f468588 --- /dev/null +++ b/server/sonar-web/src/main/js/store/projectActivity/__tests__/__snapshots__/duck-test.js.snap @@ -0,0 +1,75 @@ +exports[`actions addEvent 1`] = ` +Object { + "analysis": "foo", + "event": Object { + "key": "bar" + }, + "type": "ADD_PROJECT_ACTIVITY_EVENT" +} +`; + +exports[`actions changeEvent 1`] = ` +Object { + "changes": Object { + "name": "bar" + }, + "event": "foo", + "type": "CHANGE_PROJECT_ACTIVITY_EVENT" +} +`; + +exports[`actions deleteAnalysis 1`] = ` +Object { + "analysis": "bar", + "project": "foo", + "type": "DELETE_PROJECT_ACTIVITY_ANALYSIS" +} +`; + +exports[`actions deleteEvent 1`] = ` +Object { + "analysis": "foo", + "event": "bar", + "type": "DELETE_PROJECT_ACTIVITY_EVENT" +} +`; + +exports[`selectors getAnalyses 1`] = ` +Array [ + Object { + "date": "2016-10-27T16:33:50+0200", + "events": Array [ + Object { + "category": "VERSION", + "key": "AVjUDBiSiXOcXjpycvde", + "name": "2.18-SNAPSHOT" + } + ], + "key": "AVgGkRvCrrTJiPpCD-rG" + }, + Object { + "date": "2016-10-27T12:21:15+0200", + "events": Array [], + "key": "AVgFqeOSKpGuA48ADATE" + }, + Object { + "date": "2016-10-26T12:17:29+0200", + "events": Array [ + Object { + "category": "OTHER", + "key": "AVkWNYNYr4pSN7TrXcjY", + "name": "foo" + } + ], + "key": "AVgAgC1Vdo07z3PUnnkt" + } +] +`; + +exports[`selectors getPaging 1`] = ` +Object { + "pageIndex": 1, + "pageSize": 100, + "total": 3 +} +`; diff --git a/server/sonar-web/src/main/js/store/projectActivity/__tests__/__snapshots__/events-test.js.snap b/server/sonar-web/src/main/js/store/projectActivity/__tests__/__snapshots__/events-test.js.snap new file mode 100644 index 00000000000..78327b2ddc4 --- /dev/null +++ b/server/sonar-web/src/main/js/store/projectActivity/__tests__/__snapshots__/events-test.js.snap @@ -0,0 +1,71 @@ +exports[`test reducer 1`] = `Object {}`; + +exports[`test reducer 2`] = ` +Object { + "AVjUDBiSiXOcXjpycvde": Object { + "category": "VERSION", + "key": "AVjUDBiSiXOcXjpycvde", + "name": "2.18-SNAPSHOT" + }, + "AVkWNYNYr4pSN7TrXcjY": Object { + "category": "OTHER", + "key": "AVkWNYNYr4pSN7TrXcjY", + "name": "foo" + } +} +`; + +exports[`test reducer 3`] = ` +Object { + "AVjUDBiSiXOcXjpycvde": Object { + "category": "VERSION", + "key": "AVjUDBiSiXOcXjpycvde", + "name": "2.18-SNAPSHOT" + }, + "AVkWNYNYr4pSN7TrXcjY": Object { + "category": "OTHER", + "key": "AVkWNYNYr4pSN7TrXcjY", + "name": "foo" + }, + "AVkWcQ8Hr4pSN7TrXcjZ": Object { + "category": "OTHER", + "key": "AVkWcQ8Hr4pSN7TrXcjZ", + "name": "custom" + } +} +`; + +exports[`test reducer 4`] = ` +Object { + "AVjUDBiSiXOcXjpycvde": Object { + "category": "VERSION", + "key": "AVjUDBiSiXOcXjpycvde", + "name": "2.18-SNAPSHOT" + }, + "AVkWNYNYr4pSN7TrXcjY": Object { + "category": "OTHER", + "key": "AVkWNYNYr4pSN7TrXcjY", + "name": "foo" + }, + "AVkWcQ8Hr4pSN7TrXcjZ": Object { + "category": "OTHER", + "key": "AVkWcQ8Hr4pSN7TrXcjZ", + "name": "new name" + } +} +`; + +exports[`test reducer 5`] = ` +Object { + "AVjUDBiSiXOcXjpycvde": Object { + "category": "VERSION", + "key": "AVjUDBiSiXOcXjpycvde", + "name": "2.18-SNAPSHOT" + }, + "AVkWNYNYr4pSN7TrXcjY": Object { + "category": "OTHER", + "key": "AVkWNYNYr4pSN7TrXcjY", + "name": "foo" + } +} +`; diff --git a/server/sonar-web/src/main/js/store/projectActivity/__tests__/__snapshots__/paging-test.js.snap b/server/sonar-web/src/main/js/store/projectActivity/__tests__/__snapshots__/paging-test.js.snap new file mode 100644 index 00000000000..6c9e8c74492 --- /dev/null +++ b/server/sonar-web/src/main/js/store/projectActivity/__tests__/__snapshots__/paging-test.js.snap @@ -0,0 +1,21 @@ +exports[`test reducer 1`] = `Object {}`; + +exports[`test reducer 2`] = ` +Object { + "project-foo": Object { + "pageIndex": 1, + "pageSize": 100, + "total": 3 + } +} +`; + +exports[`test reducer 3`] = ` +Object { + "project-foo": Object { + "pageIndex": 2, + "pageSize": 30, + "total": 5 + } +} +`; diff --git a/server/sonar-web/src/main/js/store/projectActivity/__tests__/analyses-test.js b/server/sonar-web/src/main/js/store/projectActivity/__tests__/analyses-test.js new file mode 100644 index 00000000000..f53081edd5d --- /dev/null +++ b/server/sonar-web/src/main/js/store/projectActivity/__tests__/analyses-test.js @@ -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 { configureTestStore } from '../../utils/configureStore'; +import analyses, { getAnalysis } from '../analyses'; +import { receiveProjectActivity, addEvent, deleteEvent, deleteAnalysis } from '../duck'; + +const PROJECT = 'project-foo'; + +const ANALYSES = [ + { + key: 'AVgGkRvCrrTJiPpCD-rG', + date: '2016-10-27T16:33:50+0200', + events: [ + { + key: 'AVjUDBiSiXOcXjpycvde', + category: 'VERSION', + name: '2.18-SNAPSHOT' + } + ] + }, + { + key: 'AVgFqeOSKpGuA48ADATE', + date: '2016-10-27T12:21:15+0200', + events: [] + }, + { + key: 'AVgAgC1Vdo07z3PUnnkt', + date: '2016-10-26T12:17:29+0200', + events: [ + { + key: 'AVkWNYNYr4pSN7TrXcjY', + category: 'OTHER', + name: 'foo' + } + ] + } +]; + +const PAGING = { + total: 3, + pageIndex: 1, + pageSize: 100 +}; + +const NEW_EVENT = { + key: 'AVkWcQ8Hr4pSN7TrXcjZ', + category: 'OTHER', + name: 'custom' +}; + +it('reducer', () => { + const store = configureTestStore(analyses); + expect(store.getState()).toMatchSnapshot(); + + store.dispatch(receiveProjectActivity(PROJECT, ANALYSES, PAGING)); + expect(store.getState()).toMatchSnapshot(); + + store.dispatch(addEvent(ANALYSES[0].key, NEW_EVENT)); + expect(store.getState()).toMatchSnapshot(); + + store.dispatch(deleteEvent(ANALYSES[0].key, NEW_EVENT.key)); + expect(store.getState()).toMatchSnapshot(); + + store.dispatch(deleteAnalysis(PROJECT, ANALYSES[1].key)); + expect(store.getState()).toMatchSnapshot(); +}); + +it('selector `getAnalysis`', () => { + const analysis = ANALYSES[0]; + const store = configureTestStore(analyses, { [analysis.key]: analysis }); + expect(getAnalysis(store.getState(), analysis.key)).toBe(analysis); + expect(getAnalysis(store.getState(), 'random')).toBeFalsy(); +}); diff --git a/server/sonar-web/src/main/js/store/projectActivity/__tests__/analysesByProject-test.js b/server/sonar-web/src/main/js/store/projectActivity/__tests__/analysesByProject-test.js new file mode 100644 index 00000000000..c374065dd23 --- /dev/null +++ b/server/sonar-web/src/main/js/store/projectActivity/__tests__/analysesByProject-test.js @@ -0,0 +1,80 @@ +/* + * 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 { configureTestStore } from '../../utils/configureStore'; +import analysesByProject from '../analysesByProject'; +import { receiveProjectActivity, deleteAnalysis } from '../duck'; + +const PROJECT_FOO = 'project-foo'; +const PROJECT_BAR = 'project-bar'; + +const ANALYSES_FOO = [ + { + key: 'AVgFqeOSKpGuA48ADATE', + date: '2016-10-27T12:21:15+0200', + events: [] + }, + { + key: 'AVgAgC1Vdo07z3PUnnkt', + date: '2016-10-26T12:17:29+0200', + events: [] + } +]; + +const ANALYSES_FOO_2 = [ + { + key: 'AVgFqeOSKpGuA48ADATX', + date: '2016-10-27T12:21:15+0200', + events: [] + } +]; + +const ANALYSES_BAR = [ + { + key: 'AVgGkRvCrrTJiPpCD-rG', + date: '2016-10-27T16:33:50+0200', + events: [] + } +]; + +const PAGING = { + total: 3, + pageIndex: 1, + pageSize: 100 +}; + +it('reducer', () => { + const store = configureTestStore(analysesByProject); + expect(store.getState()).toMatchSnapshot(); + + store.dispatch(receiveProjectActivity(PROJECT_FOO, ANALYSES_FOO, PAGING)); + expect(store.getState()).toMatchSnapshot(); + + store.dispatch(receiveProjectActivity(PROJECT_FOO, ANALYSES_FOO_2, { pageIndex: 2 })); + expect(store.getState()).toMatchSnapshot(); + + store.dispatch(receiveProjectActivity(PROJECT_BAR, ANALYSES_BAR, PAGING)); + expect(store.getState()).toMatchSnapshot(); + + store.dispatch(deleteAnalysis(PROJECT_FOO, 'AVgFqeOSKpGuA48ADATE')); + expect(store.getState()).toMatchSnapshot(); + + store.dispatch(deleteAnalysis(PROJECT_BAR, 'AVgGkRvCrrTJiPpCD-rG')); + expect(store.getState()).toMatchSnapshot(); +}); diff --git a/server/sonar-web/src/main/js/store/projectActivity/__tests__/duck-test.js b/server/sonar-web/src/main/js/store/projectActivity/__tests__/duck-test.js new file mode 100644 index 00000000000..5a762840a07 --- /dev/null +++ b/server/sonar-web/src/main/js/store/projectActivity/__tests__/duck-test.js @@ -0,0 +1,100 @@ +/* + * 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 { configureTestStore } from '../../utils/configureStore'; +import reducer, { + receiveProjectActivity, + getAnalyses, + getPaging, + addEvent, + changeEvent, + deleteEvent, + deleteAnalysis +} from '../duck'; + +const PROJECT = 'project-foo'; + +const ANALYSES = [ + { + key: 'AVgGkRvCrrTJiPpCD-rG', + date: '2016-10-27T16:33:50+0200', + events: [ + { + key: 'AVjUDBiSiXOcXjpycvde', + category: 'VERSION', + name: '2.18-SNAPSHOT' + } + ] + }, + { + key: 'AVgFqeOSKpGuA48ADATE', + date: '2016-10-27T12:21:15+0200', + events: [] + }, + { + key: 'AVgAgC1Vdo07z3PUnnkt', + date: '2016-10-26T12:17:29+0200', + events: [ + { + key: 'AVkWNYNYr4pSN7TrXcjY', + category: 'OTHER', + name: 'foo' + } + ] + } +]; + +const PAGING = { + total: 3, + pageIndex: 1, + pageSize: 100 +}; + +describe('actions', () => { + it('addEvent', () => { + expect(addEvent('foo', { key: 'bar' })).toMatchSnapshot(); + }); + + it('changeEvent', () => { + expect(changeEvent('foo', { name: 'bar' })).toMatchSnapshot(); + }); + + it('deleteEvent', () => { + expect(deleteEvent('foo', 'bar')).toMatchSnapshot(); + }); + + it('deleteAnalysis', () => { + expect(deleteAnalysis('foo', 'bar')).toMatchSnapshot(); + }); +}); + + +describe('selectors', () => { + it('getAnalyses', () => { + const store = configureTestStore(reducer); + store.dispatch(receiveProjectActivity(PROJECT, ANALYSES, PAGING)); + expect(getAnalyses(store.getState(), PROJECT)).toMatchSnapshot(); + }); + + it('getPaging', () => { + const store = configureTestStore(reducer); + store.dispatch(receiveProjectActivity(PROJECT, ANALYSES, PAGING)); + expect(getPaging(store.getState(), PROJECT)).toMatchSnapshot(); + }); +}); diff --git a/server/sonar-web/src/main/js/store/projectActivity/__tests__/events-test.js b/server/sonar-web/src/main/js/store/projectActivity/__tests__/events-test.js new file mode 100644 index 00000000000..fc95135a07a --- /dev/null +++ b/server/sonar-web/src/main/js/store/projectActivity/__tests__/events-test.js @@ -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 { configureTestStore } from '../../utils/configureStore'; +import events, { getEvent } from '../events'; +import { receiveProjectActivity, addEvent, changeEvent, deleteEvent } from '../duck'; + +const PROJECT = 'project-foo'; + +const ANALYSES = [ + { + key: 'AVgGkRvCrrTJiPpCD-rG', + date: '2016-10-27T16:33:50+0200', + events: [ + { + key: 'AVjUDBiSiXOcXjpycvde', + category: 'VERSION', + name: '2.18-SNAPSHOT' + } + ] + }, + { + key: 'AVgFqeOSKpGuA48ADATE', + date: '2016-10-27T12:21:15+0200', + events: [] + }, + { + key: 'AVgAgC1Vdo07z3PUnnkt', + date: '2016-10-26T12:17:29+0200', + events: [ + { + key: 'AVkWNYNYr4pSN7TrXcjY', + category: 'OTHER', + name: 'foo' + } + ] + } +]; + +const PAGING = { + total: 3, + pageIndex: 1, + pageSize: 100 +}; + +const NEW_EVENT = { + key: 'AVkWcQ8Hr4pSN7TrXcjZ', + category: 'OTHER', + name: 'custom' +}; + +it('reducer', () => { + const store = configureTestStore(events); + expect(store.getState()).toMatchSnapshot(); + + store.dispatch(receiveProjectActivity(PROJECT, ANALYSES, PAGING)); + expect(store.getState()).toMatchSnapshot(); + + store.dispatch(addEvent(ANALYSES[0].key, NEW_EVENT)); + expect(store.getState()).toMatchSnapshot(); + + store.dispatch(changeEvent(NEW_EVENT.key, { name: 'new name' })); + expect(store.getState()).toMatchSnapshot(); + + store.dispatch(deleteEvent(ANALYSES[0].key, NEW_EVENT.key)); + expect(store.getState()).toMatchSnapshot(); +}); + +it('selector `getEvent`', () => { + const event = ANALYSES[0].events[0]; + const store = configureTestStore(events, { [event.key]: event }); + expect(getEvent(store.getState(), event.key)).toBe(event); + expect(getEvent(store.getState(), 'random')).toBeFalsy(); +}); diff --git a/server/sonar-web/src/main/js/store/projectActivity/__tests__/paging-test.js b/server/sonar-web/src/main/js/store/projectActivity/__tests__/paging-test.js new file mode 100644 index 00000000000..11f285a0f34 --- /dev/null +++ b/server/sonar-web/src/main/js/store/projectActivity/__tests__/paging-test.js @@ -0,0 +1,49 @@ +/* + * 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 { configureTestStore } from '../../utils/configureStore'; +import paging from '../paging'; +import { receiveProjectActivity } from '../duck'; + +const PROJECT = 'project-foo'; + +const ANALYSES = []; + +const PAGING_1 = { + total: 3, + pageIndex: 1, + pageSize: 100 +}; + +const PAGING_2 = { + total: 5, + pageIndex: 2, + pageSize: 30 +}; + +it('reducer', () => { + const store = configureTestStore(paging); + expect(store.getState()).toMatchSnapshot(); + + store.dispatch(receiveProjectActivity(PROJECT, ANALYSES, PAGING_1)); + expect(store.getState()).toMatchSnapshot(); + + store.dispatch(receiveProjectActivity(PROJECT, ANALYSES, PAGING_2)); + expect(store.getState()).toMatchSnapshot(); +}); diff --git a/server/sonar-web/src/main/js/store/projectActivity/analyses.js b/server/sonar-web/src/main/js/store/projectActivity/analyses.js new file mode 100644 index 00000000000..b60abff4b23 --- /dev/null +++ b/server/sonar-web/src/main/js/store/projectActivity/analyses.js @@ -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. + */ +// @flow +import keyBy from 'lodash/keyBy'; +import type { + Action, + ReceiveProjectActivityAction, + AddEventAction, + DeleteEventAction, + DeleteAnalysisAction +} from './duck'; + +type Analysis = { + key: string; + date: string; + events: Array +}; + +export type State = { + [key: string]: Analysis +}; + +const receiveProjectActivity = (state: State, action: ReceiveProjectActivityAction): State => { + const analysesWithFlatEvents = action.analyses.map(analysis => ({ + ...analysis, + events: analysis.events.map(event => event.key) + })); + return { ...state, ...keyBy(analysesWithFlatEvents, 'key') }; +}; + +const addEvent = (state: State, action: AddEventAction): State => { + const analysis = state[action.analysis]; + const newAnalysis = { + ...analysis, + events: [...analysis.events, action.event.key] + }; + return { ...state, [action.analysis]: newAnalysis }; +}; + +const deleteEvent = (state: State, action: DeleteEventAction): State => { + const analysis = state[action.analysis]; + const newAnalysis = { + ...analysis, + events: analysis.events.filter(event => event !== action.event) + }; + return { ...state, [action.analysis]: newAnalysis }; +}; + +const deleteAnalysis = (state: State, action: DeleteAnalysisAction): State => { + const newState = { ...state }; + delete newState[action.analysis]; + return newState; +}; + +export default (state: State = {}, action: Action): State => { + switch (action.type) { + case 'RECEIVE_PROJECT_ACTIVITY': + return receiveProjectActivity(state, action); + case 'ADD_PROJECT_ACTIVITY_EVENT': + return addEvent(state, action); + case 'DELETE_PROJECT_ACTIVITY_EVENT': + return deleteEvent(state, action); + case 'DELETE_PROJECT_ACTIVITY_ANALYSIS': + return deleteAnalysis(state, action); + default: + return state; + } +}; + +export const getAnalysis = (state: State, key: string): Analysis => ( + state[key] +); diff --git a/server/sonar-web/src/main/js/store/projectActivity/analysesByProject.js b/server/sonar-web/src/main/js/store/projectActivity/analysesByProject.js new file mode 100644 index 00000000000..d5eb2fc7315 --- /dev/null +++ b/server/sonar-web/src/main/js/store/projectActivity/analysesByProject.js @@ -0,0 +1,53 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +// @flow +import type { Action, ReceiveProjectActivityAction, DeleteAnalysisAction } from './duck'; + +export type State = { + [key: string]: Array +}; + +const receiveProjectActivity = (state: State, action: ReceiveProjectActivityAction): State => { + const analyses = state[action.project] || []; + const newAnalyses = action.analyses.map(analysis => analysis.key); + return { + ...state, + [action.project]: action.paging.pageIndex === 1 ? newAnalyses : [...analyses, ...newAnalyses] + }; +}; + +const deleteAnalysis = (state: State, action: DeleteAnalysisAction): State => { + const analyses = state[action.project]; + return { + ...state, + [action.project]: analyses.filter(key => key !== action.analysis) + }; +}; + +export default (state: State = {}, action: Action): State => { + switch (action.type) { + case 'RECEIVE_PROJECT_ACTIVITY': + return receiveProjectActivity(state, action); + case 'DELETE_PROJECT_ACTIVITY_ANALYSIS': + return deleteAnalysis(state, action); + default: + return state; + } +}; diff --git a/server/sonar-web/src/main/js/store/projectActivity/duck.js b/server/sonar-web/src/main/js/store/projectActivity/duck.js new file mode 100644 index 00000000000..00ddb08b6d2 --- /dev/null +++ b/server/sonar-web/src/main/js/store/projectActivity/duck.js @@ -0,0 +1,148 @@ +/* + * 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. + */ +// @flow +import { combineReducers } from 'redux'; +import analyses, * as fromAnalyses from './analyses'; +import type { State as AnalysesState } from './analyses'; +import analysesByProject from './analysesByProject'; +import type { State as AnalysesByProjectState } from './analysesByProject'; +import events, * as fromEvents from './events'; +import type { State as EventsState } from './events'; +import paging from './paging'; +import type { State as PagingState } from './paging'; + +export type Event = { + key: string, + name: string; + category: string; + description?: string; +}; + +export type Analysis = { + key: string; + date: string; + events: Array +}; + +export type Paging = { + total: number, + pageIndex: number, + pageSize: number +}; + +export type ReceiveProjectActivityAction = { + type: 'RECEIVE_PROJECT_ACTIVITY', + project: string, + analyses: Array, + paging: Paging +}; + +export type AddEventAction = { + type: 'ADD_PROJECT_ACTIVITY_EVENT', + analysis: string, + event: Event +}; + +export type DeleteEventAction = { + type: 'DELETE_PROJECT_ACTIVITY_EVENT', + analysis: string, + event: string +}; + +export type ChangeEventAction = { + type: 'CHANGE_PROJECT_ACTIVITY_EVENT', + event: string, + changes: Object +}; + +export type DeleteAnalysisAction = { + type: 'DELETE_PROJECT_ACTIVITY_ANALYSIS', + project: string, + analysis: string +}; + +export type Action = + ReceiveProjectActivityAction | + AddEventAction | + DeleteEventAction | + ChangeEventAction | + DeleteAnalysisAction; + +export const receiveProjectActivity = ( + project: string, + analyses: Array, + paging: Paging +): ReceiveProjectActivityAction => ({ + type: 'RECEIVE_PROJECT_ACTIVITY', + project, + analyses, + paging +}); + +export const addEvent = (analysis: string, event: Event): AddEventAction => ({ + type: 'ADD_PROJECT_ACTIVITY_EVENT', + analysis, + event +}); + +export const deleteEvent = (analysis: string, event: string): DeleteEventAction => ({ + type: 'DELETE_PROJECT_ACTIVITY_EVENT', + analysis, + event +}); + +export const changeEvent = (event: string, changes: Object): ChangeEventAction => ({ + type: 'CHANGE_PROJECT_ACTIVITY_EVENT', + event, + changes +}); + +export const deleteAnalysis = (project: string, analysis: string): DeleteAnalysisAction => ({ + type: 'DELETE_PROJECT_ACTIVITY_ANALYSIS', + project, + analysis +}); + +type State = { + analyses: AnalysesState, + analysesByProject: AnalysesByProjectState, + events: EventsState, + filter: string, + paging: PagingState, +}; + +export default combineReducers({ analyses, analysesByProject, events, paging }); + +const getEvent = (state: State, key: string): Event => ( + fromEvents.getEvent(state.events, key) +); + +const getAnalysis = (state: State, key: string) => { + const analysis = fromAnalyses.getAnalysis(state.analyses, key); + const events: Array = analysis.events.map(key => getEvent(state, key)); + return { ...analysis, events }; +}; + +export const getAnalyses = (state: State, project: string) => ( + state.analysesByProject[project] && state.analysesByProject[project].map(key => getAnalysis(state, key)) +); +export const getPaging = (state: State, project: string) => ( + state.paging[project] +); diff --git a/server/sonar-web/src/main/js/store/projectActivity/events.js b/server/sonar-web/src/main/js/store/projectActivity/events.js new file mode 100644 index 00000000000..88e6fc27b26 --- /dev/null +++ b/server/sonar-web/src/main/js/store/projectActivity/events.js @@ -0,0 +1,79 @@ +/* + * 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. + */ +// @flow +import keyBy from 'lodash/keyBy'; +import type { + Action, + ReceiveProjectActivityAction, + AddEventAction, + DeleteEventAction, + ChangeEventAction +} from './duck'; + +export type State = { + [key: string]: { + key: string, + name: string; + category: string; + description?: string; + } +}; + +const receiveProjectActivity = (state: State, action: ReceiveProjectActivityAction): State => { + const events = {}; + action.analyses.forEach(analysis => { + Object.assign(events, keyBy(analysis.events, 'key')); + }); + return { ...state, ...events }; +}; + +const addEvent = (state: State, action: AddEventAction): State => { + return { ...state, [action.event.key]: action.event }; +}; + +const deleteEvent = (state: State, action: DeleteEventAction): State => { + const newState = { ...state }; + delete newState[action.event]; + return newState; +}; + +const changeEvent = (state: State, action: ChangeEventAction): State => { + const newEvent = { ...state[action.event], ...action.changes }; + return { ...state, [action.event]: newEvent }; +}; + +export default (state: State = {}, action: Action): State => { + switch (action.type) { + case 'RECEIVE_PROJECT_ACTIVITY': + return receiveProjectActivity(state, action); + case 'ADD_PROJECT_ACTIVITY_EVENT': + return addEvent(state, action); + case 'DELETE_PROJECT_ACTIVITY_EVENT': + return deleteEvent(state, action); + case 'CHANGE_PROJECT_ACTIVITY_EVENT': + return changeEvent(state, action); + default: + return state; + } +}; + +export const getEvent = (state: State, key: string) => ( + state[key] +); diff --git a/server/sonar-web/src/main/js/store/projectActivity/paging.js b/server/sonar-web/src/main/js/store/projectActivity/paging.js new file mode 100644 index 00000000000..46287a1183c --- /dev/null +++ b/server/sonar-web/src/main/js/store/projectActivity/paging.js @@ -0,0 +1,34 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +// @flow +import type { Paging, ReceiveProjectActivityAction } from './duck'; + +export type State = { + [key: string]: Paging +}; + +export default (state: State = {}, action: ReceiveProjectActivityAction): State => { + if (action.type === 'RECEIVE_PROJECT_ACTIVITY') { + return { ...state, [action.project]: action.paging }; + } + + return state; +}; + diff --git a/server/sonar-web/src/main/js/store/rootActions.js b/server/sonar-web/src/main/js/store/rootActions.js index 005c1158025..c6408588568 100644 --- a/server/sonar-web/src/main/js/store/rootActions.js +++ b/server/sonar-web/src/main/js/store/rootActions.js @@ -26,7 +26,7 @@ import { addGlobalErrorMessage } from './globalMessages/duck'; import { parseError } from '../apps/code/utils'; import { setAppState } from './appState/duck'; -const onFail = dispatch => error => ( +export const onFail = dispatch => error => ( parseError(error).then(message => dispatch(addGlobalErrorMessage(message))) ); diff --git a/server/sonar-web/src/main/js/store/rootReducer.js b/server/sonar-web/src/main/js/store/rootReducer.js index 1a9e8793369..c7d223c78bf 100644 --- a/server/sonar-web/src/main/js/store/rootReducer.js +++ b/server/sonar-web/src/main/js/store/rootReducer.js @@ -25,6 +25,7 @@ import favorites, * as fromFavorites from './favorites/duck'; import languages, * as fromLanguages from './languages/reducer'; import measures, * as fromMeasures from './measures/reducer'; import globalMessages, * as fromGlobalMessages from './globalMessages/duck'; +import projectActivity from './projectActivity/duck'; import measuresApp, * as fromMeasuresApp from '../apps/component-measures/store/rootReducer'; import permissionsApp, * as fromPermissionsApp from '../apps/permissions/shared/store/rootReducer'; @@ -40,6 +41,7 @@ export default combineReducers({ favorites, languages, measures, + projectActivity, users, // apps @@ -83,6 +85,10 @@ export const getComponentMeasures = (state, componentKey) => ( fromMeasures.getComponentMeasures(state.measures, componentKey) ); +export const getProjectActivity = state => ( + state.projectActivity +); + export const getProjects = state => ( fromProjectsApp.getProjects(state.projectsApp) ); diff --git a/server/sonar-web/src/main/js/store/utils/configureStore.js b/server/sonar-web/src/main/js/store/utils/configureStore.js index 97397d836cd..361edd2dc18 100644 --- a/server/sonar-web/src/main/js/store/utils/configureStore.js +++ b/server/sonar-web/src/main/js/store/utils/configureStore.js @@ -38,3 +38,7 @@ const finalCreateStore = compose( export default function configureStore (rootReducer, initialState) { return finalCreateStore(rootReducer, initialState); } + +export const configureTestStore = (rootReducer, initialState) => ( + createStore(rootReducer, initialState) +); diff --git a/server/sonar-web/src/main/less/components/modals.less b/server/sonar-web/src/main/less/components/modals.less index 241364a6066..bc771a5d25b 100644 --- a/server/sonar-web/src/main/less/components/modals.less +++ b/server/sonar-web/src/main/less/components/modals.less @@ -20,7 +20,8 @@ @import (reference) "../mixins"; @import (reference) "../variables"; -.modal { +.modal, +.ReactModal__Content { position: fixed; z-index: @modal-z-index; top: 0; @@ -32,7 +33,8 @@ transition: all 0.2s ease; } -.modal.in { +.modal.in, +.ReactModal__Content--after-open { top: 15%; opacity: 1; } @@ -42,20 +44,26 @@ margin-left: -45vw; } -.modal-overlay { +.modal-overlay, +.ReactModal__Overlay { position: fixed; z-index: @modal-overlay-z-index; - top: 0; bottom: 0; left: 0; right: 0; + top: 0; + bottom: 0; + left: 0; + right: 0; background-color: rgba(0, 0, 0, 0.7); opacity: 0; transition: all 0.2s ease; } -.modal-overlay.in { +.modal-overlay.in, +.ReactModal__Overlay--after-open { opacity: 1; } -.modal-open { +.modal-open, +.ReactModal__Body--open { overflow: hidden; } @@ -69,8 +77,8 @@ .modal-head { padding: 0 10px; - background-color: #EFEFEF; - border-bottom: 1px solid #DDD; + background-color: #efefef; + border-bottom: 1px solid #ddd; } .modal-head h1, .modal-head h2 { @@ -167,9 +175,9 @@ ul.modal-head-metadata li { .modal-foot { text-align: right; padding: 8px 10px; - border-top: 1px solid #CCC; + border-top: 1px solid #ccc; line-height: 30px; - background-color: #EFEFEF; + background-color: #efefef; button, .button, diff --git a/server/sonar-web/src/main/less/init/forms.less b/server/sonar-web/src/main/less/init/forms.less index 4de11a1c3e8..43748629980 100644 --- a/server/sonar-web/src/main/less/init/forms.less +++ b/server/sonar-web/src/main/less/init/forms.less @@ -152,7 +152,6 @@ input[type="submit"].button-success { .button-clean, .button-clean:hover, .button-clean:focus { - margin: 0; padding: 0; line-height: 1; border: none; @@ -161,6 +160,14 @@ input[type="submit"].button-success { color: @baseFontColor; } +.button-clean path { + transition: opacity 0.3s ease; +} + +.button-clean:hover path { + opacity: 0.8; +} + .button-link { display: inline; height: auto; @@ -189,6 +196,15 @@ input[type="submit"].button-success { } } +.button-small { + height: 20px; + line-height: 18px; + + & > svg { + margin-top: 2px; + } +} + .button-group { display: inline-block; vertical-align: middle; diff --git a/server/sonar-web/yarn.lock b/server/sonar-web/yarn.lock index fbe676ea9aa..2ba39576c43 100644 --- a/server/sonar-web/yarn.lock +++ b/server/sonar-web/yarn.lock @@ -1,5 +1,11 @@ # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. # yarn lockfile v1 + + +Base64@~0.2.0: + version "0.2.1" + resolved "https://registry.yarnpkg.com/Base64/-/Base64-0.2.1.tgz#ba3a4230708e186705065e66babdd4c35cf60028" + abab@^1.0.0: version "1.0.3" resolved "https://registry.yarnpkg.com/abab/-/abab-1.0.3.tgz#b81de5f7274ec4e756d797cd834f303642724e5d" @@ -187,14 +193,14 @@ async-each@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d" +async@1.x, async@^1.3.0, async@^1.4.0, async@^1.4.2, async@^1.5.0: + version "1.5.2" + resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" + async@^0.9.0: version "0.9.2" resolved "https://registry.yarnpkg.com/async/-/async-0.9.2.tgz#aea74d5e61c1f899613bf64bda66d4c78f2fd17d" -async@^1.3.0, async@^1.4.0, async@^1.4.2, async@^1.5.0, async@1.x: - version "1.5.2" - resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" - async@~0.2.10, async@~0.2.6: version "0.2.10" resolved "https://registry.yarnpkg.com/async/-/async-0.2.10.tgz#b6bbe0b0674b9d719708ca38de8c237cb526c3d1" @@ -203,18 +209,7 @@ asynckit@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" -autoprefixer@^6.3.1: - version "6.5.3" - resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-6.5.3.tgz#2d853af66d04449fcf50db3066279ab54c3e4b01" - dependencies: - browserslist "~1.4.0" - caniuse-db "^1.0.30000578" - normalize-range "^0.1.2" - num2fraction "^1.2.2" - postcss "^5.2.5" - postcss-value-parser "^3.2.3" - -autoprefixer@6.4.1: +autoprefixer@6.4.1, autoprefixer@^6.3.1: version "6.4.1" resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-6.4.1.tgz#c1ba8461759faf5fb7737dbdbe5ea46a78c68a6f" dependencies: @@ -241,31 +236,7 @@ babel-code-frame@^6.20.0, babel-code-frame@^6.8.0: esutils "^2.0.2" js-tokens "^2.0.0" -babel-core@^6.0.0, babel-core@^6.11.4, babel-core@^6.14.0, babel-core@^6.18.0: - version "6.20.0" - resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-6.20.0.tgz#ab0d7176d9dea434e66badadaf92237865eab1ec" - dependencies: - babel-code-frame "^6.20.0" - babel-generator "^6.20.0" - babel-helpers "^6.16.0" - babel-messages "^6.8.0" - babel-register "^6.18.0" - babel-runtime "^6.20.0" - babel-template "^6.16.0" - babel-traverse "^6.20.0" - babel-types "^6.20.0" - babylon "^6.11.0" - convert-source-map "^1.1.0" - debug "^2.1.1" - json5 "^0.5.0" - lodash "^4.2.0" - minimatch "^3.0.2" - path-is-absolute "^1.0.0" - private "^0.1.6" - slash "^1.0.0" - source-map "^0.5.0" - -babel-core@6.14.0: +babel-core@6.14.0, babel-core@^6.0.0: version "6.14.0" resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-6.14.0.tgz#c9e13ed4e2f97329215496fd9fb48f2b3bcb9b42" dependencies: @@ -291,6 +262,30 @@ babel-core@6.14.0: slash "^1.0.0" source-map "^0.5.0" +babel-core@^6.11.4, babel-core@^6.14.0, babel-core@^6.18.0: + version "6.20.0" + resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-6.20.0.tgz#ab0d7176d9dea434e66badadaf92237865eab1ec" + dependencies: + babel-code-frame "^6.20.0" + babel-generator "^6.20.0" + babel-helpers "^6.16.0" + babel-messages "^6.8.0" + babel-register "^6.18.0" + babel-runtime "^6.20.0" + babel-template "^6.16.0" + babel-traverse "^6.20.0" + babel-types "^6.20.0" + babylon "^6.11.0" + convert-source-map "^1.1.0" + debug "^2.1.1" + json5 "^0.5.0" + lodash "^4.2.0" + minimatch "^3.0.2" + path-is-absolute "^1.0.0" + private "^0.1.6" + slash "^1.0.0" + source-map "^0.5.0" + babel-eslint@6.1.2: version "6.1.2" resolved "https://registry.yarnpkg.com/babel-eslint/-/babel-eslint-6.1.2.tgz#5293419fe3672d66598d327da9694567ba6a5f2f" @@ -423,7 +418,7 @@ babel-helpers@^6.16.0, babel-helpers@^6.8.0: babel-runtime "^6.0.0" babel-template "^6.16.0" -babel-jest@^15.0.0, babel-jest@15.0.0: +babel-jest@15.0.0, babel-jest@^15.0.0: version "15.0.0" resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-15.0.0.tgz#6a9e2e3999f241383db9ab1e2ef6704401d74242" dependencies: @@ -711,14 +706,14 @@ babel-plugin-transform-react-display-name@^6.3.13: dependencies: babel-runtime "^6.0.0" -babel-plugin-transform-react-jsx-self@^6.11.0, babel-plugin-transform-react-jsx-self@6.11.0: +babel-plugin-transform-react-jsx-self@6.11.0, babel-plugin-transform-react-jsx-self@^6.11.0: version "6.11.0" resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-jsx-self/-/babel-plugin-transform-react-jsx-self-6.11.0.tgz#605c9450c1429f97a930f7e1dfe3f0d9d0dbd0f4" dependencies: babel-plugin-syntax-jsx "^6.8.0" babel-runtime "^6.9.0" -babel-plugin-transform-react-jsx-source@^6.3.13, babel-plugin-transform-react-jsx-source@6.9.0: +babel-plugin-transform-react-jsx-source@6.9.0, babel-plugin-transform-react-jsx-source@^6.3.13: version "6.9.0" resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-jsx-source/-/babel-plugin-transform-react-jsx-source-6.9.0.tgz#af684a05c2067a86e0957d4f343295ccf5dccf00" dependencies: @@ -733,12 +728,6 @@ babel-plugin-transform-react-jsx@^6.3.13: babel-plugin-syntax-jsx "^6.8.0" babel-runtime "^6.0.0" -babel-plugin-transform-regenerator@^6.16.0: - version "6.20.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.20.0.tgz#a546cd2aa1c9889929d5c427a31303847847ab75" - dependencies: - regenerator-transform "0.9.8" - babel-plugin-transform-regenerator@6.14.0: version "6.14.0" resolved "https://registry.yarnpkg.com/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.14.0.tgz#119119b20c8b4283f6c77f0170d404c3c654bec8" @@ -753,6 +742,12 @@ babel-plugin-transform-regenerator@6.14.0: babylon "^6.9.0" private "~0.1.5" +babel-plugin-transform-regenerator@^6.16.0: + version "6.20.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.20.0.tgz#a546cd2aa1c9889929d5c427a31303847847ab75" + dependencies: + regenerator-transform "0.9.8" + babel-plugin-transform-runtime@6.15.0: version "6.15.0" resolved "https://registry.yarnpkg.com/babel-plugin-transform-runtime/-/babel-plugin-transform-runtime-6.15.0.tgz#3d75b4d949ad81af157570273846fb59aeb0d57c" @@ -873,6 +868,13 @@ babel-register@^6.14.0, babel-register@^6.18.0: mkdirp "^0.5.1" source-map-support "^0.4.2" +babel-runtime@6.11.6: + version "6.11.6" + resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.11.6.tgz#6db707fef2d49c49bfa3cb64efdb436b518b8222" + dependencies: + core-js "^2.4.0" + regenerator-runtime "^0.9.5" + babel-runtime@^5.0.0: version "5.8.38" resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-5.8.38.tgz#1c0b02eb63312f5f087ff20450827b425c9d4c19" @@ -886,13 +888,6 @@ babel-runtime@^6.0.0, babel-runtime@^6.11.6, babel-runtime@^6.18.0, babel-runtim core-js "^2.4.0" regenerator-runtime "^0.10.0" -babel-runtime@6.11.6: - version "6.11.6" - resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.11.6.tgz#6db707fef2d49c49bfa3cb64efdb436b518b8222" - dependencies: - core-js "^2.4.0" - regenerator-runtime "^0.9.5" - babel-template@^6.14.0, babel-template@^6.15.0, babel-template@^6.16.0, babel-template@^6.8.0: version "6.16.0" resolved "https://registry.yarnpkg.com/babel-template/-/babel-template-6.16.0.tgz#e149dd1a9f03a35f817ddbc4d0481988e7ebc8ca" @@ -953,13 +948,7 @@ backbone.wreqr@^1.0.0: backbone ">=0.9.9 <=1.3.x" underscore ">=1.3.3 <=1.8.3" -"backbone@>=0.9.9 <=1.3.x": - version "1.3.3" - resolved "https://registry.yarnpkg.com/backbone/-/backbone-1.3.3.tgz#4cc80ea7cb1631ac474889ce40f2f8bc683b2999" - dependencies: - underscore ">=1.8.3" - -"backbone@1.0.0 - 1.2.3", backbone@1.2.3: +"backbone@1.0.0 - 1.2.3", backbone@1.2.3, "backbone@>=0.9.9 <=1.3.x": version "1.2.3" resolved "https://registry.yarnpkg.com/backbone/-/backbone-1.2.3.tgz#c22cfd07fc86ebbeae61d18929ed115e999d65b9" dependencies: @@ -973,10 +962,6 @@ base64-js@^1.0.2: version "1.2.0" resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.2.0.tgz#a39992d723584811982be5e290bb6a53d86700f1" -Base64@~0.2.0: - version "0.2.1" - resolved "https://registry.yarnpkg.com/Base64/-/Base64-0.2.1.tgz#ba3a4230708e186705065e66babdd4c35cf60028" - batch@0.5.3: version "0.5.3" resolved "https://registry.yarnpkg.com/batch/-/batch-0.5.3.tgz#3f3414f380321743bfc1042f9a83ff1d5824d464" @@ -1052,12 +1037,6 @@ browserslist@~1.3.6: dependencies: caniuse-db "^1.0.30000525" -browserslist@~1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-1.4.0.tgz#9cfdcf5384d9158f5b70da2aa00b30e8ff019049" - dependencies: - caniuse-db "^1.0.30000539" - bser@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/bser/-/bser-1.0.2.tgz#381116970b2a6deea5646dd15dd7278444b56169" @@ -1117,7 +1096,7 @@ camelcase@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-3.0.0.tgz#32fc4b9fcdaf845fcdf7e73bb97cac2261f0ab0a" -caniuse-db@^1.0.30000525, caniuse-db@^1.0.30000527, caniuse-db@^1.0.30000539, caniuse-db@^1.0.30000578: +caniuse-db@^1.0.30000525, caniuse-db@^1.0.30000527: version "1.0.30000597" resolved "https://registry.yarnpkg.com/caniuse-db/-/caniuse-db-1.0.30000597.tgz#b52e6cbe9dc83669affb98501629feaee1af6588" @@ -1143,7 +1122,7 @@ center-align@^0.1.1: align-text "^0.1.3" lazy-cache "^1.0.3" -chalk@^1.0.0, chalk@^1.1.0, chalk@^1.1.1, chalk@^1.1.3, chalk@1.1.3: +chalk@1.1.3, chalk@^1.0.0, chalk@^1.1.0, chalk@^1.1.1, chalk@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" dependencies: @@ -1190,14 +1169,14 @@ clap@^1.0.9: dependencies: chalk "^1.1.3" -classnames@^2.2.3: - version "2.2.5" - resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.2.5.tgz#fb3801d453467649ef3603c7d61a02bd129bde6d" - classnames@2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.2.0.tgz#8f61df81f356c45d18a31d83fde4dfb194ea8722" +classnames@^2.2.3: + version "2.2.5" + resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.2.5.tgz#fb3801d453467649ef3603c7d61a02bd129bde6d" + clean-css@3.4.x: version "3.4.21" resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-3.4.21.tgz#2101d5dbd19d63dbc16a75ebd570e7c33948f65b" @@ -1302,29 +1281,29 @@ colormin@^1.0.5: css-color-names "0.0.4" has "^1.0.1" -colors@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/colors/-/colors-1.1.2.tgz#168a4701756b6a7f51a12ce0c97bfa28c084ed63" - colors@1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/colors/-/colors-1.0.3.tgz#0433f44d809680fdeb60ed260f1b0c262e82a40b" +colors@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/colors/-/colors-1.1.2.tgz#168a4701756b6a7f51a12ce0c97bfa28c084ed63" + combined-stream@^1.0.5, combined-stream@~1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.5.tgz#938370a57b4a51dea2c77c15d5c5fdf895164009" dependencies: delayed-stream "~1.0.0" -commander@^2.9.0, commander@2.9.x: - version "2.9.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.9.0.tgz#9c99094176e12240cb22d6c5146098400fe0f7d4" +commander@2.8.x, commander@~2.8.1: + version "2.8.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.8.1.tgz#06be367febfda0c330aa1e2a072d3dc9762425d4" dependencies: graceful-readlink ">= 1.0.0" -commander@~2.8.1, commander@2.8.x: - version "2.8.1" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.8.1.tgz#06be367febfda0c330aa1e2a072d3dc9762425d4" +commander@2.9.x, commander@^2.9.0: + version "2.9.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.9.0.tgz#9c99094176e12240cb22d6c5146098400fe0f7d4" dependencies: graceful-readlink ">= 1.0.0" @@ -1361,7 +1340,7 @@ concat-stream@^1.4.6: readable-stream "~2.0.0" typedarray "~0.0.5" -connect-history-api-fallback@^1.3.0, connect-history-api-fallback@1.3.0: +connect-history-api-fallback@1.3.0, connect-history-api-fallback@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/connect-history-api-fallback/-/connect-history-api-fallback-1.3.0.tgz#e51d17f8f0ef0db90a64fdb47de3051556e9f169" @@ -1391,7 +1370,7 @@ content-type-parser@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/content-type-parser/-/content-type-parser-1.0.1.tgz#c3e56988c53c65127fb46d4032a3a900246fdc94" -content-type@~1.0.1, content-type@~1.0.2: +content-type@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.2.tgz#b7d113aee7a8dd27bd21133c4dc2529df1721eed" @@ -1407,10 +1386,6 @@ cookie@0.1.5: version "0.1.5" resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.1.5.tgz#6ab9948a4b1ae21952cd2588530a4722d4044d7c" -cookie@0.3.1: - version "0.3.1" - resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb" - core-js@^1.0.0, core-js@^1.0.1: version "1.2.7" resolved "https://registry.yarnpkg.com/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636" @@ -1430,16 +1405,16 @@ cross-env@2.0.0: cross-spawn "^3.0.1" lodash.assign "^3.2.0" -cross-spawn@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-3.0.1.tgz#1256037ecb9f0c5f79e3d6ef135e30770184b982" +cross-spawn@4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-4.0.0.tgz#8254774ab4786b8c5b3cf4dfba66ce563932c252" dependencies: lru-cache "^4.0.1" which "^1.2.9" -cross-spawn@4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-4.0.0.tgz#8254774ab4786b8c5b3cf4dfba66ce563932c252" +cross-spawn@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-3.0.1.tgz#1256037ecb9f0c5f79e3d6ef135e30770184b982" dependencies: lru-cache "^4.0.1" which "^1.2.9" @@ -1554,7 +1529,7 @@ csso@~2.2.1: clap "^1.0.9" source-map "^0.5.3" -"cssom@>= 0.3.0 < 0.4.0", cssom@0.3.x: +cssom@0.3.x, "cssom@>= 0.3.0 < 0.4.0": version "0.3.1" resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.3.1.tgz#c9e37ef2490e64f6d1baa10fda852257082c25d3" @@ -1564,16 +1539,16 @@ csso@~2.2.1: dependencies: cssom "0.3.x" +d3@3.5.6: + version "3.5.6" + resolved "https://registry.yarnpkg.com/d3/-/d3-3.5.6.tgz#9451c651ca733fb9672c81fb7f2655164a73a42d" + d@^0.1.1, d@~0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/d/-/d-0.1.1.tgz#da184c535d18d8ee7ba2aa229b914009fae11309" dependencies: es5-ext "~0.10.2" -d3@3.5.6: - version "3.5.6" - resolved "https://registry.yarnpkg.com/d3/-/d3-3.5.6.tgz#9451c651ca733fb9672c81fb7f2655164a73a42d" - damerau-levenshtein@^1.0.0: version "1.0.3" resolved "https://registry.yarnpkg.com/damerau-levenshtein/-/damerau-levenshtein-1.0.3.tgz#ae4f4ce0b62acae10ff63a01bb08f652f5213af2" @@ -1604,7 +1579,7 @@ decamelize@^1.0.0, decamelize@^1.1.1, decamelize@^1.1.2: version "1.2.0" resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" -deep-equal@^1.0.0, deep-equal@^1.0.1, deep-equal@1.0.1: +deep-equal@1.0.1, deep-equal@^1.0.0, deep-equal@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.0.1.tgz#f5d260292b660e084eff4cdbc9f08ad3247448b5" @@ -1675,16 +1650,16 @@ diff@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/diff/-/diff-3.1.0.tgz#9406c73a401e6c2b3ba901c5e2c44eb6a60c5385" -doctrine@^1.2.2: - version "1.5.0" - resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-1.5.0.tgz#379dce730f6166f76cefa4e6707a159b02c5a6fa" +doctrine@1.2.x: + version "1.2.3" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-1.2.3.tgz#6aec6bbd62cf89dd498cae70c0ed9f49da873a6a" dependencies: esutils "^2.0.2" isarray "^1.0.0" -doctrine@1.2.x: - version "1.2.3" - resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-1.2.3.tgz#6aec6bbd62cf89dd498cae70c0ed9f49da873a6a" +doctrine@^1.2.2: + version "1.5.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-1.5.0.tgz#379dce730f6166f76cefa4e6707a159b02c5a6fa" dependencies: esutils "^2.0.2" isarray "^1.0.0" @@ -1699,7 +1674,7 @@ dom-helpers@^2.4.0: version "2.4.0" resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-2.4.0.tgz#9bb4b245f637367b1fa670274272aa28fe06c367" -dom-serializer@~0.1.0, dom-serializer@0: +dom-serializer@0, dom-serializer@~0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.1.0.tgz#073c697546ce0780ce23be4a28e293e40bc30c82" dependencies: @@ -1714,14 +1689,10 @@ domain-browser@^1.1.1: version "1.1.7" resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.1.7.tgz#867aa4b093faa05f1de08c06f4d7b21fdf8698bc" -domelementtype@~1.1.1: +domelementtype@1, domelementtype@~1.1.1: version "1.1.3" resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.1.3.tgz#bd28773e2642881aec51544924299c5cd822185b" -domelementtype@1: - version "1.3.0" - resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.3.0.tgz#b17aed82e8ab59e52dd9c19b1756e0fc187204c2" - domhandler@2.1: version "2.1.0" resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-2.1.0.tgz#d2646f5e57f6c3bab11cf6cb05d3c0acf7412594" @@ -1765,14 +1736,14 @@ ee-first@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" +element-class@^0.2.0: + version "0.2.2" + resolved "https://registry.yarnpkg.com/element-class/-/element-class-0.2.2.tgz#9d3bbd0767f9013ef8e1c8ebe722c1402a60050e" + emojis-list@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389" -encodeurl@~1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.1.tgz#79e3d58655346909fe6f0f45a5de68103b294d20" - encoding@^0.1.11: version "0.1.12" resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.12.tgz#538b66f3ee62cd1ab51ec323829d1f9480c74beb" @@ -1787,14 +1758,14 @@ enhanced-resolve@~0.9.0: memory-fs "^0.2.0" tapable "^0.1.8" -entities@~1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.1.tgz#6e5c2d0a5621b5dadaecef80b90edfb5cd7772f0" - entities@1.0: version "1.0.0" resolved "https://registry.yarnpkg.com/entities/-/entities-1.0.0.tgz#b2987aa3821347fcde642b24fdfc9e4fb712bf26" +entities@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.1.tgz#6e5c2d0a5621b5dadaecef80b90edfb5cd7772f0" + enzyme@2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/enzyme/-/enzyme-2.2.0.tgz#972f1b89d771356ad4e06a15b4736173ec64aed5" @@ -1805,7 +1776,7 @@ enzyme@2.2.0: object.assign "^4.0.3" object.values "^1.0.3" -errno@^0.1.1, errno@^0.1.3, "errno@>=0.1.1 <0.2.0-0": +"errno@>=0.1.1 <0.2.0-0", errno@^0.1.1, errno@^0.1.3: version "0.1.4" resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.4.tgz#b896e23a9e5e8ba33871fc996abd3635fc9a1c7d" dependencies: @@ -1870,7 +1841,7 @@ es6-set@^0.1.4, es6-set@~0.1.3: es6-symbol "3" event-emitter "~0.3.4" -es6-symbol@~3.1, es6-symbol@~3.1.0, es6-symbol@3: +es6-symbol@3, es6-symbol@~3.1, es6-symbol@~3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.0.tgz#94481c655e7a7cad82eba832d97d5433496d7ffa" dependencies: @@ -1886,15 +1857,15 @@ es6-weak-map@^2.0.1: es6-iterator "2" es6-symbol "3" -escape-html@~1.0.3, escape-html@1.0.3: +escape-html@1.0.3, escape-html@~1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" -escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5, escape-string-regexp@1.0.5: +escape-string-regexp@1.0.5, escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" -escodegen@^1.6.1, escodegen@1.8.x: +escodegen@1.8.x, escodegen@^1.6.1: version "1.8.1" resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.8.1.tgz#5a5b53af4693110bebb0867aa3430dd3b70a1018" dependencies: @@ -2019,7 +1990,7 @@ espree@^3.1.6: acorn "^4.0.1" acorn-jsx "^3.0.0" -esprima@^2.6.0, esprima@^2.7.1, esprima@2.7.x: +esprima@2.7.x, esprima@^2.6.0, esprima@^2.7.1: version "2.7.3" resolved "https://registry.yarnpkg.com/esprima/-/esprima-2.7.3.tgz#96e3b70d5779f6ad49cd032673d1c312767ba581" @@ -2069,7 +2040,7 @@ events@^1.0.0: version "1.1.1" resolved "https://registry.yarnpkg.com/events/-/events-1.1.1.tgz#9ebdb7635ad099c70dcc4c2a1f5004288e8bd924" -eventsource@^0.1.3, eventsource@~0.1.6: +eventsource@^0.1.3: version "0.1.6" resolved "https://registry.yarnpkg.com/eventsource/-/eventsource-0.1.6.tgz#0acede849ed7dd1ccc32c811bb11b944d4f29232" dependencies: @@ -2081,6 +2052,10 @@ exec-sh@^0.2.0: dependencies: merge "^1.1.3" +exenv@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/exenv/-/exenv-1.2.0.tgz#3835f127abf075bfe082d0aed4484057c78e3c89" + exit-hook@^1.0.0: version "1.1.1" resolved "https://registry.yarnpkg.com/exit-hook/-/exit-hook-1.1.1.tgz#f05ca233b48c05d54fff07765df8507e95c02ff8" @@ -2108,38 +2083,7 @@ express-http-proxy@0.6.0: raw-body "^1.1.6" type-is "^1.2.0" -express@^4.13.3: - version "4.14.0" - resolved "https://registry.yarnpkg.com/express/-/express-4.14.0.tgz#c1ee3f42cdc891fb3dc650a8922d51ec847d0d66" - dependencies: - accepts "~1.3.3" - array-flatten "1.1.1" - content-disposition "0.5.1" - content-type "~1.0.2" - cookie "0.3.1" - cookie-signature "1.0.6" - debug "~2.2.0" - depd "~1.1.0" - encodeurl "~1.0.1" - escape-html "~1.0.3" - etag "~1.7.0" - finalhandler "0.5.0" - fresh "0.3.0" - merge-descriptors "1.0.1" - methods "~1.1.2" - on-finished "~2.3.0" - parseurl "~1.3.1" - path-to-regexp "0.1.7" - proxy-addr "~1.1.2" - qs "6.2.0" - range-parser "~1.2.0" - send "0.14.1" - serve-static "~1.11.1" - type-is "~1.6.13" - utils-merge "1.0.0" - vary "~1.1.0" - -express@4.13.4: +express@4.13.4, express@^4.13.3: version "4.13.4" resolved "https://registry.yarnpkg.com/express/-/express-4.13.4.tgz#3c0b76f3c77590c8345739061ec0bd3ba067ec24" dependencies: @@ -2205,12 +2149,6 @@ faye-websocket@^0.10.0: dependencies: websocket-driver ">=0.5.1" -faye-websocket@~0.11.0: - version "0.11.0" - resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.11.0.tgz#d9ccf0e789e7db725d74bc4877d23aa42972ac50" - dependencies: - websocket-driver ">=0.5.1" - faye-websocket@~0.7.3: version "0.7.3" resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.7.3.tgz#cc4074c7f4a4dfd03af54dd65c354b135132ce11" @@ -2223,6 +2161,14 @@ fb-watchman@^1.8.0, fb-watchman@^1.9.0: dependencies: bser "^1.0.2" +fbjs@0.1.0-alpha.10: + version "0.1.0-alpha.10" + resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.1.0-alpha.10.tgz#46e457c09cbefb51fc752a3e030e7b67fcc384c8" + dependencies: + core-js "^1.0.0" + promise "^7.0.3" + whatwg-fetch "^0.9.0" + fbjs@^0.8.4: version "0.8.6" resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.6.tgz#7eb67d6986b2d5007a9b6e92e0e7cb6f75cad290" @@ -2234,14 +2180,6 @@ fbjs@^0.8.4: promise "^7.1.1" ua-parser-js "^0.7.9" -fbjs@0.1.0-alpha.10: - version "0.1.0-alpha.10" - resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.1.0-alpha.10.tgz#46e457c09cbefb51fc752a3e030e7b67fcc384c8" - dependencies: - core-js "^1.0.0" - promise "^7.0.3" - whatwg-fetch "^0.9.0" - figures@^1.3.5: version "1.7.0" resolved "https://registry.yarnpkg.com/figures/-/figures-1.7.0.tgz#cbe1e3affcf1cd44b80cadfed28dc793a9701d2e" @@ -2296,17 +2234,7 @@ finalhandler@0.4.1: on-finished "~2.3.0" unpipe "~1.0.0" -finalhandler@0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-0.5.0.tgz#e9508abece9b6dba871a6942a1d7911b91911ac7" - dependencies: - debug "~2.2.0" - escape-html "~1.0.3" - on-finished "~2.3.0" - statuses "~1.3.0" - unpipe "~1.0.0" - -find-cache-dir@^0.1.1, find-cache-dir@0.1.1: +find-cache-dir@0.1.1, find-cache-dir@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-0.1.1.tgz#c8defae57c8a52a8a784f9e31c57c742e993a0b9" dependencies: @@ -2461,7 +2389,7 @@ glob-parent@^2.0.0: dependencies: is-glob "^2.0.0" -glob@^5.0.15, glob@5.x: +glob@5.x, glob@^5.0.15: version "5.0.15" resolved "https://registry.yarnpkg.com/glob/-/glob-5.0.15.tgz#1bc936b9e02f4a603fcc222ecf7633d30b8b93b1" dependencies: @@ -2536,6 +2464,14 @@ handlebars-loader@1.1.4: fastparse "^1.0.0" loader-utils "0.2.x" +handlebars@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-2.0.0.tgz#6e9d7f8514a3467fa5e9f82cc158ecfc1d5ac76f" + dependencies: + optimist "~0.3" + optionalDependencies: + uglify-js "~2.3" + handlebars@^4.0.1, handlebars@^4.0.3: version "4.0.6" resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.0.6.tgz#2ce4484850537f9c97a8026d5399b935c4ed4ed7" @@ -2546,14 +2482,6 @@ handlebars@^4.0.1, handlebars@^4.0.3: optionalDependencies: uglify-js "^2.6" -handlebars@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-2.0.0.tgz#6e9d7f8514a3467fa5e9f82cc158ecfc1d5ac76f" - dependencies: - optimist "~0.3" - optionalDependencies: - uglify-js "~2.3" - har-validator@~2.0.6: version "2.0.6" resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-2.0.6.tgz#cdcbc08188265ad119b6a5a7c8ab70eecfb5d27d" @@ -2596,18 +2524,18 @@ he@1.1.x: version "1.1.0" resolved "https://registry.yarnpkg.com/he/-/he-1.1.0.tgz#29319d49beec13a9b1f3c4f9b2a6dde4859bb2a7" -history@^2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/history/-/history-2.1.2.tgz#4aa2de897a0e4867e4539843be6ecdb2986bfdec" +history@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/history/-/history-2.0.0.tgz#6d5144af2da8a3dea4e5f1abae11a3c2e868e2c7" dependencies: deep-equal "^1.0.0" invariant "^2.0.0" query-string "^3.0.0" warning "^2.0.0" -history@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/history/-/history-2.0.0.tgz#6d5144af2da8a3dea4e5f1abae11a3c2e868e2c7" +history@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/history/-/history-2.1.2.tgz#4aa2de897a0e4867e4539843be6ecdb2986bfdec" dependencies: deep-equal "^1.0.0" invariant "^2.0.0" @@ -2740,10 +2668,6 @@ https-browserify@0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-0.0.0.tgz#b3ffdfe734b2a3d4a9efd58e8654c91fce86eafd" -iconv-lite@^0.4.13, iconv-lite@~0.4.13: - version "0.4.15" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.15.tgz#fe265a218ac6a57cfe854927e9d04c19825eddeb" - iconv-lite@0.4.13: version "0.4.13" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.13.tgz#1f88aba4ab0b1508e8312acc39345f36e992e2f2" @@ -2752,6 +2676,10 @@ iconv-lite@0.4.8: version "0.4.8" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.8.tgz#c6019a7595f2cefca702eab694a010bcd9298d20" +iconv-lite@^0.4.13, iconv-lite@~0.4.13: + version "0.4.15" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.15.tgz#fe265a218ac6a57cfe854927e9d04c19825eddeb" + icss-replace-symbols@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/icss-replace-symbols/-/icss-replace-symbols-1.0.2.tgz#cb0b6054eb3af6edc9ab1d62d01933e2d4c8bfa5" @@ -2794,7 +2722,7 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@^2.0.1, inherits@~2.0.0, inherits@~2.0.1, inherits@2, inherits@2.0.3: +inherits@2, inherits@2.0.3, inherits@^2.0.1, inherits@~2.0.0, inherits@~2.0.1: version "2.0.3" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" @@ -2842,10 +2770,6 @@ ipaddr.js@1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.0.5.tgz#5fa78cf301b825c78abc3042d812723049ea23c7" -ipaddr.js@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.1.1.tgz#c791d95f52b29c1247d5df80ada39b8a73647230" - is-absolute-url@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/is-absolute-url/-/is-absolute-url-2.1.0.tgz#50530dfb84fcc9aa7dbe7852e83a37b93b9f2aa6" @@ -3011,14 +2935,14 @@ is-utf8@^0.2.0: version "0.2.1" resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" -isarray@^1.0.0, isarray@~1.0.0, isarray@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" - isarray@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" +isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + isexe@^1.1.1: version "1.1.2" resolved "https://registry.yarnpkg.com/isexe/-/isexe-1.1.2.tgz#36f3e22e60750920f5e7241a476a8c6a42275ad0" @@ -3321,7 +3245,7 @@ js-tokens@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-2.0.0.tgz#79903f5563ee778cc1162e6dcf1a0027c97f9cb5" -js-yaml@^3.5.1, js-yaml@3.x: +js-yaml@3.x, js-yaml@^3.5.1: version "3.7.0" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.7.0.tgz#5c967ddd837a9bfdca5f2de84253abe8a1c03b80" dependencies: @@ -3508,7 +3432,7 @@ load-json-file@^1.0.0: pinkie-promise "^2.0.0" strip-bom "^2.0.0" -loader-utils@^0.2.11, loader-utils@^0.2.16, loader-utils@^0.2.3, loader-utils@^0.2.5, loader-utils@^0.2.7, loader-utils@~0.2.2, loader-utils@~0.2.5, loader-utils@0.2.x: +loader-utils@0.2.x, loader-utils@^0.2.11, loader-utils@^0.2.16, loader-utils@^0.2.3, loader-utils@^0.2.5, loader-utils@^0.2.7, loader-utils@~0.2.2, loader-utils@~0.2.5: version "0.2.16" resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-0.2.16.tgz#f08632066ed8282835dff88dfb52704765adee6d" dependencies: @@ -3667,14 +3591,14 @@ lodash.words@^3.0.0: dependencies: lodash._root "^3.0.0" -lodash@^4.0.0, lodash@^4.1.0, lodash@^4.15.0, lodash@^4.16.4, lodash@^4.17.2, lodash@^4.2.0, lodash@^4.2.1, lodash@^4.3.0, lodash@^4.6.1: - version "4.17.2" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.2.tgz#34a3055babe04ce42467b607d700072c7ff6bf42" - -lodash@4.6.1: +lodash@4.6.1, lodash@^4.0.0, lodash@^4.2.0: version "4.6.1" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.6.1.tgz#df00c1164ad236b183cfc3887a5e8d38cc63cbbc" +lodash@^4.1.0, lodash@^4.15.0, lodash@^4.16.4, lodash@^4.17.2, lodash@^4.2.1, lodash@^4.3.0, lodash@^4.6.1: + version "4.17.2" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.2.tgz#34a3055babe04ce42467b607d700072c7ff6bf42" + longest@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097" @@ -3781,7 +3705,7 @@ mime-types@^2.1.12, mime-types@~2.1.11, mime-types@~2.1.13, mime-types@~2.1.6, m dependencies: mime-db "~1.25.0" -mime@^1.2.11, mime@^1.3.4, mime@1.3.4: +mime@1.3.4, mime@^1.2.11, mime@^1.3.4: version "1.3.4" resolved "https://registry.yarnpkg.com/mime/-/mime-1.3.4.tgz#115f9e3b6b3daf2959983cb38f149a2d40eb5d53" @@ -3791,7 +3715,7 @@ min-document@^2.19.0: dependencies: dom-walk "^0.1.0" -minimatch@^3.0.0, minimatch@^3.0.2, "minimatch@2 || 3": +"minimatch@2 || 3", minimatch@^3.0.0, minimatch@^3.0.2: version "3.0.3" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.3.tgz#2a4e4090b96b2db06a9d7df01055a62a77c9b774" dependencies: @@ -3809,19 +3733,15 @@ minimatch@3.0.2: dependencies: brace-expansion "^1.0.0" +minimist@0.0.8, minimist@~0.0.1: + version "0.0.8" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" + minimist@^1.1.1, minimist@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" -minimist@~0.0.1: - version "0.0.10" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf" - -minimist@0.0.8: - version "0.0.8" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" - -mkdirp@^0.5.0, mkdirp@^0.5.1, "mkdirp@>=0.5 0", mkdirp@~0.5.0, mkdirp@~0.5.1, mkdirp@0.5.x: +mkdirp@0.5.x, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0, mkdirp@~0.5.1: version "0.5.1" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" dependencies: @@ -3951,7 +3871,7 @@ node-pre-gyp@^0.6.29: tar "~2.2.1" tar-pack "~3.3.0" -nopt@~3.0.6, nopt@3.x: +nopt@3.x, nopt@~3.0.6: version "3.0.6" resolved "https://registry.yarnpkg.com/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9" dependencies: @@ -4060,7 +3980,7 @@ on-headers@~1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.1.tgz#928f5d0f470d49342651ea6794b0857c100693f7" -once@^1.3.0, once@1.x: +once@1.x, once@^1.3.0: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" dependencies: @@ -4172,16 +4092,16 @@ path-browserify@0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-0.0.0.tgz#a0b870729aae214005b7d5032ec2cbbb0fb4451a" -path-exists@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-1.0.0.tgz#d5a8998eb71ef37a74c34eb0d9eba6e878eea081" - -path-exists@^2.0.0, path-exists@2.1.0: +path-exists@2.1.0, path-exists@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b" dependencies: pinkie-promise "^2.0.0" +path-exists@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-1.0.0.tgz#d5a8998eb71ef37a74c34eb0d9eba6e878eea081" + path-is-absolute@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" @@ -4473,7 +4393,7 @@ postcss-zindex@^2.0.1: postcss "^5.0.4" uniqs "^2.0.0" -postcss@^5.0.10, postcss@^5.0.11, postcss@^5.0.12, postcss@^5.0.13, postcss@^5.0.14, postcss@^5.0.16, postcss@^5.0.2, postcss@^5.0.4, postcss@^5.0.5, postcss@^5.0.6, postcss@^5.0.8, postcss@^5.1.2, postcss@^5.2.5: +postcss@^5.0.10, postcss@^5.0.11, postcss@^5.0.12, postcss@^5.0.13, postcss@^5.0.14, postcss@^5.0.16, postcss@^5.0.2, postcss@^5.0.4, postcss@^5.0.5, postcss@^5.0.6, postcss@^5.0.8, postcss@^5.1.2: version "5.2.6" resolved "https://registry.yarnpkg.com/postcss/-/postcss-5.2.6.tgz#a252cd67cd52585035f17e9ad12b35137a7bdd9e" dependencies: @@ -4538,13 +4458,6 @@ proxy-addr@~1.0.10: forwarded "~0.1.0" ipaddr.js "1.0.5" -proxy-addr@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-1.1.2.tgz#b4cc5f22610d9535824c123aef9d3cf73c40ba37" - dependencies: - forwarded "~0.1.0" - ipaddr.js "1.1.1" - prr@~0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/prr/-/prr-0.0.0.tgz#1a84b85908325501411853d0081ee3fa86e2926a" @@ -4553,29 +4466,25 @@ pseudomap@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" -punycode@^1.2.4, punycode@^1.4.1: - version "1.4.1" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" - punycode@1.3.2: version "1.3.2" resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" +punycode@^1.2.4, punycode@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" + q@^1.1.2: version "1.4.1" resolved "https://registry.yarnpkg.com/q/-/q-1.4.1.tgz#55705bcd93c5f3673530c2c2cbc0c2b3addc286e" -qs@~6.3.0: - version "6.3.0" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.3.0.tgz#f403b264f23bc01228c74131b407f18d5ea5d442" - qs@4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/qs/-/qs-4.0.0.tgz#c31d9b74ec27df75e543a86c78728ed8d4623607" -qs@6.2.0: - version "6.2.0" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.2.0.tgz#3b7848c03c2dece69a9522b0fae8c4126d745f3b" +qs@~6.3.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.3.0.tgz#f403b264f23bc01228c74131b407f18d5ea5d442" query-string@^3.0.0: version "3.0.3" @@ -4609,11 +4518,7 @@ randomatic@^1.1.3: is-number "^2.0.2" kind-of "^3.0.2" -range-parser@^1.0.3, range-parser@~1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e" - -range-parser@~1.0.3: +range-parser@^1.0.3, range-parser@~1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.0.3.tgz#6872823535c692e2c2a0103826afd82c2e0ff175" @@ -4679,6 +4584,14 @@ react-input-autosize@^0.6.10: version "0.6.13" resolved "https://registry.yarnpkg.com/react-input-autosize/-/react-input-autosize-0.6.13.tgz#386ff7a9d2c3dc016c265bf2e59d397050f65af7" +react-modal@^1.6.4: + version "1.6.4" + resolved "https://registry.yarnpkg.com/react-modal/-/react-modal-1.6.4.tgz#639383931cbaae7946a92de9d5a7c05a4a1cab82" + dependencies: + element-class "^0.2.0" + exenv "1.2.0" + lodash.assign "^4.2.0" + react-proxy@^1.1.7: version "1.1.8" resolved "https://registry.yarnpkg.com/react-proxy/-/react-proxy-1.1.8.tgz#9dbfd9d927528c3aa9f444e4558c37830ab8c26a" @@ -4760,39 +4673,25 @@ read-pkg@^1.0.0: normalize-package-data "^2.3.2" path-type "^1.0.0" -readable-stream@^1.0.27-1, readable-stream@^1.1.13: - version "1.1.14" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9" +readable-stream@1.0: + version "1.0.34" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.0.34.tgz#125820e34bc842d2f2aaafafe4c2916ee32c157c" dependencies: core-util-is "~1.0.0" inherits "~2.0.1" isarray "0.0.1" string_decoder "~0.10.x" -"readable-stream@^2.0.0 || ^1.1.13", readable-stream@^2.0.1, readable-stream@^2.0.2: - version "2.2.2" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.2.2.tgz#a9e6fec3c7dda85f8bb1b3ba7028604556fc825e" - dependencies: - buffer-shims "^1.0.0" - core-util-is "~1.0.0" - inherits "~2.0.1" - isarray "~1.0.0" - process-nextick-args "~1.0.6" - string_decoder "~0.10.x" - util-deprecate "~1.0.1" - -readable-stream@~2.0.0: - version "2.0.6" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.0.6.tgz#8f90341e68a53ccc928788dacfcd11b36eb9b78e" +readable-stream@1.1, readable-stream@^1.0.27-1, readable-stream@^1.1.13: + version "1.1.14" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9" dependencies: core-util-is "~1.0.0" inherits "~2.0.1" - isarray "~1.0.0" - process-nextick-args "~1.0.6" + isarray "0.0.1" string_decoder "~0.10.x" - util-deprecate "~1.0.1" -readable-stream@~2.1.4: +"readable-stream@^2.0.0 || ^1.1.13", readable-stream@~2.1.4: version "2.1.5" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.1.5.tgz#66fa8b720e1438b364681f2ad1a63c618448c9d0" dependencies: @@ -4804,23 +4703,16 @@ readable-stream@~2.1.4: string_decoder "~0.10.x" util-deprecate "~1.0.1" -readable-stream@1.0: - version "1.0.34" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.0.34.tgz#125820e34bc842d2f2aaafafe4c2916ee32c157c" - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.1" - isarray "0.0.1" - string_decoder "~0.10.x" - -readable-stream@1.1: - version "1.1.13" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.13.tgz#f6eef764f514c89e2b9e23146a75ba106756d23e" +readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@~2.0.0: + version "2.0.6" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.0.6.tgz#8f90341e68a53ccc928788dacfcd11b36eb9b78e" dependencies: core-util-is "~1.0.0" inherits "~2.0.1" - isarray "0.0.1" + isarray "~1.0.0" + process-nextick-args "~1.0.6" string_decoder "~0.10.x" + util-deprecate "~1.0.1" readdirp@^2.0.0: version "2.1.0" @@ -5016,7 +4908,7 @@ resolve-from@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-1.0.1.tgz#26cbfe935d1aeeeabb29bc3fe5aeb01e93d44226" -resolve@^1.1.6, resolve@1.1.7, resolve@1.1.x: +resolve@1.1.7, resolve@1.1.x, resolve@^1.1.6: version "1.1.7" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b" @@ -5033,7 +4925,7 @@ right-align@^0.1.1: dependencies: align-text "^0.1.1" -rimraf@^2.2.8, rimraf@^2.4.3, rimraf@^2.4.4, rimraf@~2.5.1, rimraf@~2.5.4, rimraf@2, rimraf@2.5.4: +rimraf@2, rimraf@2.5.4, rimraf@^2.2.8, rimraf@^2.4.3, rimraf@^2.4.4, rimraf@~2.5.1, rimraf@~2.5.4: version "2.5.4" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.5.4.tgz#96800093cbf1a0c86bd95b4625467535c29dfa04" dependencies: @@ -5078,7 +4970,7 @@ select@^1.0.6: version "1.1.0" resolved "https://registry.yarnpkg.com/select/-/select-1.1.0.tgz#a6c520cd9ab919ad81c7d1a273e0452f504dd7a2" -semver@^5.1.0, semver@^5.3.0, semver@~5.3.0, "semver@2 || 3 || 4 || 5": +"semver@2 || 3 || 4 || 5", semver@^5.1.0, semver@^5.3.0, semver@~5.3.0: version "5.3.0" resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f" @@ -5116,24 +5008,6 @@ send@0.13.2: range-parser "~1.0.3" statuses "~1.2.1" -send@0.14.1: - version "0.14.1" - resolved "https://registry.yarnpkg.com/send/-/send-0.14.1.tgz#a954984325392f51532a7760760e459598c89f7a" - dependencies: - debug "~2.2.0" - depd "~1.1.0" - destroy "~1.0.4" - encodeurl "~1.0.1" - escape-html "~1.0.3" - etag "~1.7.0" - fresh "0.3.0" - http-errors "~1.5.0" - mime "1.3.4" - ms "0.7.1" - on-finished "~2.3.0" - range-parser "~1.2.0" - statuses "~1.3.0" - serve-index@^1.7.2: version "1.8.0" resolved "https://registry.yarnpkg.com/serve-index/-/serve-index-1.8.0.tgz#7c5d96c13fb131101f93c1c5774f8516a1e78d3b" @@ -5154,15 +5028,6 @@ serve-static@~1.10.2: parseurl "~1.3.1" send "0.13.2" -serve-static@~1.11.1: - version "1.11.1" - resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.11.1.tgz#d6cce7693505f733c759de57befc1af76c0f0805" - dependencies: - encodeurl "~1.0.1" - escape-html "~1.0.3" - parseurl "~1.3.1" - send "0.14.1" - set-blocking@^2.0.0, set-blocking@~2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" @@ -5215,18 +5080,7 @@ sntp@1.x.x: dependencies: hoek "2.x.x" -sockjs-client@^1.0.3: - version "1.1.1" - resolved "https://registry.yarnpkg.com/sockjs-client/-/sockjs-client-1.1.1.tgz#284843e9a9784d7c474b1571b3240fca9dda4bb0" - dependencies: - debug "^2.2.0" - eventsource "~0.1.6" - faye-websocket "~0.11.0" - inherits "^2.0.1" - json3 "^3.3.2" - url-parse "^1.1.1" - -sockjs-client@1.0.3: +sockjs-client@1.0.3, sockjs-client@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/sockjs-client/-/sockjs-client-1.0.3.tgz#b0d8280998460eb2564c5d79d7e3d7cfd8a353ad" dependencies: @@ -5260,7 +5114,13 @@ source-map-support@^0.4.2: dependencies: source-map "^0.5.3" -source-map@^0.4.4, source-map@~0.4.1, source-map@0.4.x: +source-map@0.1.x, source-map@~0.1.7: + version "0.1.43" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.1.43.tgz#c24bc146ca517c1471f5dacbe2571b2b7f9e3346" + dependencies: + amdefine ">=0.0.4" + +source-map@0.4.x, source-map@^0.4.4, source-map@~0.4.1: version "0.4.4" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.4.4.tgz#eba4f5da9c0dc999de68032d8b4f76173652036b" dependencies: @@ -5270,12 +5130,6 @@ source-map@^0.5.0, source-map@^0.5.3, source-map@^0.5.6, source-map@~0.5.1, sour version "0.5.6" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.6.tgz#75ce38f52bf0733c5a7f0c118d81334a2bb5f412" -source-map@~0.1.7, source-map@0.1.x: - version "0.1.43" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.1.43.tgz#c24bc146ca517c1471f5dacbe2571b2b7f9e3346" - dependencies: - amdefine ">=0.0.4" - source-map@~0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.2.0.tgz#dab73fbcfc2ba819b4de03bd6f6eaa48164b3f9d" @@ -5315,14 +5169,14 @@ sshpk@^1.7.0: jsbn "~0.1.0" tweetnacl "~0.14.0" -"statuses@>= 1.3.1 < 2", statuses@~1.3.0, statuses@1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.3.1.tgz#faf51b9eb74aaef3b3acf4ad5f61abf24cb7b93e" - -statuses@~1.2.1: +statuses@1, statuses@~1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.2.1.tgz#dded45cc18256d51ed40aec142489d5c61026d28" +"statuses@>= 1.3.1 < 2": + version "1.3.1" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.3.1.tgz#faf51b9eb74aaef3b3acf4ad5f61abf24cb7b93e" + stream-browserify@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-1.0.0.tgz#bf9b4abfb42b274d751479e44e0ff2656b6f1193" @@ -5338,10 +5192,6 @@ strict-uri-encode@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713" -string_decoder@~0.10.25, string_decoder@~0.10.x: - version "0.10.31" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" - string-width@^1.0.1, string-width@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" @@ -5361,11 +5211,15 @@ string.prototype.codepointat@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/string.prototype.codepointat/-/string.prototype.codepointat-0.2.0.tgz#6b26e9bd3afcaa7be3b4269b526de1b82000ac78" +string_decoder@~0.10.25, string_decoder@~0.10.x: + version "0.10.31" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" + stringstream@~0.0.4: version "0.0.5" resolved "https://registry.yarnpkg.com/stringstream/-/stringstream-0.0.5.tgz#4e484cd4de5a0bbbee18e46307710a8a81621878" -strip-ansi@^3.0.0, strip-ansi@^3.0.1, strip-ansi@3.0.1: +strip-ansi@3.0.1, strip-ansi@^3.0.0, strip-ansi@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" dependencies: @@ -5533,7 +5387,7 @@ type-check@~0.3.2: dependencies: prelude-ls "~1.1.2" -type-is@^1.2.0, type-is@~1.6.13, type-is@~1.6.6: +type-is@^1.2.0, type-is@~1.6.6: version "1.6.14" resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.14.tgz#e219639c17ded1ca0789092dd54a03826b817cb2" dependencies: @@ -5548,7 +5402,7 @@ ua-parser-js@^0.7.9: version "0.7.12" resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.12.tgz#04c81a99bdd5dc52263ea29d24c6bf8d4818a4bb" -uglify-js@^2.6, uglify-js@2.7.x: +uglify-js@2.7.x, uglify-js@^2.6: version "2.7.5" resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.7.5.tgz#4612c0c7baaee2ba7c487de4904ae122079f2ca8" dependencies: @@ -5582,7 +5436,7 @@ uid-number@~0.0.6: version "0.0.6" resolved "https://registry.yarnpkg.com/uid-number/-/uid-number-0.0.6.tgz#0ea10e8035e8eb5b8e4449f06da1c730663baa81" -"underscore@>=1.3.3 <=1.8.3", "underscore@>=1.4.0 <=1.8.3", underscore@>=1.7.0, underscore@>=1.8.3, "underscore@1.4.4 - 1.8.3", underscore@1.8.3: +"underscore@1.4.4 - 1.8.3", underscore@1.8.3, "underscore@>=1.3.3 <=1.8.3", "underscore@>=1.4.0 <=1.8.3", underscore@>=1.7.0: version "1.8.3" resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.8.3.tgz#4f3fb53b106e6097fcf9cb4109f2a5e9bdfa5022" @@ -5608,16 +5462,16 @@ upper-case@^1.1.1: version "1.1.3" resolved "https://registry.yarnpkg.com/upper-case/-/upper-case-1.1.3.tgz#f6b4501c2ec4cdd26ba78be7222961de77621598" -url-parse@^1.0.1, url-parse@^1.1.1: - version "1.1.7" - resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.1.7.tgz#025cff999653a459ab34232147d89514cc87d74a" +url-parse@1.0.x: + version "1.0.5" + resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.0.5.tgz#0854860422afdcfefeb6c965c662d4800169927b" dependencies: querystringify "0.0.x" requires-port "1.0.x" -url-parse@1.0.x: - version "1.0.5" - resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.0.5.tgz#0854860422afdcfefeb6c965c662d4800169927b" +url-parse@^1.0.1: + version "1.1.7" + resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.1.7.tgz#025cff999653a459ab34232147d89514cc87d74a" dependencies: querystringify "0.0.x" requires-port "1.0.x" @@ -5639,7 +5493,7 @@ util-deprecate@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" -util@~0.10.3, util@0.10.3: +util@0.10.3, util@~0.10.3: version "0.10.3" resolved "https://registry.yarnpkg.com/util/-/util-0.10.3.tgz#7afb1afe50805246489e3db7fe0ed379336ac0f9" dependencies: @@ -5702,7 +5556,7 @@ walker@~1.0.5: dependencies: makeerror "1.0.x" -warning@^2.0.0, warning@2.1.0: +warning@2.1.0, warning@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/warning/-/warning-2.1.0.tgz#21220d9c63afc77a8c92111e011af705ce0c6901" dependencies: @@ -5811,18 +5665,14 @@ whatwg-encoding@^1.0.1: dependencies: iconv-lite "0.4.13" +whatwg-fetch@1.0.0, whatwg-fetch@>=0.10.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-1.0.0.tgz#01c2ac4df40e236aaa18480e3be74bd5c8eb798e" + whatwg-fetch@^0.9.0: version "0.9.0" resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-0.9.0.tgz#0e3684c6cb9995b43efc9df03e4c365d95fd9cc0" -whatwg-fetch@>=0.10.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-2.0.1.tgz#078b9461bbe91cea73cbce8bb122a05f9e92b772" - -whatwg-fetch@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-1.0.0.tgz#01c2ac4df40e236aaa18480e3be74bd5c8eb798e" - whatwg-url-compat@~0.6.5: version "0.6.5" resolved "https://registry.yarnpkg.com/whatwg-url-compat/-/whatwg-url-compat-0.6.5.tgz#00898111af689bb097541cd5a45ca6c8798445bf" @@ -5856,13 +5706,17 @@ wide-align@^1.1.0: dependencies: string-width "^1.0.1" +window-size@0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.0.tgz#5438cd2ea93b202efa3a19fe8887aee7c94f9c9d" + window-size@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.2.0.tgz#b4315bb4214a3d7058ebeee892e13fa24d98b075" -window-size@0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.0.tgz#5438cd2ea93b202efa3a19fe8887aee7c94f9c9d" +wordwrap@0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f" wordwrap@^1.0.0, wordwrap@~1.0.0: version "1.0.0" @@ -5872,10 +5726,6 @@ wordwrap@~0.0.2: version "0.0.3" resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107" -wordwrap@0.0.2: - version "0.0.2" - resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f" - worker-farm@^1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/worker-farm/-/worker-farm-1.3.1.tgz#4333112bb49b17aa050b87895ca6b2cacf40e5ff" @@ -5908,7 +5758,7 @@ xml-char-classes@^1.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-2.0.1.tgz#4d8b8f1eccd3419aa362061becef515e1e559635" -xtend@^4.0.0, "xtend@>=4.0.0 <4.1.0-0": +"xtend@>=4.0.0 <4.1.0-0", xtend@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" @@ -5954,4 +5804,3 @@ yargs@~3.10.0: cliui "^2.1.0" decamelize "^1.0.0" window-size "0.1.0" - diff --git a/sonar-core/src/main/resources/org/sonar/l10n/core.properties b/sonar-core/src/main/resources/org/sonar/l10n/core.properties index 67b93b050ea..8ec7fda9c47 100644 --- a/sonar-core/src/main/resources/org/sonar/l10n/core.properties +++ b/sonar-core/src/main/resources/org/sonar/l10n/core.properties @@ -438,10 +438,10 @@ project_links.url=URL #------------------------------------------------------------------------------ event.category.All=All -event.category.Version=Version -event.category.Alert=Quality Gate -event.category.Profile=Quality Profile -event.category.Other=Other +event.category.VERSION=Version +event.category.QUALITY_GATE=Quality Gate +event.category.QUALITY_PROFILE=Quality Profile +event.category.OTHER=Other #------------------------------------------------------------------------------ @@ -552,7 +552,8 @@ source.page=Source timemachine.page=Time Machine comparison.page=Compare view_projects.page=Projects - +project_activity.page=Activity +project_activity.page.description=The page shows the history of project analyses. #------------------------------------------------------------------------------ # @@ -1150,10 +1151,22 @@ manual_rules.add_manual_rule=Add Manual Rule #------------------------------------------------------------------------------ # -# PROJECT HISTORY SERVICE +# PROJECT ACTIVITY/HISTORY SERVICE # #------------------------------------------------------------------------------ +project_activity.project_analyzed=Project Analyzed +project_activity.add_version=Create Version +project_activity.remove_version=Remove Version +project_activity.remove_version.question=Are you sure you want to delete this version? +project_activity.change_version=Change Version +project_activity.add_custom_event=Create Custom Event +project_activity.change_custom_event=Change Event +project_activity.remove_custom_event=Delete Event +project_activity.remove_custom_event.question=Are you sure you want to delete this event? +project_activity.delete_analysis=Delete Analysis +project_activity.delete_analysis.question=Are you sure you want to delete this analysis from the project history? + project_history.col.year=Year project_history.col.month=Month project_history.col.day=Day -- 2.39.5