From f0da51dc6ad711b31f92af91050357d41187eb5b Mon Sep 17 00:00:00 2001 From: =?utf8?q?Gr=C3=A9goire=20Aubert?= Date: Fri, 7 Jul 2017 16:21:18 +0200 Subject: [PATCH] SONAR-8611 Add shortcuts to project activity page on project dashboard --- .../overview/main/BugsAndVulnerabilities.js | 10 ++-- .../main/js/apps/overview/main/CodeSmells.js | 6 +- .../main/js/apps/overview/main/Coverage.js | 1 + .../js/apps/overview/main/Duplications.js | 1 + .../src/main/js/apps/overview/main/enhance.js | 58 ++++++++++++------- .../src/main/js/apps/overview/styles.css | 17 ++++++ .../pageobjects/ProjectDashboardPage.java | 9 +++ .../tests/measure/ProjectDashboardTest.java | 16 +++++ 8 files changed, 90 insertions(+), 28 deletions(-) diff --git a/server/sonar-web/src/main/js/apps/overview/main/BugsAndVulnerabilities.js b/server/sonar-web/src/main/js/apps/overview/main/BugsAndVulnerabilities.js index db8f370c60f..1de56542c21 100644 --- a/server/sonar-web/src/main/js/apps/overview/main/BugsAndVulnerabilities.js +++ b/server/sonar-web/src/main/js/apps/overview/main/BugsAndVulnerabilities.js @@ -69,7 +69,7 @@ class BugsAndVulnerabilities extends React.PureComponent { {this.props.renderRating('new_reliability_rating')}
- + {getMetricName('new_bugs')}
@@ -82,7 +82,7 @@ class BugsAndVulnerabilities extends React.PureComponent { {this.props.renderRating('new_security_rating')}
- + {getMetricName('new_vulnerabilities')}
@@ -103,8 +103,9 @@ class BugsAndVulnerabilities extends React.PureComponent { {this.props.renderRating('reliability_rating')}
- + {getMetricName('bugs')} + {this.props.renderHistoryLink('bugs')}
@@ -116,8 +117,9 @@ class BugsAndVulnerabilities extends React.PureComponent { {this.props.renderRating('security_rating')}
- + {getMetricName('vulnerabilities')} + {this.props.renderHistoryLink('vulnerabilities')}
diff --git a/server/sonar-web/src/main/js/apps/overview/main/CodeSmells.js b/server/sonar-web/src/main/js/apps/overview/main/CodeSmells.js index 44ef34fa0a4..6ae5012f443 100644 --- a/server/sonar-web/src/main/js/apps/overview/main/CodeSmells.js +++ b/server/sonar-web/src/main/js/apps/overview/main/CodeSmells.js @@ -99,7 +99,7 @@ class CodeSmells extends React.PureComponent { {this.props.renderIssues('new_code_smells', 'CODE_SMELL')}
- + {getMetricName('new_code_smells')}
@@ -123,6 +123,7 @@ class CodeSmells extends React.PureComponent {
{getMetricName('effort')} + {this.props.renderHistoryLink('sqale_rating')}
@@ -133,8 +134,9 @@ class CodeSmells extends React.PureComponent { {this.props.renderIssues('code_smells', 'CODE_SMELL')}
- + {getMetricName('code_smells')} + {this.props.renderHistoryLink('code_smells')}
diff --git a/server/sonar-web/src/main/js/apps/overview/main/Coverage.js b/server/sonar-web/src/main/js/apps/overview/main/Coverage.js index b2eeb752d25..2c86b6e6970 100644 --- a/server/sonar-web/src/main/js/apps/overview/main/Coverage.js +++ b/server/sonar-web/src/main/js/apps/overview/main/Coverage.js @@ -76,6 +76,7 @@ class Coverage extends React.PureComponent {
{getMetricName('coverage')} + {this.props.renderHistoryLink('coverage')}
diff --git a/server/sonar-web/src/main/js/apps/overview/main/Duplications.js b/server/sonar-web/src/main/js/apps/overview/main/Duplications.js index d0989dcddf1..c6e9a8cd18f 100644 --- a/server/sonar-web/src/main/js/apps/overview/main/Duplications.js +++ b/server/sonar-web/src/main/js/apps/overview/main/Duplications.js @@ -58,6 +58,7 @@ class Duplications extends React.PureComponent {
{getMetricName('duplications')} + {this.props.renderHistoryLink('duplicated_lines_density')}
diff --git a/server/sonar-web/src/main/js/apps/overview/main/enhance.js b/server/sonar-web/src/main/js/apps/overview/main/enhance.js index f6d450c661a..2bd0e72530b 100644 --- a/server/sonar-web/src/main/js/apps/overview/main/enhance.js +++ b/server/sonar-web/src/main/js/apps/overview/main/enhance.js @@ -21,6 +21,7 @@ import React from 'react'; import { Link } from 'react-router'; import moment from 'moment'; import { DrilldownLink } from '../../../components/shared/drilldown-link'; +import HistoryIcon from '../../../components/icons-components/HistoryIcon'; import Rating from './../../../components/ui/Rating'; import Timeline from '../components/Timeline'; import { @@ -33,13 +34,13 @@ import { } from '../../../helpers/measures'; import { translateWithParameters } from '../../../helpers/l10n'; import { getPeriodDate } from '../../../helpers/periods'; -import { getComponentIssuesUrl } from '../../../helpers/urls'; +import { getComponentIssuesUrl, getComponentMeasureHistory } from '../../../helpers/urls'; export default function enhance(ComposedComponent) { return class extends React.PureComponent { static displayName = `enhance(${ComposedComponent.displayName})}`; - getValue(measure) { + getValue = measure => { const { leakPeriod } = this.props; if (!measure) { @@ -49,9 +50,9 @@ export default function enhance(ComposedComponent) { return isDiffMetric(measure.metric.key) ? getPeriodValue(measure, leakPeriod.index) : measure.value; - } + }; - renderHeader(domain, label) { + renderHeader = (domain, label) => { const { component } = this.props; const domainUrl = { pathname: `/component_measures/domain/${domain}`, @@ -65,9 +66,9 @@ export default function enhance(ComposedComponent) { ); - } + }; - renderMeasure(metricKey) { + renderMeasure = metricKey => { const { measures, component } = this.props; const measure = measures.find(measure => measure.metric.key === metricKey); @@ -87,12 +88,13 @@ export default function enhance(ComposedComponent) {
{measure.metric.name} + {this.renderHistoryLink(measure.metric.key)}
); - } + }; - renderMeasureVariation(metricKey, customLabel) { + renderMeasureVariation = (metricKey, customLabel) => { const NO_VALUE = '—'; const { measures, leakPeriod } = this.props; const measure = measures.find(measure => measure.metric.key === metricKey); @@ -111,8 +113,8 @@ export default function enhance(ComposedComponent) { ); - } - renderRating(metricKey) { + }; + renderRating = metricKey => { const { component, measures } = this.props; const measure = measures.find(measure => measure.metric.key === metricKey); if (!measure) { @@ -127,8 +129,8 @@ export default function enhance(ComposedComponent) { ); - } - renderIssues(metric, type) { + }; + renderIssues = (metric, type) => { const { measures, component } = this.props; const measure = measures.find(measure => measure.metric.key === metric); const value = this.getValue(measure); @@ -148,8 +150,19 @@ export default function enhance(ComposedComponent) { ); - } - renderTimeline(metricKey, range, children) { + }; + renderHistoryLink = metricKey => { + const linkClass = + 'button button-small button-compact spacer-left overview-domain-measure-history-link'; + return ( + + + + ); + }; + renderTimeline = (metricKey, range, children) => { if (!this.props.history) { return null; } @@ -167,18 +180,19 @@ export default function enhance(ComposedComponent) { {children} ); - } + }; render() { return ( ); } diff --git a/server/sonar-web/src/main/js/apps/overview/styles.css b/server/sonar-web/src/main/js/apps/overview/styles.css index 45911113921..5de0ceca320 100644 --- a/server/sonar-web/src/main/js/apps/overview/styles.css +++ b/server/sonar-web/src/main/js/apps/overview/styles.css @@ -246,10 +246,27 @@ margin-top: 10px; } +.overview-domain-measure-label > svg { + margin-top: 3px; +} + .overview-domain-leak .overview-domain-measure-label { text-align: center; } +.overview-domain-leak .overview-domain-measure-label > svg { + margin-top: 0; +} + +.overview-domain-measure-history-link { + vertical-align: bottom; + visibility: hidden; +} + +.overview-domain-measure:hover .overview-domain-measure-history-link { + visibility: visible; +} + .overview-domain-measure-sup { display: inline-block; vertical-align: top; diff --git a/tests/src/test/java/org/sonarqube/pageobjects/ProjectDashboardPage.java b/tests/src/test/java/org/sonarqube/pageobjects/ProjectDashboardPage.java index f576ea4cc32..60969c43fa5 100644 --- a/tests/src/test/java/org/sonarqube/pageobjects/ProjectDashboardPage.java +++ b/tests/src/test/java/org/sonarqube/pageobjects/ProjectDashboardPage.java @@ -19,13 +19,16 @@ */ package org.sonarqube.pageobjects; +import com.codeborne.selenide.ElementsCollection; import com.codeborne.selenide.SelenideElement; import java.util.Arrays; import static com.codeborne.selenide.Condition.exist; import static com.codeborne.selenide.Condition.hasText; +import static com.codeborne.selenide.Condition.text; import static com.codeborne.selenide.Condition.visible; import static com.codeborne.selenide.Selenide.$; +import static com.codeborne.selenide.Selenide.$$; public class ProjectDashboardPage { @@ -45,6 +48,12 @@ public class ProjectDashboardPage { return element; } + public SelenideElement getOverviewMeasure(String measure) { + ElementsCollection measures = $$(".overview-domain-measure"); + SelenideElement element = measures.find(text(measure)).shouldBe(visible); + return element; + } + private SelenideElement getTagsMeta() { SelenideElement element = $(".overview-meta-tags"); element.shouldBe(visible); diff --git a/tests/src/test/java/org/sonarqube/tests/measure/ProjectDashboardTest.java b/tests/src/test/java/org/sonarqube/tests/measure/ProjectDashboardTest.java index 584938877da..956c8e7f109 100644 --- a/tests/src/test/java/org/sonarqube/tests/measure/ProjectDashboardTest.java +++ b/tests/src/test/java/org/sonarqube/tests/measure/ProjectDashboardTest.java @@ -34,8 +34,10 @@ import org.sonarqube.pageobjects.Navigation; import org.sonarqube.pageobjects.ProjectDashboardPage; import util.user.UserRule; +import static com.codeborne.selenide.Condition.exist; import static com.codeborne.selenide.Condition.hasText; import static com.codeborne.selenide.Condition.text; +import static com.codeborne.selenide.Condition.visible; import static util.ItUtils.newAdminWsClient; import static util.ItUtils.projectDir; import static util.selenium.Selenese.runSelenese; @@ -121,6 +123,20 @@ public class ProjectDashboardTest { .shouldHaveTags("test"); } + @Test + public void display_project_activity_shortcut() { + executeBuild("shared/xoo-sample", "sample-with-tags", "Sample with tags"); + // Add some tags to another project to have them in the list + wsClient.wsConnector().call( + new PostRequest("api/project_tags/set") + .setParam("project", "sample-with-tags") + .setParam("tags", "foo,bar,baz")); + + executeBuild("shared/xoo-sample", "sample", "Sample"); + ProjectDashboardPage page = nav.logIn().submitCredentials(adminUser).openProjectDashboard("sample"); + page.getOverviewMeasure("Debt").$(".overview-domain-measure-history-link").should(exist); + } + @Test @Ignore("there is no more place to show the error") public void display_a_nice_error_when_requesting_unknown_project() { -- 2.39.5