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;
PurgeTest.class,
// project event
EventTest.class,
+ ProjectActivityPageTest.class,
// project search
SearchProjectsTest.class,
// http
// 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"))
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2016 SonarSource SA
- * mailto:contact AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package it.projectAdministration;
-
-import com.sonar.orchestrator.Orchestrator;
-import com.sonar.orchestrator.build.SonarScanner;
-import it.Category1Suite;
-import java.util.List;
-import org.junit.Before;
-import org.junit.ClassRule;
-import org.junit.Rule;
-import org.junit.Test;
-import pageobjects.Navigation;
-import pageobjects.ProjectHistoryPage;
-import pageobjects.ProjectHistorySnapshotItem;
-
-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 {
-
- @ClassRule
- public static Orchestrator ORCHESTRATOR = Category1Suite.ORCHESTRATOR;
-
- @Rule
- public Navigation nav = Navigation.get(ORCHESTRATOR);
-
- @Before
- public void setUp() {
- 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);
-
- List<ProjectHistorySnapshotItem> snapshots = page.getSnapshotsAsItems();
-
- snapshots.get(0).getVersionText().shouldBe(text("1.0-SNAPSHOT"));
- snapshots.get(0).getDeleteButton().shouldNot(exist);
-
- snapshots.get(1).getVersionText().shouldBe(text("0.9-SNAPSHOT"));
- snapshots.get(1).getDeleteButton().should(exist);
- }
-
- @Test
- public void should_delete_snapshot() {
- ProjectHistoryPage page = openPage();
-
- page.getSnapshots().shouldHaveSize(2);
-
- page.getSnapshotsAsItems().get(1).clickDelete();
- confirm();
-
- page.checkAlertDisplayed();
- page.getSnapshots().shouldHaveSize(1);
- }
-
- private ProjectHistoryPage openPage() {
- nav.logIn().submitCredentials("admin", "admin");
- return nav.openProjectHistory("sample");
- }
-
- private static void analyzeProject(String path, String date) {
- ORCHESTRATOR.executeBuild(SonarScanner.create(projectDir(path))
- .setProperties("sonar.projectDate", date));
- }
-}
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
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"));
.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
*/
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package it.projectEvent;
+
+import com.sonar.orchestrator.Orchestrator;
+import com.sonar.orchestrator.build.SonarScanner;
+import it.Category1Suite;
+import java.util.List;
+import org.junit.Before;
+import org.junit.ClassRule;
+import org.junit.Rule;
+import org.junit.Test;
+import pageobjects.Navigation;
+import pageobjects.ProjectActivityPage;
+import pageobjects.ProjectAnalysisItem;
+
+import static util.ItUtils.projectDir;
+
+public class ProjectActivityPageTest {
+
+ @ClassRule
+ public static Orchestrator ORCHESTRATOR = Category1Suite.ORCHESTRATOR;
+
+ @Rule
+ public Navigation nav = Navigation.get(ORCHESTRATOR);
+
+ @Before
+ public void setUp() throws Exception {
+ ORCHESTRATOR.resetData();
+ }
+
+ @Test
+ public void should_list_snapshots() {
+ analyzeProject("shared/xoo-history-v1", "2014-10-19");
+ analyzeProject("shared/xoo-history-v2", "2014-11-13");
+
+ ProjectActivityPage page = openPage();
+ page.getAnalyses().shouldHaveSize(2);
+
+ List<ProjectAnalysisItem> analyses = page.getAnalysesAsItems();
+ analyses.get(0)
+ .shouldHaveEventWithText("1.0-SNAPSHOT")
+ .shouldNotHaveDeleteButton();
+
+ analyses.get(1)
+ .shouldHaveEventWithText("0.9-SNAPSHOT")
+ .shouldHaveDeleteButton();
+ }
+
+ @Test
+ public void add_change_delete_custom_event() {
+ analyzeProject();
+ openPage().getLastAnalysis()
+ .addCustomEvent("foo")
+ .changeLastEvent("bar")
+ .deleteLastEvent();
+ }
+
+ @Test
+ public void delete_analysis() {
+ analyzeProject();
+ analyzeProject();
+ openPage().getFirstAnalysis().delete();
+ }
+
+ private ProjectActivityPage openPage() {
+ nav.logIn().submitCredentials("admin", "admin");
+ 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));
+ }
+}
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;
* 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");
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());
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);
}
--- /dev/null
+/*
+ * 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.ElementsCollection;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import static com.codeborne.selenide.Condition.hasText;
+import static com.codeborne.selenide.Selenide.$;
+import static com.codeborne.selenide.Selenide.$$;
+
+public class ProjectActivityPage {
+
+ public ProjectActivityPage() {
+ $("#project-activity").should(Condition.exist);
+ }
+
+ public ElementsCollection getAnalyses() {
+ return $$(".project-activity-analysis");
+ }
+
+ public List<ProjectAnalysisItem> getAnalysesAsItems() {
+ return getAnalyses()
+ .stream()
+ .map(ProjectAnalysisItem::new)
+ .collect(Collectors.toList());
+ }
+
+ 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;
+ }
+}
--- /dev/null
+/*
+ * 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;
+ }
+}
+++ /dev/null
-/*
- * 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.ElementsCollection;
-import java.util.List;
-import java.util.stream.Collectors;
-
-import static com.codeborne.selenide.Condition.exist;
-import static com.codeborne.selenide.Selenide.$;
-import static com.codeborne.selenide.Selenide.$$;
-
-public class ProjectHistoryPage {
-
- public ProjectHistoryPage() {
- $("#project-history").should(exist);
- }
-
- public ElementsCollection getSnapshots() {
- return $$("tr.snapshot");
- }
-
- public List<ProjectHistorySnapshotItem> getSnapshotsAsItems() {
- return getSnapshots()
- .stream()
- .map(ProjectHistorySnapshotItem::new)
- .collect(Collectors.toList());
- }
-
- public void checkAlertDisplayed() {
- $("#info:not(.hidden)").should(exist);
- }
-}
+++ /dev/null
-/*
- * 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.SelenideElement;
-import org.openqa.selenium.NoSuchElementException;
-
-public class ProjectHistorySnapshotItem {
-
- private final SelenideElement elt;
-
- 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");
- }
-
- public SelenideElement getDeleteButton() {
- return elt.$("td:nth-child(9) input[type=\"submit\"]");
- }
-
- public void clickDelete() {
- getDeleteButton().click();
- }
-}
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
-<head profile="http://selenium-ide.openqa.org/profiles/test-case">
- <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
- <title>create_delete_standard_event</title>
-</head>
-<body>
-<table cellpadding="1" cellspacing="1" border="1">
- <thead>
- <tr>
- <td rowspan="1" colspan="3">create_delete_standard_event</td>
- </tr>
- </thead>
- <tbody>
- <tr>
- <td>open</td>
- <td>/sessions/logout</td>
- <td></td>
-</tr>
-<tr>
- <td>open</td>
- <td>/sessions/login</td>
- <td></td>
-</tr>
-<tr>
- <td>type</td>
- <td>login</td>
- <td>admin</td>
-</tr>
-<tr>
- <td>type</td>
- <td>password</td>
- <td>admin</td>
-</tr>
-<tr>
- <td>clickAndWait</td>
- <td>commit</td>
- <td></td>
-</tr>
-<tr>
- <td>waitForElementPresent</td>
- <td>css=.js-user-authenticated</td>
- <td></td>
-</tr>
-<tr>
- <td>open</td>
- <td>/project/history?id=sample</td>
- <td></td>
-</tr>
-<tr>
- <td>click</td>
- <td>link=Create</td>
- <td></td>
-</tr>
-<tr>
- <td>waitForElementPresent</td>
- <td>create_event_name_0</td>
- <td></td>
-</tr>
-<tr>
- <td>type</td>
- <td>create_event_name_0</td>
- <td>EventToBeDeleted</td>
-</tr>
-<tr>
- <td>clickAndWait</td>
- <td>create_save_event_0</td>
- <td></td>
-</tr>
-<tr>
- <td>waitForElementPresent</td>
- <td>infomsg</td>
- <td></td>
-</tr>
-<tr>
- <td>waitForText</td>
- <td>infomsg</td>
- <td>Event 'EventToBeDeleted' was created.</td>
-</tr>
-<tr>
- <td>assertElementPresent</td>
- <td>//td[text()='EventToBeDeleted']</td>
- <td></td>
-</tr>
-<tr>
- <td>clickAndWait</td>
- <td>link=Remove</td>
- <td></td>
-</tr>
-<tr>
- <td>assertConfirmation</td>
- <td>Are you sure you want to remove 'EventToBeDeleted' from this snapshot?</td>
- <td></td>
-</tr>
-<tr>
- <td>waitForElementPresent</td>
- <td>infomsg</td>
- <td></td>
-</tr>
-<tr>
- <td>waitForText</td>
- <td>infomsg</td>
- <td>Event 'EventToBeDeleted' was deleted.</td>
-</tr>
-<tr>
- <td>assertElementNotPresent</td>
- <td>//td[text()='EventToBeDeleted']</td>
- <td></td>
-</tr>
-</tbody>
-</table>
-</body>
-</html>
"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",
"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"
--- /dev/null
+/*
+ * 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<Object>,
+ paging: {
+ total: number,
+ pageIndex: number,
+ pageSize: number
+ }
+};
+
+type GetProjectActivityOptions = {
+ category?: ?string,
+ pageIndex?: ?number,
+ pageSize?: ?number
+};
+
+export const getProjectActivity = (
+ project: string,
+ options?: GetProjectActivityOptions
+): Promise<GetProjectActivityResponse> => {
+ 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<CreateEventResponse> => {
+ 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<CreateEventResponse> => {
+ 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 })
+);
);
}
+ renderActivityLink () {
+ return (
+ <li>
+ <Link to={{ pathname: '/project/activity', query: { id: this.props.component.key } }}
+ activeClassName="active">
+ {translate('project_activity.page')}
+ </Link>
+ </li>
+ );
+ }
+
renderComponentIssuesLink () {
return (
<li>
{this.renderCustomMeasuresLink()}
{this.renderLinksLink()}
{this.renderPermissionsLink()}
- {this.renderHistoryLink()}
{this.renderBackgroundTasksLink()}
{this.renderUpdateKeyLink()}
{this.renderExtensions()}
);
}
- 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 (
- <li key={url}>
- <span className="text-muted" style={{ cursor: 'not-allowed', textDecoration: 'line-through' }}>
- {translate('project_history.page')}
- </span>
- </li>
- );
- }
-
renderBackgroundTasksLink () {
if (!this.props.conf.showBackgroundTasks) {
return null;
{this.renderComponentIssuesLink()}
{this.renderComponentMeasuresLink()}
{this.renderCodeLink()}
+ {this.renderActivityLink()}
{this.renderTools()}
{this.renderAdministration()}
</ul>
},
events: {
- 'submit': 'onSubmit',
+ 'submit': 'handleSubmit',
'keydown .js-search-input': 'onKeyDown',
'keyup .js-search-input': 'onKeyUp'
},
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';
<Route path="custom_measures">{customMeasuresRoutes}</Route>
<Route path="dashboard">{overviewRoutes}</Route>
<Route path="project">
+ <Route path="activity">{projectActivityRoutes}</Route>
<Route path="background_tasks">{backgroundTasksRoutes}</Route>
<Route path="settings">{settingsRoutes}</Route>
{projectAdminRoutes}
--- /dev/null
+/*
+ * 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)
+ )
+);
--- /dev/null
+/*
+ * 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 (
+ <p className="spacer-top note">
+ {translate('no_results')}
+ </p>
+ );
+ }
+
+ return (
+ <ul className="spacer-top">
+ {analyses.map(analysis => (
+ <Analysis key={analysis.key} analysis={analysis}/>
+ ))}
+ </ul>
+ );
+ }
+
+ render () {
+ const { analyses } = this.props;
+ const { loading } = this.state;
+
+ if (loading || !analyses) {
+ return null;
+ }
+
+ return (
+ <div className="overview-meta-card">
+ <h4 className="overview-meta-header">
+ {translate('project_activity.page')}
+ </h4>
+
+ {this.renderList(analyses)}
+
+ <div className="spacer-top small">
+ <Link to={{ pathname: '/project/activity', query: { id: this.props.project } }}>
+ {translate('show_more')}
+ </Link>
+ </div>
+ </div>
+ );
+ }
+}
+
+const mapStateToProps = (state, ownProps: Props) => ({
+ analyses: getAnalyses(getProjectActivity(state), ownProps.project)
+});
+
+const mapDispatchToProps = { fetchRecentProjectActivity };
+
+export default connect(mapStateToProps, mapDispatchToProps)(AnalysesList);
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import React from 'react';
+import 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';
+
+export default class Analysis extends React.Component {
+ props: {
+ analysis: AnalysisType
+ };
+
+ render () {
+ const { analysis } = this.props;
+
+ return (
+ <TooltipsContainer>
+ <li className="overview-analysis">
+ <div className="small little-spacer-bottom">
+ <strong>
+ <FormattedDate date={analysis.date} format="LL"/>
+ </strong>
+ </div>
+
+ {analysis.events.length > 0 ? (
+ <Events events={analysis.events} canAdmin={false}/>
+ ) : (
+ <span className="note">{translate('project_activity.project_analyzed')}</span>
+ )}
+ </li>
+ </TooltipsContainer>
+ );
+ }
+}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2016 SonarSource SA
- * mailto:contact AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import React from 'react';
-import moment from 'moment';
-
-import { EventType } from '../propTypes';
-import { TooltipsContainer } from '../../../components/mixins/tooltips-mixin';
-import { translate } from '../../../helpers/l10n';
-
-const Event = ({ event }) => {
- return (
- <TooltipsContainer>
- <li className="spacer-top">
- <p>
- <strong className="js-event-type">
- {translate('event.category', event.type)}
- </strong>
- {': '}
- <span className="js-event-name">{event.name}</span>
- {event.text && (
- <i
- className="spacer-left icon-help"
- data-toggle="tooltip"
- title={event.text}/>
- )}
- </p>
- <p className="note little-spacer-top js-event-date">
- {moment(event.date).format('LL')}
- </p>
- </li>
- </TooltipsContainer>
- );
-};
-
-Event.propTypes = {
- event: EventType.isRequired
-};
-
-export default Event;
+++ /dev/null
-/*
- * 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 (
- <p className="spacer-top note">
- <a onClick={this.handleClick.bind(this)} href="#">{text}</a>
- </p>
- );
- }
-
- renderList (events) {
- if (events.length) {
- return (
- <ul>
- {events.map(event => (
- <Event key={event.id} event={event}/>
- ))}
- </ul>
- );
- } else {
- return (
- <p className="spacer-top note">
- {translate('no_results')}
- </p>
- );
- }
- }
-
- render () {
- const filteredEvents = this.filterEvents(this.state.events);
- const events = this.limitEvents(filteredEvents);
-
- return (
- <div className="overview-meta-card">
- <div className="clearfix">
- <h4 className="pull-left overview-meta-header">
- {translate('widget.events.name')}
- </h4>
- <div className="pull-right">
- <EventsListFilter
- currentFilter={this.state.filter}
- onFilter={this.handleFilter.bind(this)}/>
- </div>
- </div>
-
- {this.renderList(events)}
-
- {filteredEvents.length > LIMIT && this.renderMoreLink()}
- </div>
- );
- }
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2016 SonarSource SA
- * mailto:contact AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import React from 'react';
-import Select from 'react-select';
-import { translate } from '../../../helpers/l10n';
-
-const TYPES = ['All', 'Version', 'Alert', 'Profile', 'Other'];
-
-const EventsListFilter = ({ currentFilter, onFilter }) => {
- const handleChange = selected => onFilter(selected.value);
-
- const options = TYPES.map(type => {
- return {
- value: type,
- label: translate('event.category', type)
- };
- });
-
- return (
- <Select
- value={currentFilter}
- options={options}
- clearable={false}
- searchable={false}
- onChange={handleChange}
- style={{ width: '125px' }}/>
- );
-};
-
-EventsListFilter.propTypes = {
- onFilter: React.PropTypes.func.isRequired,
- currentFilter: React.PropTypes.string.isRequired
-};
-
-export default EventsListFilter;
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 }) => {
const shouldShowQualityProfiles = !isView && !isDeveloper && hasQualityProfiles;
const shouldShowQualityGate = !isView && !isDeveloper && hasQualityGate;
- const showShowEvents = isProject || isView || isDeveloper;
+ const showShowAnalyses = isProject || isView || isDeveloper;
return (
<div className="overview-meta">
<MetaKey component={component}/>
- {showShowEvents && (
- <EventsList component={component}/>
+ {showShowAnalyses && (
+ <AnalysesList project={component.key}/>
)}
</div>
);
box-sizing: border-box;
}
+.overview-analysis {
+
+}
+
+.overview-analysis + .overview-analysis {
+ margin-top: 8px;
+ padding-top: 8px;
+ border-top: 1px solid #e6e6e6;
+}
+
/*
* Other
*/
--- /dev/null
+/*
+ * 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)
+ );
+};
--- /dev/null
+/*
+ * 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 (
+ <svg width="12" height="12" viewBox="0 0 14 14">
+ <path fill="#236a97"
+ d="M3.35 12.82l.85-.84L2.02 9.8l-.84.85v.98h1.2v1.2h.97zM8.2 4.24c0-.13-.08-.2-.22-.2-.06 0-.1.02-.15.06l-5 5c-.05.05-.08.1-.08.17 0 .13.07.2.2.2.07 0 .12-.02.16-.06l5.02-5c.05-.04.07-.1.07-.16zm-.5-1.77l3.83 3.84-7.7 7.7H0v-3.84l7.7-7.7zm6.3.88c0 .33-.1.6-.34.84L12.12 5.7 8.28 1.88 9.8.35c.24-.23.5-.35.85-.35.32 0 .6.12.84.35l2.16 2.16c.23.25.34.53.34.85z"/>
+ </svg>
+ );
+ }
+}
--- /dev/null
+/*
+ * 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 (
+ <svg width="12" height="12" viewBox="0 0 14 14">
+ <path fill="#d4333f"
+ d="M14 11.27c0 .3-.1.58-.33.8l-1.6 1.6c-.22.22-.5.33-.8.33-.32 0-.6-.1-.8-.33L7 10.2l-3.46 3.47c-.22.22-.5.33-.8.33-.32 0-.6-.1-.8-.33l-1.6-1.6c-.23-.22-.34-.5-.34-.8 0-.32.1-.6.33-.8L3.8 7 .32 3.54C.1 3.32 0 3.04 0 2.74c0-.32.1-.6.33-.8l1.6-1.6c.22-.23.5-.34.8-.34.32 0 .6.1.8.33L7 3.8 10.46.32c.22-.22.5-.33.8-.33.32 0 .6.1.8.33l1.6 1.6c.23.22.34.5.34.8 0 .32-.1.6-.33.8L10.2 7l3.47 3.46c.22.22.33.5.33.8z"/>
+ </svg>
+ );
+ }
+}
--- /dev/null
+.project-activity-event {
+
+}
+
+.project-activity-event + .project-activity-event {
+ margin-top: 4px;
+}
--- /dev/null
+/*
+ * 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 (
+ <div className="project-activity-event">
+ <EventInner event={this.props.event}/>
+
+ {showActions && (
+ <div className="project-activity-event-actions">
+ {canChange && (
+ <button className="js-change-event button-clean" onClick={this.startChanging}>
+ <ChangeIcon/>
+ </button>
+ )}
+ {canDelete && (
+ <button className="js-delete-event button-clean" onClick={this.startDeleting}>
+ <DeleteIcon/>
+ </button>
+ )}
+ </div>
+ )}
+
+ {this.state.changing && (
+ <ChangeCustomEventForm
+ event={this.props.event}
+ onClose={this.stopChanging}/>
+ )}
+
+ {this.state.deleting && (
+ <RemoveCustomEventForm
+ analysis={this.props.analysis}
+ event={this.props.event}
+ onClose={this.stopDeleting}/>
+ )}
+ </div>
+ );
+ }
+}
--- /dev/null
+/*
+ * 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 type { Event as EventType } from '../../../store/projectActivity/duck';
+import { translate } from '../../../helpers/l10n';
+import './Event.css';
+
+export default class EventInner extends React.Component {
+ props: {
+ event: EventType
+ };
+
+ render () {
+ const { event } = this.props;
+
+ if (event.category === 'VERSION') {
+ return (
+ <span className="badge project-activity-version-badge">{this.props.event.name}</span>
+ );
+ }
+
+ return (
+ <span>
+ <span className="note">{translate('event.category', event.category)}:</span>
+ {' '}
+ <strong title={event.description}>{event.name}</strong>
+ </span>
+ );
+ }
+}
--- /dev/null
+/*
+ * 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 sortBy from 'lodash/sortBy';
+import Event from './Event';
+import type { Event as EventType } from '../../../store/projectActivity/duck';
+
+export default class Events extends React.Component {
+ props: {
+ analysis: string,
+ events: Array<EventType>,
+ isFirst: boolean,
+ canAdmin: boolean
+ };
+
+ render () {
+ const sortedEvents: Array<EventType> = sortBy(
+ this.props.events,
+ // versions first
+ (event: EventType) => event.category === 'VERSION' ? 0 : 1,
+ // then the rest sorted by category
+ 'category'
+ );
+
+ return (
+ <div className="project-activity-events">
+ {sortedEvents.map(event => (
+ <Event
+ key={event.key}
+ analysis={this.props.analysis}
+ event={event}
+ isFirst={this.props.isFirst}
+ canAdmin={this.props.canAdmin}/>
+ ))}
+ </div>
+ );
+ }
+}
--- /dev/null
+/*
+ * 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 groupBy from 'lodash/groupBy';
+import moment from 'moment';
+import ProjectActivityAnalysis from './ProjectActivityAnalysis';
+import FormattedDate from '../../../components/ui/FormattedDate';
+import { getProjectActivity } from '../../../store/rootReducer';
+import { getAnalyses } from '../../../store/projectActivity/duck';
+import { translate } from '../../../helpers/l10n';
+
+class ProjectActivityAnalysesList extends React.Component {
+ props: {
+ project: string,
+ analyses?: Array<{
+ key: string,
+ date: string
+ }>,
+ canAdmin: boolean
+ };
+
+ render () {
+ if (!this.props.analyses) {
+ return null;
+ }
+
+ if (this.props.analyses.length === 0) {
+ return (
+ <div className="note">{translate('no_results')}</div>
+ );
+ }
+
+ const firstAnalysis = this.props.analyses[0];
+
+ const byDay = groupBy(this.props.analyses, analysis => moment(analysis.date).startOf('day').valueOf());
+
+ return (
+ <div className="boxed-group boxed-group-inner">
+ <ul className="project-activity-days-list">
+ {Object.keys(byDay).map(day => (
+ <li key={day} className="project-activity-day" data-day={moment(Number(day)).format('YYYY-MM-DD')}>
+ <div className="project-activity-date">
+ <FormattedDate date={Number(day)} format="LL"/>
+ </div>
+
+ <ul className="project-activity-analyses-list">
+ {byDay[day].map(analysis => (
+ <ProjectActivityAnalysis
+ key={analysis.key}
+ analysis={analysis}
+ isFirst={analysis === firstAnalysis}
+ project={this.props.project}
+ canAdmin={this.props.canAdmin}/>
+ ))}
+ </ul>
+ </li>
+ ))}
+ </ul>
+ </div>
+ );
+ }
+}
+
+const mapStateToProps = (state, ownProps) => ({
+ analyses: getAnalyses(getProjectActivity(state), ownProps.project)
+});
+
+export default connect(mapStateToProps)(ProjectActivityAnalysesList);
--- /dev/null
+/*
+ * 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 Events from './Events';
+import AddVersionForm from './forms/AddVersionForm';
+import AddCustomEventForm from './forms/AddCustomEventForm';
+import RemoveAnalysisForm from './forms/RemoveAnalysisForm';
+import FormattedDate from '../../../components/ui/FormattedDate';
+import type { Analysis } from '../../../store/projectActivity/duck';
+import { translate } from '../../../helpers/l10n';
+
+export default class ProjectActivityAnalysis extends React.Component {
+ props: {
+ analysis: Analysis,
+ isFirst: boolean,
+ project: string,
+ canAdmin: boolean
+ };
+
+ render () {
+ const { date, events } = this.props.analysis;
+ const { isFirst, canAdmin } = this.props;
+
+ const version = events.find(event => event.category === 'VERSION');
+
+ return (
+ <li className="project-activity-analysis clearfix">
+ {canAdmin && (
+ <div className="project-activity-analysis-actions">
+ <div className="dropdown display-inline-block">
+ <button className="js-create button-small" data-toggle="dropdown">
+ {translate('create')} <i className="icon-dropdown"/>
+ </button>
+ <ul className="dropdown-menu dropdown-menu-right">
+ {version == null && (
+ <li>
+ <AddVersionForm analysis={this.props.analysis}/>
+ </li>
+ )}
+ <li>
+ <AddCustomEventForm analysis={this.props.analysis}/>
+ </li>
+ </ul>
+ </div>
+
+ {!isFirst && (
+ <div className="display-inline-block little-spacer-left">
+ <RemoveAnalysisForm
+ analysis={this.props.analysis}
+ project={this.props.project}/>
+ </div>
+ )}
+ </div>
+ )}
+
+ <div className="project-activity-time">
+ <FormattedDate date={date} format="LT" tooltipFormat="LTS"/>
+ </div>
+
+ {events.length > 0 && (
+ <Events
+ analysis={this.props.analysis.key}
+ events={events}
+ isFirst={this.props.isFirst}
+ canAdmin={canAdmin}/>
+ )}
+ </li>
+ );
+ }
+}
--- /dev/null
+/*
+ * 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 ProjectActivityPageHeader from './ProjectActivityPageHeader';
+import ProjectActivityAnalysesList from './ProjectActivityAnalysesList';
+import ProjectActivityPageFooter from './ProjectActivityPageFooter';
+import { fetchProjectActivity } from '../actions';
+import { getComponent } from '../../../store/rootReducer';
+import './projectActivity.css';
+
+type Props = {
+ location: { query: { id: string } },
+ fetchProjectActivity: (project: string) => void,
+ filter: ?string,
+ project: { configuration?: { showHistory: boolean } }
+};
+
+type State = {
+ filter: ?string
+};
+
+class ProjectActivityApp extends React.Component {
+ props: Props;
+
+ state: State = {
+ filter: null
+ };
+
+ componentDidMount () {
+ document.querySelector('html').classList.add('dashboard-page');
+ this.props.fetchProjectActivity(this.props.location.query.id);
+ }
+
+ componentWillUnmount () {
+ document.querySelector('html').classList.remove('dashboard-page');
+ }
+
+ handleFilter = (filter: ?string) => {
+ this.setState({ filter });
+ this.props.fetchProjectActivity(this.props.location.query.id, filter);
+ };
+
+ render () {
+ const project = this.props.location.query.id;
+ const { configuration } = this.props.project;
+ const canAdmin = configuration ? configuration.showHistory : false;
+
+ return (
+ <div id="project-activity" className="page page-limited">
+ <ProjectActivityPageHeader
+ project={project}
+ filter={this.state.filter}
+ changeFilter={this.handleFilter}/>
+
+ <ProjectActivityAnalysesList
+ project={project}
+ canAdmin={canAdmin}/>
+
+ <ProjectActivityPageFooter
+ project={project}/>
+ </div>
+ );
+ }
+}
+
+const mapStateToProps = (state, ownProps: Props) => ({
+ project: getComponent(state, ownProps.location.query.id)
+});
+
+const mapDispatchToProps = { fetchProjectActivity };
+
+export default connect(mapStateToProps, mapDispatchToProps)(ProjectActivityApp);
--- /dev/null
+/*
+ * 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 ListFooter from '../../../components/controls/ListFooter';
+import { getProjectActivity } from '../../../store/rootReducer';
+import { getAnalyses, getPaging } from '../../../store/projectActivity/duck';
+import { fetchMoreProjectActivity } from '../actions';
+import type { Paging } from '../../../store/projectActivity/duck';
+
+class ProjectActivityPageFooter extends React.Component {
+ props: {
+ analyses: Array<*>,
+ paging: ?Paging,
+ project: string,
+ fetchMoreProjectActivity: (project: string) => void
+ };
+
+ handleLoadMore = () => {
+ this.props.fetchMoreProjectActivity(this.props.project);
+ };
+
+ render () {
+ const { analyses, paging } = this.props;
+
+ if (!paging || analyses.length === 0) {
+ return null;
+ }
+
+ return (
+ <ListFooter count={analyses.length} total={paging.total} loadMore={this.handleLoadMore}/>
+ );
+ }
+}
+
+const mapStateToProps = (state, ownProps) => ({
+ analyses: getAnalyses(getProjectActivity(state), ownProps.project),
+ paging: getPaging(getProjectActivity(state), ownProps.project)
+});
+
+const mapDispatchToProps = { fetchMoreProjectActivity };
+
+export default connect(mapStateToProps, mapDispatchToProps)(ProjectActivityPageFooter);
--- /dev/null
+/*
+ * 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 Select from 'react-select';
+import { translate } from '../../../helpers/l10n';
+
+type Props = {
+ changeFilter: (filter: ?string) => void,
+ filter: ?string,
+ project: string
+};
+
+export default class ProjectActivityPageHeader extends React.Component {
+ props: Props;
+
+ handleChange = (option: null | { value: string }) => {
+ this.props.changeFilter(option && option.value);
+ }
+
+ render () {
+ const selectOptions = ['VERSION', 'QUALITY_GATE', 'QUALITY_PROFILE', 'OTHER'].map(category => ({
+ label: translate('event.category', category),
+ value: category
+ }));
+
+ return (
+ <header className="page-header">
+ <div className="page-actions">
+ <Select
+ className="input-medium"
+ placeholder={translate('filter_verb') + '...'}
+ clearable={true}
+ searchable={false}
+ value={this.props.filter}
+ options={selectOptions}
+ onChange={this.handleChange}/>
+ </div>
+
+ <div className="page-description">
+ {translate('project_activity.page.description')}
+ </div>
+ </header>
+ );
+ }
+}
--- /dev/null
+/*
+ * 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 => (
+ <AddEventForm {...props} addEventButtonText="project_activity.add_custom_event"/>
+);
+
+const mapStateToProps = null;
+
+const mapDispatchToProps = { addEvent: addCustomEvent };
+
+export default connect(mapStateToProps, mapDispatchToProps)(AddCustomEventForm);
--- /dev/null
+/*
+ * 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 (
+ <Modal isOpen={true}
+ contentLabel="modal form"
+ className="modal"
+ overlayClassName="modal-overlay"
+ onRequestClose={this.closeForm}>
+
+ <header className="modal-head">
+ <h2>{translate(this.props.addEventButtonText)}</h2>
+ </header>
+
+ <form onSubmit={this.handleSubmit}>
+ <div className="modal-body">
+ <div className="modal-field">
+ <label>{translate('name')}</label>
+ <input
+ value={this.state.name}
+ autoFocus={true}
+ disabled={this.state.processing}
+ className="input-medium"
+ type="text"
+ onChange={this.changeInput}/>
+ </div>
+ </div>
+
+ <footer className="modal-foot">
+ {this.state.processing ? (
+ <i className="spinner"/>
+ ) : (
+ <div>
+ <button type="submit">{translate('save')}</button>
+ <button type="reset" className="button-link" onClick={this.closeForm}>
+ {translate('cancel')}
+ </button>
+ </div>
+ )}
+ </footer>
+ </form>
+
+ </Modal>
+ );
+ }
+
+ render () {
+ return (
+ <a className="js-add-event button-small" href="#" onClick={this.openForm}>
+ {translate(this.props.addEventButtonText)}
+ {this.state.open && this.renderModal()}
+ </a>
+ );
+ }
+}
--- /dev/null
+/*
+ * 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 => (
+ <AddEventForm {...props} addEventButtonText="project_activity.add_version"/>
+);
+
+const mapStateToProps = null;
+
+const mapDispatchToProps = { addEvent: addVersion };
+
+export default connect(mapStateToProps, mapDispatchToProps)(AddVersionForm);
--- /dev/null
+/*
+ * 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 => (
+ <ChangeEventForm
+ {...props}
+ changeEventButtonText="project_activity.change_custom_event"/>
+);
+
+const mapStateToProps = null;
+
+const mapDispatchToProps = { changeEvent };
+
+export default connect(mapStateToProps, mapDispatchToProps)(ChangeCustomEventForm);
--- /dev/null
+/*
+ * 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 (
+ <Modal isOpen={true}
+ contentLabel="modal form"
+ className="modal"
+ overlayClassName="modal-overlay"
+ onRequestClose={this.closeForm}>
+
+ <header className="modal-head">
+ <h2>{translate(this.props.changeEventButtonText)}</h2>
+ </header>
+
+ <form onSubmit={this.handleSubmit}>
+ <div className="modal-body">
+ <div className="modal-field">
+ <label>{translate('name')}</label>
+ <input
+ value={this.state.name}
+ autoFocus={true}
+ disabled={this.state.processing}
+ className="input-medium"
+ type="text"
+ onChange={this.changeInput}/>
+ </div>
+ </div>
+
+ <footer className="modal-foot">
+ {this.state.processing ? (
+ <i className="spinner"/>
+ ) : (
+ <div>
+ <button type="submit">{translate('change_verb')}</button>
+ <button type="reset" className="button-link" onClick={this.closeForm}>
+ {translate('cancel')}
+ </button>
+ </div>
+ )}
+ </footer>
+ </form>
+
+ </Modal>
+ );
+ }
+}
--- /dev/null
+/*
+ * 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 => (
+ <ChangeEventForm
+ {...props}
+ changeEventButtonText="project_activity.change_version"/>
+);
+
+const mapStateToProps = null;
+
+const mapDispatchToProps = { changeEvent };
+
+export default connect(mapStateToProps, mapDispatchToProps)(ChangeVersionForm);
--- /dev/null
+/*
+ * 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 (
+ <Modal isOpen={true}
+ contentLabel="modal form"
+ className="modal"
+ overlayClassName="modal-overlay"
+ onRequestClose={this.closeForm}>
+
+ <header className="modal-head">
+ <h2>{translate('project_activity.delete_analysis')}</h2>
+ </header>
+
+ <form onSubmit={this.handleSubmit}>
+ <div className="modal-body">
+ {translate('project_activity.delete_analysis.question')}
+ </div>
+
+ <footer className="modal-foot">
+ {this.state.processing ? (
+ <i className="spinner"/>
+ ) : (
+ <div>
+ <button type="submit" className="button-red">{translate('delete')}</button>
+ <button type="reset" className="button-link" onClick={this.closeForm}>
+ {translate('cancel')}
+ </button>
+ </div>
+ )}
+ </footer>
+ </form>
+
+ </Modal>
+ );
+ }
+
+ render () {
+ return (
+ <button className="js-delete-analysis button-small button-red" onClick={this.openForm}>
+ {translate('delete')}
+ {this.state.open && this.renderModal()}
+ </button>
+ );
+ }
+}
+
+const mapStateToProps = null;
+
+const mapDispatchToProps = { deleteAnalysis };
+
+export default connect(mapStateToProps, mapDispatchToProps)(RemoveAnalysisForm);
--- /dev/null
+/*
+ * 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 => (
+ <RemoveEventForm
+ {...props}
+ removeEventButtonText="project_activity.remove_custom_event"
+ removeEventQuestion="project_activity.remove_custom_event.question"/>
+);
+
+const mapStateToProps = null;
+
+const mapDispatchToProps = { deleteEvent };
+
+export default connect(mapStateToProps, mapDispatchToProps)(RemoveCustomEventForm);
--- /dev/null
+/*
+ * 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 (
+ <Modal isOpen={true}
+ contentLabel="modal form"
+ className="modal"
+ overlayClassName="modal-overlay"
+ onRequestClose={this.closeForm}>
+
+ <header className="modal-head">
+ <h2>{translate(this.props.removeEventButtonText)}</h2>
+ </header>
+
+ <form onSubmit={this.handleSubmit}>
+ <div className="modal-body">
+ {translate(this.props.removeEventQuestion)}
+ </div>
+
+ <footer className="modal-foot">
+ {this.state.processing ? (
+ <i className="spinner"/>
+ ) : (
+ <div>
+ <button type="submit" className="button-red" autoFocus={true}>{translate('delete')}</button>
+ <button type="reset" className="button-link" onClick={this.closeForm}>
+ {translate('cancel')}
+ </button>
+ </div>
+ )}
+ </footer>
+ </form>
+
+ </Modal>
+ );
+ }
+}
--- /dev/null
+/*
+ * 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 => (
+ <RemoveEventForm
+ {...props}
+ removeEventButtonText="project_activity.remove_version"
+ removeEventQuestion="project_activity.remove_version.question"/>
+);
+
+const mapStateToProps = null;
+
+const mapDispatchToProps = { deleteEvent };
+
+export default connect(mapStateToProps, mapDispatchToProps)(RemoveVersionForm);
--- /dev/null
+.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;
+}
--- /dev/null
+/*
+ * 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 (
+ <IndexRoute component={ProjectActivityApp}/>
+);
--- /dev/null
+/*
+ * 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 moment from 'moment';
+
+export default class FormattedDate extends React.Component {
+ props: {
+ date: string | number,
+ format?: string,
+ tooltipFormat?: string
+ };
+
+ static defaultProps = {
+ format: 'LLL'
+ };
+
+ render () {
+ const { date, format, tooltipFormat } = this.props;
+
+ const m = moment(date);
+
+ const title = tooltipFormat ? m.format(tooltipFormat) : undefined;
+
+ return (
+ <time dateTime={m.format()} title={title}>
+ {m.format(format)}
+ </time>
+ );
+ }
+}
--- /dev/null
+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"
+ }
+}
+`;
--- /dev/null
+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"
+ ]
+}
+`;
--- /dev/null
+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
+}
+`;
--- /dev/null
+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"
+ }
+}
+`;
--- /dev/null
+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
+ }
+}
+`;
--- /dev/null
+/*
+ * 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();
+});
--- /dev/null
+/*
+ * 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();
+});
--- /dev/null
+/*
+ * 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();
+ });
+});
--- /dev/null
+/*
+ * 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();
+});
--- /dev/null
+/*
+ * 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();
+});
--- /dev/null
+/*
+ * 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<string>
+};
+
+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]
+);
--- /dev/null
+/*
+ * 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<string>
+};
+
+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;
+ }
+};
--- /dev/null
+/*
+ * 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<Event>
+};
+
+export type Paging = {
+ total: number,
+ pageIndex: number,
+ pageSize: number
+};
+
+export type ReceiveProjectActivityAction = {
+ type: 'RECEIVE_PROJECT_ACTIVITY',
+ project: string,
+ analyses: Array<Analysis>,
+ 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<Analysis>,
+ 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<Event> = 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]
+);
--- /dev/null
+/*
+ * 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]
+);
--- /dev/null
+/*
+ * 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;
+};
+
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)))
);
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';
favorites,
languages,
measures,
+ projectActivity,
users,
// apps
fromMeasures.getComponentMeasures(state.measures, componentKey)
);
+export const getProjectActivity = state => (
+ state.projectActivity
+);
+
export const getProjects = state => (
fromProjectsApp.getProjects(state.projectsApp)
);
export default function configureStore (rootReducer, initialState) {
return finalCreateStore(rootReducer, initialState);
}
+
+export const configureTestStore = (rootReducer, initialState) => (
+ createStore(rootReducer, initialState)
+);
@import (reference) "../mixins";
@import (reference) "../variables";
-.modal {
+.modal,
+.ReactModal__Content {
position: fixed;
z-index: @modal-z-index;
top: 0;
transition: all 0.2s ease;
}
-.modal.in {
+.modal.in,
+.ReactModal__Content--after-open {
top: 15%;
opacity: 1;
}
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;
}
.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 {
.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,
.button-clean,
.button-clean:hover,
.button-clean:focus {
- margin: 0;
padding: 0;
line-height: 1;
border: none;
color: @baseFontColor;
}
+.button-clean path {
+ transition: opacity 0.3s ease;
+}
+
+.button-clean:hover path {
+ opacity: 0.8;
+}
+
.button-link {
display: inline;
height: auto;
}
}
+.button-small {
+ height: 20px;
+ line-height: 18px;
+
+ & > svg {
+ margin-top: 2px;
+ }
+}
+
.button-group {
display: inline-block;
vertical-align: middle;
# 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"
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"
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:
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:
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"
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:
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:
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"
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"
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"
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"
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:
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"
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"
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"
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:
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"
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"
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"
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"
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"
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"
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"
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"
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"
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"
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:
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"
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"
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"
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:
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:
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:
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"
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:
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"
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:
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"
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"
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"
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:
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:
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"
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"
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"
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"
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"
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"
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"
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"
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:
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:
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"
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"
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:
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:
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:
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:
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"
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:
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"
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"
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"
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"
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:
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"
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"
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:
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"
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"
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"
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:
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:
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"
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"
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"
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:
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:
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:
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"
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"
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:
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:
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"
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"
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"
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"
cliui "^2.1.0"
decamelize "^1.0.0"
window-size "0.1.0"
-
#------------------------------------------------------------------------------
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
#------------------------------------------------------------------------------
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.
#------------------------------------------------------------------------------
#
#------------------------------------------------------------------------------
#
-# 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