aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWouter Admiraal <wouter.admiraal@sonarsource.com>2020-06-15 17:46:06 +0200
committersonartech <sonartech@sonarsource.com>2020-06-19 20:04:42 +0000
commitae807c088ed8910660af642766692feb62bfdab0 (patch)
tree755860c9fd36303babc24b41cb411144e981e28a
parent72a34678a0da474c17e1d375a7e9f8699f9433ce (diff)
downloadsonarqube-ae807c088ed8910660af642766692feb62bfdab0.tar.gz
sonarqube-ae807c088ed8910660af642766692feb62bfdab0.zip
SONAR-13075 Show a legend for the New Code period on the activity graph
-rw-r--r--server/sonar-web/src/main/js/apps/overview/styles.css14
-rw-r--r--server/sonar-web/src/main/js/components/activity-graph/GraphHistory.tsx9
-rw-r--r--server/sonar-web/src/main/js/components/activity-graph/GraphsLegendCustom.tsx61
-rw-r--r--server/sonar-web/src/main/js/components/activity-graph/GraphsLegendNewCode.tsx34
-rw-r--r--server/sonar-web/src/main/js/components/activity-graph/GraphsLegendStatic.tsx8
-rw-r--r--server/sonar-web/src/main/js/components/activity-graph/__tests__/GraphsLegendCustom-test.tsx58
-rw-r--r--server/sonar-web/src/main/js/components/activity-graph/__tests__/GraphsLegendNewCode-test.tsx31
-rw-r--r--server/sonar-web/src/main/js/components/activity-graph/__tests__/GraphsLegendStatic-test.tsx25
-rw-r--r--server/sonar-web/src/main/js/components/activity-graph/__tests__/__snapshots__/GraphHistory-test.tsx.snap1
-rw-r--r--server/sonar-web/src/main/js/components/activity-graph/__tests__/__snapshots__/GraphsLegendCustom-test.tsx.snap124
-rw-r--r--server/sonar-web/src/main/js/components/activity-graph/__tests__/__snapshots__/GraphsLegendNewCode-test.tsx.snap14
-rw-r--r--server/sonar-web/src/main/js/components/activity-graph/__tests__/__snapshots__/GraphsLegendStatic-test.tsx.snap24
-rw-r--r--server/sonar-web/src/main/js/components/activity-graph/styles.css14
-rw-r--r--sonar-core/src/main/resources/org/sonar/l10n/core.properties2
14 files changed, 321 insertions, 98 deletions
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 d07c641e950..ccdaeb8c740 100644
--- a/server/sonar-web/src/main/js/apps/overview/styles.css
+++ b/server/sonar-web/src/main/js/apps/overview/styles.css
@@ -272,6 +272,20 @@
margin-top: -30px;
}
+.overview-panel .activity-graph-new-code-legend {
+ position: relative;
+ z-index: var(--aboveNormalZIndex);
+ width: 12px;
+ overflow: hidden;
+ margin-top: 1px;
+ margin-left: calc(2 * var(--gridSize));
+ text-indent: -9999px;
+}
+
+.overview-panel .activity-graph-new-code-legend::after {
+ margin: 0;
+}
+
.overview-analysis {
color: var(--secondFontColor);
}
diff --git a/server/sonar-web/src/main/js/components/activity-graph/GraphHistory.tsx b/server/sonar-web/src/main/js/components/activity-graph/GraphHistory.tsx
index da94b4e0a08..366cc3aac76 100644
--- a/server/sonar-web/src/main/js/components/activity-graph/GraphHistory.tsx
+++ b/server/sonar-web/src/main/js/components/activity-graph/GraphHistory.tsx
@@ -85,10 +85,15 @@ export default class GraphHistory extends React.PureComponent<Props, State> {
return (
<div className="activity-graph-container flex-grow display-flex-column display-flex-stretch display-flex-justify-center">
{isCustom && this.props.removeCustomMetric ? (
- <GraphsLegendCustom removeMetric={this.props.removeCustomMetric} series={series} />
+ <GraphsLegendCustom
+ removeMetric={this.props.removeCustomMetric}
+ series={series}
+ showLeakLegend={Boolean(leakPeriodDate)}
+ />
) : (
- <GraphsLegendStatic series={series} />
+ <GraphsLegendStatic series={series} showLeakLegend={Boolean(leakPeriodDate)} />
)}
+
<div className="flex-1">
<AutoSizer>
{({ height, width }) => (
diff --git a/server/sonar-web/src/main/js/components/activity-graph/GraphsLegendCustom.tsx b/server/sonar-web/src/main/js/components/activity-graph/GraphsLegendCustom.tsx
index aaf71573351..0e120067944 100644
--- a/server/sonar-web/src/main/js/components/activity-graph/GraphsLegendCustom.tsx
+++ b/server/sonar-web/src/main/js/components/activity-graph/GraphsLegendCustom.tsx
@@ -22,42 +22,49 @@ import Tooltip from 'sonar-ui-common/components/controls/Tooltip';
import { translate } from 'sonar-ui-common/helpers/l10n';
import { Serie } from '../../types/project-activity';
import GraphsLegendItem from './GraphsLegendItem';
+import GraphsLegendNewCode from './GraphsLegendNewCode';
import { hasDataValues } from './utils';
-interface Props {
+export interface GraphsLegendCustomProps {
removeMetric: (metric: string) => void;
series: Serie[];
+ showLeakLegend: boolean;
}
-export default function GraphsLegendCustom({ removeMetric, series }: Props) {
+export default function GraphsLegendCustom(props: GraphsLegendCustomProps) {
+ const { series, showLeakLegend } = props;
return (
- <div className="activity-graph-legends">
- {series.map((serie, idx) => {
- const hasData = hasDataValues(serie);
- const legendItem = (
- <GraphsLegendItem
- index={idx}
- metric={serie.name}
- name={serie.translatedName}
- removeMetric={removeMetric}
- showWarning={!hasData}
- />
- );
- if (!hasData) {
+ <div className="activity-graph-legends display-flex-center">
+ <div className="flex-1">
+ {series.map((serie, idx) => {
+ const hasData = hasDataValues(serie);
+ const legendItem = (
+ <GraphsLegendItem
+ index={idx}
+ metric={serie.name}
+ name={serie.translatedName}
+ removeMetric={props.removeMetric}
+ showWarning={!hasData}
+ />
+ );
+ if (!hasData) {
+ return (
+ <Tooltip
+ key={serie.name}
+ overlay={translate('project_activity.graphs.custom.metric_no_history')}>
+ <span className="spacer-left spacer-right">{legendItem}</span>
+ </Tooltip>
+ );
+ }
return (
- <Tooltip
- key={serie.name}
- overlay={translate('project_activity.graphs.custom.metric_no_history')}>
- <span className="spacer-left spacer-right">{legendItem}</span>
- </Tooltip>
+ <span className="spacer-left spacer-right" key={serie.name}>
+ {legendItem}
+ </span>
);
- }
- return (
- <span className="spacer-left spacer-right" key={serie.name}>
- {legendItem}
- </span>
- );
- })}
+ })}
+ </div>
+
+ {showLeakLegend && <GraphsLegendNewCode />}
</div>
);
}
diff --git a/server/sonar-web/src/main/js/components/activity-graph/GraphsLegendNewCode.tsx b/server/sonar-web/src/main/js/components/activity-graph/GraphsLegendNewCode.tsx
new file mode 100644
index 00000000000..d128f685a74
--- /dev/null
+++ b/server/sonar-web/src/main/js/components/activity-graph/GraphsLegendNewCode.tsx
@@ -0,0 +1,34 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2020 SonarSource SA
+ * mailto:info 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 * as React from 'react';
+import Tooltip from 'sonar-ui-common/components/controls/Tooltip';
+import { translate } from 'sonar-ui-common/helpers/l10n';
+
+export default function GraphsLegendNewCode() {
+ return (
+ <Tooltip overlay={translate('project_activity.graphs.new_code_long')}>
+ <span
+ aria-label={translate('project_activity.graphs.new_code_long')}
+ className="activity-graph-new-code-legend display-flex-center pull-right note">
+ {translate('project_activity.graphs.new_code')}
+ </span>
+ </Tooltip>
+ );
+}
diff --git a/server/sonar-web/src/main/js/components/activity-graph/GraphsLegendStatic.tsx b/server/sonar-web/src/main/js/components/activity-graph/GraphsLegendStatic.tsx
index 9d723ad7071..54349d2a99d 100644
--- a/server/sonar-web/src/main/js/components/activity-graph/GraphsLegendStatic.tsx
+++ b/server/sonar-web/src/main/js/components/activity-graph/GraphsLegendStatic.tsx
@@ -20,12 +20,14 @@
import * as React from 'react';
import { Serie } from '../../types/project-activity';
import GraphsLegendItem from './GraphsLegendItem';
+import GraphsLegendNewCode from './GraphsLegendNewCode';
-interface Props {
+export interface GraphsLegendStaticProps {
series: Array<Pick<Serie, 'name' | 'translatedName'>>;
+ showLeakLegend: boolean;
}
-export default function GraphsLegendStatic({ series }: Props) {
+export default function GraphsLegendStatic({ series, showLeakLegend }: GraphsLegendStaticProps) {
return (
<div className="activity-graph-legends">
{series.map((serie, idx) => (
@@ -37,6 +39,8 @@ export default function GraphsLegendStatic({ series }: Props) {
name={serie.translatedName}
/>
))}
+
+ {showLeakLegend && <GraphsLegendNewCode />}
</div>
);
}
diff --git a/server/sonar-web/src/main/js/components/activity-graph/__tests__/GraphsLegendCustom-test.tsx b/server/sonar-web/src/main/js/components/activity-graph/__tests__/GraphsLegendCustom-test.tsx
index 5b213e8141f..9d437a7a0f1 100644
--- a/server/sonar-web/src/main/js/components/activity-graph/__tests__/GraphsLegendCustom-test.tsx
+++ b/server/sonar-web/src/main/js/components/activity-graph/__tests__/GraphsLegendCustom-test.tsx
@@ -20,29 +20,39 @@
import { shallow } from 'enzyme';
import * as React from 'react';
import { parseDate } from 'sonar-ui-common/helpers/dates';
-import GraphsLegendCustom from '../GraphsLegendCustom';
+import GraphsLegendCustom, { GraphsLegendCustomProps } from '../GraphsLegendCustom';
-const SERIES = [
- {
- name: 'bugs',
- translatedName: 'Bugs',
- data: [{ x: parseDate('2017-05-16T13:50:02+0200'), y: 1 }],
- type: 'INT'
- },
- {
- name: 'my_metric',
- translatedName: 'My Metric',
- data: [{ x: parseDate('2017-05-16T13:50:02+0200'), y: 1 }],
- type: 'INT'
- },
- {
- name: 'foo',
- translatedName: 'Foo',
- data: [],
- type: 'INT'
- }
-];
-
-it('should render correctly the list of series', () => {
- expect(shallow(<GraphsLegendCustom removeMetric={() => {}} series={SERIES} />)).toMatchSnapshot();
+it('should render correctly', () => {
+ expect(shallowRender()).toMatchSnapshot('default');
+ expect(shallowRender({ showLeakLegend: true })).toMatchSnapshot('with leak legend');
});
+
+function shallowRender(props: Partial<GraphsLegendCustomProps> = {}) {
+ return shallow<GraphsLegendCustomProps>(
+ <GraphsLegendCustom
+ removeMetric={jest.fn()}
+ series={[
+ {
+ name: 'bugs',
+ translatedName: 'Bugs',
+ data: [{ x: parseDate('2017-05-16T13:50:02+0200'), y: 1 }],
+ type: 'INT'
+ },
+ {
+ name: 'my_metric',
+ translatedName: 'My Metric',
+ data: [{ x: parseDate('2017-05-16T13:50:02+0200'), y: 1 }],
+ type: 'INT'
+ },
+ {
+ name: 'foo',
+ translatedName: 'Foo',
+ data: [],
+ type: 'INT'
+ }
+ ]}
+ showLeakLegend={false}
+ {...props}
+ />
+ );
+}
diff --git a/server/sonar-web/src/main/js/components/activity-graph/__tests__/GraphsLegendNewCode-test.tsx b/server/sonar-web/src/main/js/components/activity-graph/__tests__/GraphsLegendNewCode-test.tsx
new file mode 100644
index 00000000000..7f74bf22117
--- /dev/null
+++ b/server/sonar-web/src/main/js/components/activity-graph/__tests__/GraphsLegendNewCode-test.tsx
@@ -0,0 +1,31 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2020 SonarSource SA
+ * mailto:info 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 { shallow } from 'enzyme';
+import * as React from 'react';
+import GraphsLegendNewCode from '../GraphsLegendNewCode';
+
+it('should render correctly', () => {
+ expect(shallowRender()).toMatchSnapshot('default');
+});
+
+function shallowRender() {
+ return shallow(<GraphsLegendNewCode />);
+}
diff --git a/server/sonar-web/src/main/js/components/activity-graph/__tests__/GraphsLegendStatic-test.tsx b/server/sonar-web/src/main/js/components/activity-graph/__tests__/GraphsLegendStatic-test.tsx
index a0492576ddf..4fa8d55ed7a 100644
--- a/server/sonar-web/src/main/js/components/activity-graph/__tests__/GraphsLegendStatic-test.tsx
+++ b/server/sonar-web/src/main/js/components/activity-graph/__tests__/GraphsLegendStatic-test.tsx
@@ -19,13 +19,22 @@
*/
import { shallow } from 'enzyme';
import * as React from 'react';
-import GraphsLegendStatic from '../GraphsLegendStatic';
+import GraphsLegendStatic, { GraphsLegendStaticProps } from '../GraphsLegendStatic';
-const SERIES = [
- { name: 'bugs', translatedName: 'Bugs', data: [] },
- { name: 'code_smells', translatedName: 'Code Smells', data: [] }
-];
-
-it('should render correctly the list of series', () => {
- expect(shallow(<GraphsLegendStatic series={SERIES} />)).toMatchSnapshot();
+it('should render correctly', () => {
+ expect(shallowRender()).toMatchSnapshot('default');
+ expect(shallowRender({ showLeakLegend: true })).toMatchSnapshot('with leak legend');
});
+
+function shallowRender(props: Partial<GraphsLegendStaticProps> = {}) {
+ return shallow<GraphsLegendStaticProps>(
+ <GraphsLegendStatic
+ series={[
+ { name: 'bugs', translatedName: 'Bugs' },
+ { name: 'code_smells', translatedName: 'Code Smells' }
+ ]}
+ showLeakLegend={false}
+ {...props}
+ />
+ );
+}
diff --git a/server/sonar-web/src/main/js/components/activity-graph/__tests__/__snapshots__/GraphHistory-test.tsx.snap b/server/sonar-web/src/main/js/components/activity-graph/__tests__/__snapshots__/GraphHistory-test.tsx.snap
index cb92ba1524d..d3f064bbe89 100644
--- a/server/sonar-web/src/main/js/components/activity-graph/__tests__/__snapshots__/GraphHistory-test.tsx.snap
+++ b/server/sonar-web/src/main/js/components/activity-graph/__tests__/__snapshots__/GraphHistory-test.tsx.snap
@@ -28,6 +28,7 @@ exports[`should correctly render a graph 1`] = `
},
]
}
+ showLeakLegend={true}
/>
<div
className="flex-1"
diff --git a/server/sonar-web/src/main/js/components/activity-graph/__tests__/__snapshots__/GraphsLegendCustom-test.tsx.snap b/server/sonar-web/src/main/js/components/activity-graph/__tests__/__snapshots__/GraphsLegendCustom-test.tsx.snap
index 9dede77b48a..35be613cd2d 100644
--- a/server/sonar-web/src/main/js/components/activity-graph/__tests__/__snapshots__/GraphsLegendCustom-test.tsx.snap
+++ b/server/sonar-web/src/main/js/components/activity-graph/__tests__/__snapshots__/GraphsLegendCustom-test.tsx.snap
@@ -1,48 +1,104 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
-exports[`should render correctly the list of series 1`] = `
+exports[`should render correctly: default 1`] = `
<div
- className="activity-graph-legends"
+ className="activity-graph-legends display-flex-center"
>
- <span
- className="spacer-left spacer-right"
- key="bugs"
+ <div
+ className="flex-1"
>
- <GraphsLegendItem
- index={0}
- metric="bugs"
- name="Bugs"
- removeMetric={[Function]}
- showWarning={false}
- />
- </span>
- <span
- className="spacer-left spacer-right"
- key="my_metric"
- >
- <GraphsLegendItem
- index={1}
- metric="my_metric"
- name="My Metric"
- removeMetric={[Function]}
- showWarning={false}
- />
- </span>
- <Tooltip
- key="foo"
- overlay="project_activity.graphs.custom.metric_no_history"
+ <span
+ className="spacer-left spacer-right"
+ key="bugs"
+ >
+ <GraphsLegendItem
+ index={0}
+ metric="bugs"
+ name="Bugs"
+ removeMetric={[MockFunction]}
+ showWarning={false}
+ />
+ </span>
+ <span
+ className="spacer-left spacer-right"
+ key="my_metric"
+ >
+ <GraphsLegendItem
+ index={1}
+ metric="my_metric"
+ name="My Metric"
+ removeMetric={[MockFunction]}
+ showWarning={false}
+ />
+ </span>
+ <Tooltip
+ key="foo"
+ overlay="project_activity.graphs.custom.metric_no_history"
+ >
+ <span
+ className="spacer-left spacer-right"
+ >
+ <GraphsLegendItem
+ index={2}
+ metric="foo"
+ name="Foo"
+ removeMetric={[MockFunction]}
+ showWarning={true}
+ />
+ </span>
+ </Tooltip>
+ </div>
+</div>
+`;
+
+exports[`should render correctly: with leak legend 1`] = `
+<div
+ className="activity-graph-legends display-flex-center"
+>
+ <div
+ className="flex-1"
>
<span
className="spacer-left spacer-right"
+ key="bugs"
>
<GraphsLegendItem
- index={2}
- metric="foo"
- name="Foo"
- removeMetric={[Function]}
- showWarning={true}
+ index={0}
+ metric="bugs"
+ name="Bugs"
+ removeMetric={[MockFunction]}
+ showWarning={false}
/>
</span>
- </Tooltip>
+ <span
+ className="spacer-left spacer-right"
+ key="my_metric"
+ >
+ <GraphsLegendItem
+ index={1}
+ metric="my_metric"
+ name="My Metric"
+ removeMetric={[MockFunction]}
+ showWarning={false}
+ />
+ </span>
+ <Tooltip
+ key="foo"
+ overlay="project_activity.graphs.custom.metric_no_history"
+ >
+ <span
+ className="spacer-left spacer-right"
+ >
+ <GraphsLegendItem
+ index={2}
+ metric="foo"
+ name="Foo"
+ removeMetric={[MockFunction]}
+ showWarning={true}
+ />
+ </span>
+ </Tooltip>
+ </div>
+ <GraphsLegendNewCode />
</div>
`;
diff --git a/server/sonar-web/src/main/js/components/activity-graph/__tests__/__snapshots__/GraphsLegendNewCode-test.tsx.snap b/server/sonar-web/src/main/js/components/activity-graph/__tests__/__snapshots__/GraphsLegendNewCode-test.tsx.snap
new file mode 100644
index 00000000000..e6c7707ef39
--- /dev/null
+++ b/server/sonar-web/src/main/js/components/activity-graph/__tests__/__snapshots__/GraphsLegendNewCode-test.tsx.snap
@@ -0,0 +1,14 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should render correctly: default 1`] = `
+<Tooltip
+ overlay="project_activity.graphs.new_code_long"
+>
+ <span
+ aria-label="project_activity.graphs.new_code_long"
+ className="activity-graph-new-code-legend display-flex-center pull-right note"
+ >
+ project_activity.graphs.new_code
+ </span>
+</Tooltip>
+`;
diff --git a/server/sonar-web/src/main/js/components/activity-graph/__tests__/__snapshots__/GraphsLegendStatic-test.tsx.snap b/server/sonar-web/src/main/js/components/activity-graph/__tests__/__snapshots__/GraphsLegendStatic-test.tsx.snap
index d1198d5f498..cb0be89ef40 100644
--- a/server/sonar-web/src/main/js/components/activity-graph/__tests__/__snapshots__/GraphsLegendStatic-test.tsx.snap
+++ b/server/sonar-web/src/main/js/components/activity-graph/__tests__/__snapshots__/GraphsLegendStatic-test.tsx.snap
@@ -1,6 +1,6 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
-exports[`should render correctly the list of series 1`] = `
+exports[`should render correctly: default 1`] = `
<div
className="activity-graph-legends"
>
@@ -20,3 +20,25 @@ exports[`should render correctly the list of series 1`] = `
/>
</div>
`;
+
+exports[`should render correctly: with leak legend 1`] = `
+<div
+ className="activity-graph-legends"
+>
+ <GraphsLegendItem
+ className="big-spacer-left big-spacer-right"
+ index={0}
+ key="bugs"
+ metric="bugs"
+ name="Bugs"
+ />
+ <GraphsLegendItem
+ className="big-spacer-left big-spacer-right"
+ index={1}
+ key="code_smells"
+ metric="code_smells"
+ name="Code Smells"
+ />
+ <GraphsLegendNewCode />
+</div>
+`;
diff --git a/server/sonar-web/src/main/js/components/activity-graph/styles.css b/server/sonar-web/src/main/js/components/activity-graph/styles.css
index 277d3084262..61d2759ce79 100644
--- a/server/sonar-web/src/main/js/components/activity-graph/styles.css
+++ b/server/sonar-web/src/main/js/components/activity-graph/styles.css
@@ -67,3 +67,17 @@
border-style: solid;
border-radius: calc(1.5 * var(--gridSize));
}
+
+.activity-graph-new-code-legend {
+ margin-right: 10px; /* padding of activity graph */
+}
+
+.activity-graph-new-code-legend::after {
+ content: '';
+ display: inline-block;
+ margin-left: calc(var(--gridSize) / 2);
+ width: var(--gridSize);
+ height: var(--gridSize);
+ background-color: var(--leakPrimaryColor);
+ border: 2px solid var(--leakSecondaryColor);
+}
diff --git a/sonar-core/src/main/resources/org/sonar/l10n/core.properties b/sonar-core/src/main/resources/org/sonar/l10n/core.properties
index bb781d111ba..789b8cf6718 100644
--- a/sonar-core/src/main/resources/org/sonar/l10n/core.properties
+++ b/sonar-core/src/main/resources/org/sonar/l10n/core.properties
@@ -1301,6 +1301,8 @@ project_activity.events.tooltip.delete=Delete this event
project_activity.new_code_period_start=New Code Period starts here
project_activity.new_code_period_start.help=The analysis before this mark is the baseline for New Code comparison
+project_activity.graphs.new_code=New Code
+project_activity.graphs.new_code_long=New Code is indicated in yellow on the graph.
project_activity.graphs.issues=Issues
project_activity.graphs.coverage=Coverage
project_activity.graphs.duplications=Duplications