aboutsummaryrefslogtreecommitdiffstats
path: root/server/sonar-web/src
diff options
context:
space:
mode:
authorGrégoire Aubert <gregoire.aubert@sonarsource.com>2018-01-17 11:29:05 +0100
committerGrégoire Aubert <gregoire.aubert@sonarsource.com>2018-01-25 15:16:50 +0100
commitdf96a05cc325b2946c25ee8277f64638ed72288c (patch)
treeca28960f1a7fc514e0b1d6e5b90d1f46a6c45ffd /server/sonar-web/src
parent49391d2eff65209068acc31e41393b9617fb2458 (diff)
downloadsonarqube-df96a05cc325b2946c25ee8277f64638ed72288c.tar.gz
sonarqube-df96a05cc325b2946c25ee8277f64638ed72288c.zip
Migrate parts of overview app to TS
Diffstat (limited to 'server/sonar-web/src')
-rw-r--r--server/sonar-web/src/main/js/api/components.ts2
-rw-r--r--server/sonar-web/src/main/js/api/projectActivity.ts21
-rw-r--r--server/sonar-web/src/main/js/api/projectLinks.ts12
-rw-r--r--server/sonar-web/src/main/js/api/quality-gates.ts27
-rw-r--r--server/sonar-web/src/main/js/api/time-machine.ts3
-rw-r--r--server/sonar-web/src/main/js/app/components/ComponentContainer.tsx4
-rw-r--r--server/sonar-web/src/main/js/app/types.ts16
-rw-r--r--server/sonar-web/src/main/js/apps/code/components/ComponentMeasure.tsx4
-rw-r--r--server/sonar-web/src/main/js/apps/component-measures/components/MeasureHeader.js11
-rw-r--r--server/sonar-web/src/main/js/apps/component-measures/components/__tests__/__snapshots__/MeasureHeader-test.js.snap53
-rw-r--r--server/sonar-web/src/main/js/apps/component-measures/drilldown/ComponentsListRow.js7
-rw-r--r--server/sonar-web/src/main/js/apps/component-measures/drilldown/MeasureCell.js7
-rw-r--r--server/sonar-web/src/main/js/apps/component-measures/sidebar/FacetMeasureValue.js12
-rw-r--r--server/sonar-web/src/main/js/apps/component-measures/sidebar/__tests__/__snapshots__/FacetMeasureValue-test.js.snap41
-rw-r--r--server/sonar-web/src/main/js/apps/overview/badges/BadgesModal.tsx2
-rw-r--r--server/sonar-web/src/main/js/apps/overview/components/App.tsx86
-rw-r--r--server/sonar-web/src/main/js/apps/overview/components/OverviewApp.tsx (renamed from server/sonar-web/src/main/js/apps/overview/components/OverviewApp.js)95
-rw-r--r--server/sonar-web/src/main/js/apps/overview/components/Timeline.tsx (renamed from server/sonar-web/src/main/js/apps/overview/components/Timeline.js)16
-rw-r--r--server/sonar-web/src/main/js/apps/overview/components/__tests__/App-test.tsx68
-rw-r--r--server/sonar-web/src/main/js/apps/overview/events/AnalysesList.tsx (renamed from server/sonar-web/src/main/js/apps/overview/events/AnalysesList.js)62
-rw-r--r--server/sonar-web/src/main/js/apps/overview/events/Analysis.tsx (renamed from server/sonar-web/src/main/js/apps/overview/events/Analysis.js)22
-rw-r--r--server/sonar-web/src/main/js/apps/overview/events/Event.tsx (renamed from server/sonar-web/src/main/js/apps/overview/events/Event.js)15
-rw-r--r--server/sonar-web/src/main/js/apps/overview/events/__tests__/Analysis-test.tsx (renamed from server/sonar-web/src/main/js/apps/overview/events/__tests__/Analysis-test.js)4
-rw-r--r--server/sonar-web/src/main/js/apps/overview/events/__tests__/Event-test.tsx (renamed from server/sonar-web/src/main/js/apps/overview/events/__tests__/Event-test.js)2
-rw-r--r--server/sonar-web/src/main/js/apps/overview/events/__tests__/__snapshots__/Analysis-test.tsx.snap (renamed from server/sonar-web/src/main/js/apps/overview/events/__tests__/__snapshots__/Analysis-test.js.snap)0
-rw-r--r--server/sonar-web/src/main/js/apps/overview/events/__tests__/__snapshots__/Event-test.tsx.snap (renamed from server/sonar-web/src/main/js/apps/overview/events/__tests__/__snapshots__/Event-test.js.snap)0
-rw-r--r--server/sonar-web/src/main/js/apps/overview/main/Coverage.js2
-rw-r--r--server/sonar-web/src/main/js/apps/overview/main/Duplications.js2
-rw-r--r--server/sonar-web/src/main/js/apps/overview/main/enhance.tsx (renamed from server/sonar-web/src/main/js/apps/overview/main/enhance.js)89
-rw-r--r--server/sonar-web/src/main/js/apps/overview/meta/Meta.tsx (renamed from server/sonar-web/src/main/js/apps/overview/meta/Meta.js)46
-rw-r--r--server/sonar-web/src/main/js/apps/overview/meta/MetaLink.tsx (renamed from server/sonar-web/src/main/js/apps/overview/meta/MetaLink.js)48
-rw-r--r--server/sonar-web/src/main/js/apps/overview/meta/MetaLinks.tsx (renamed from server/sonar-web/src/main/js/apps/overview/meta/MetaLinks.js)41
-rw-r--r--server/sonar-web/src/main/js/apps/overview/meta/MetaSize.tsx (renamed from server/sonar-web/src/main/js/apps/overview/meta/MetaSize.js)26
-rw-r--r--server/sonar-web/src/main/js/apps/overview/meta/MetaTags.tsx (renamed from server/sonar-web/src/main/js/apps/overview/meta/MetaTags.js)80
-rw-r--r--server/sonar-web/src/main/js/apps/overview/meta/MetaTagsSelector.tsx (renamed from server/sonar-web/src/main/js/apps/overview/meta/MetaTagsSelector.js)41
-rw-r--r--server/sonar-web/src/main/js/apps/overview/meta/__tests__/MetaLink-test.tsx (renamed from server/sonar-web/src/main/js/apps/overview/meta/__tests__/MetaLink-test.js)2
-rw-r--r--server/sonar-web/src/main/js/apps/overview/meta/__tests__/MetaTags-test.tsx (renamed from server/sonar-web/src/main/js/apps/overview/meta/__tests__/MetaTags-test.js)31
-rw-r--r--server/sonar-web/src/main/js/apps/overview/meta/__tests__/MetaTagsSelector-test.tsx (renamed from server/sonar-web/src/main/js/apps/overview/meta/__tests__/MetaTagsSelector-test.js)20
-rw-r--r--server/sonar-web/src/main/js/apps/overview/meta/__tests__/__snapshots__/MetaLink-test.tsx.snap (renamed from server/sonar-web/src/main/js/apps/overview/meta/__tests__/__snapshots__/MetaLink-test.js.snap)0
-rw-r--r--server/sonar-web/src/main/js/apps/overview/meta/__tests__/__snapshots__/MetaTags-test.tsx.snap (renamed from server/sonar-web/src/main/js/apps/overview/meta/__tests__/__snapshots__/MetaTags-test.js.snap)0
-rw-r--r--server/sonar-web/src/main/js/apps/overview/qualityGate/ApplicationQualityGate.tsx (renamed from server/sonar-web/src/main/js/apps/overview/qualityGate/ApplicationQualityGate.js)71
-rw-r--r--server/sonar-web/src/main/js/apps/overview/qualityGate/ApplicationQualityGateProject.tsx (renamed from server/sonar-web/src/main/js/apps/overview/qualityGate/ApplicationQualityGateProject.js)46
-rw-r--r--server/sonar-web/src/main/js/apps/overview/qualityGate/QualityGateCondition.js9
-rw-r--r--server/sonar-web/src/main/js/apps/overview/qualityGate/__tests__/ApplicationQualityGate-test.tsx (renamed from server/sonar-web/src/main/js/apps/overview/qualityGate/__tests__/ApplicationQualityGate-test.js)7
-rw-r--r--server/sonar-web/src/main/js/apps/overview/qualityGate/__tests__/ApplicationQualityGateProject-test.tsx (renamed from server/sonar-web/src/main/js/apps/overview/qualityGate/__tests__/ApplicationQualityGateProject-test.js)3
-rw-r--r--server/sonar-web/src/main/js/apps/overview/qualityGate/__tests__/__snapshots__/ApplicationQualityGate-test.tsx.snap (renamed from server/sonar-web/src/main/js/apps/overview/qualityGate/__tests__/__snapshots__/ApplicationQualityGate-test.js.snap)0
-rw-r--r--server/sonar-web/src/main/js/apps/overview/qualityGate/__tests__/__snapshots__/ApplicationQualityGateProject-test.tsx.snap (renamed from server/sonar-web/src/main/js/apps/overview/qualityGate/__tests__/__snapshots__/ApplicationQualityGateProject-test.js.snap)0
-rw-r--r--server/sonar-web/src/main/js/apps/overview/qualityGate/__tests__/__snapshots__/QualityGateCondition-test.js.snap150
-rw-r--r--server/sonar-web/src/main/js/apps/portfolio/components/Effort.tsx10
-rw-r--r--server/sonar-web/src/main/js/apps/portfolio/components/ReleasabilityBox.tsx7
-rw-r--r--server/sonar-web/src/main/js/apps/portfolio/components/Summary.tsx6
-rw-r--r--server/sonar-web/src/main/js/apps/portfolio/components/WorstProjects.tsx9
-rw-r--r--server/sonar-web/src/main/js/apps/portfolio/components/__tests__/__snapshots__/Effort-test.tsx.snap14
-rw-r--r--server/sonar-web/src/main/js/apps/portfolio/components/__tests__/__snapshots__/ReleasabilityBox-test.tsx.snap14
-rw-r--r--server/sonar-web/src/main/js/apps/portfolio/components/__tests__/__snapshots__/Summary-test.tsx.snap24
-rw-r--r--server/sonar-web/src/main/js/apps/portfolio/components/__tests__/__snapshots__/WorstProjects-test.tsx.snap180
-rw-r--r--server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityAppContainer.js2
-rw-r--r--server/sonar-web/src/main/js/apps/projects/components/ProjectCardLeakMeasures.tsx42
-rw-r--r--server/sonar-web/src/main/js/apps/projects/components/ProjectCardOverallMeasures.tsx42
-rw-r--r--server/sonar-web/src/main/js/apps/projects/components/__tests__/__snapshots__/ProjectCardLeakMeasures-test.tsx.snap141
-rw-r--r--server/sonar-web/src/main/js/apps/projects/components/__tests__/__snapshots__/ProjectCardOverallMeasures-test.tsx.snap106
-rw-r--r--server/sonar-web/src/main/js/apps/projects/filters/TagsFilter.tsx13
-rw-r--r--server/sonar-web/src/main/js/components/common/BubblePopup.tsx7
-rw-r--r--server/sonar-web/src/main/js/components/common/MultiSelect.tsx (renamed from server/sonar-web/src/main/js/components/common/MultiSelect.js)128
-rw-r--r--server/sonar-web/src/main/js/components/common/MultiSelectOption.tsx (renamed from server/sonar-web/src/main/js/components/common/MultiSelectOption.js)41
-rw-r--r--server/sonar-web/src/main/js/components/common/__tests__/MultiSelect-test.tsx (renamed from server/sonar-web/src/main/js/components/common/__tests__/MultiSelect-test.js)2
-rw-r--r--server/sonar-web/src/main/js/components/common/__tests__/MultiSelectOption-test.tsx (renamed from server/sonar-web/src/main/js/components/common/__tests__/MultiSelectOption-test.js)5
-rw-r--r--server/sonar-web/src/main/js/components/common/__tests__/__snapshots__/MultiSelect-test.tsx.snap (renamed from server/sonar-web/src/main/js/components/common/__tests__/__snapshots__/MultiSelect-test.js.snap)17
-rw-r--r--server/sonar-web/src/main/js/components/common/__tests__/__snapshots__/MultiSelectOption-test.tsx.snap (renamed from server/sonar-web/src/main/js/components/common/__tests__/__snapshots__/MultiSelectOption-test.js.snap)0
-rw-r--r--server/sonar-web/src/main/js/components/issue/popups/SetIssueTagsPopup.js1
-rw-r--r--server/sonar-web/src/main/js/components/measure/Measure.tsx27
-rw-r--r--server/sonar-web/src/main/js/components/measure/__tests__/Measure-test.tsx49
-rw-r--r--server/sonar-web/src/main/js/components/measure/utils.ts15
-rw-r--r--server/sonar-web/src/main/js/components/preview-graph/PreviewGraph.d.ts32
-rw-r--r--server/sonar-web/src/main/js/components/shared/DrilldownLink.tsx (renamed from server/sonar-web/src/main/js/components/shared/drilldown-link.js)24
-rw-r--r--server/sonar-web/src/main/js/components/tags/TagsSelector.tsx (renamed from server/sonar-web/src/main/js/components/tags/TagsSelector.js)29
-rw-r--r--server/sonar-web/src/main/js/components/tags/__tests__/TagsSelector-test.tsx (renamed from server/sonar-web/src/main/js/components/tags/__tests__/TagsSelector-test.js)5
-rw-r--r--server/sonar-web/src/main/js/components/tags/__tests__/__snapshots__/TagsSelector-test.tsx.snap (renamed from server/sonar-web/src/main/js/components/tags/__tests__/__snapshots__/TagsSelector-test.js.snap)4
-rw-r--r--server/sonar-web/src/main/js/helpers/__tests__/measures-test.ts91
-rw-r--r--server/sonar-web/src/main/js/helpers/measures.ts88
-rw-r--r--server/sonar-web/src/main/js/helpers/periods.ts4
81 files changed, 1007 insertions, 1478 deletions
diff --git a/server/sonar-web/src/main/js/api/components.ts b/server/sonar-web/src/main/js/api/components.ts
index 5ed1cf5a258..db1e32cc643 100644
--- a/server/sonar-web/src/main/js/api/components.ts
+++ b/server/sonar-web/src/main/js/api/components.ts
@@ -79,7 +79,7 @@ export function createProject(data: {
}
export function searchProjectTags(data?: { ps?: number; q?: string }): Promise<any> {
- return getJSON('/api/project_tags/search', data);
+ return getJSON('/api/project_tags/search', data).catch(throwGlobalError);
}
export function setProjectTags(data: { project: string; tags: string }): Promise<void> {
diff --git a/server/sonar-web/src/main/js/api/projectActivity.ts b/server/sonar-web/src/main/js/api/projectActivity.ts
index d78ff17681e..b931ea5a6f6 100644
--- a/server/sonar-web/src/main/js/api/projectActivity.ts
+++ b/server/sonar-web/src/main/js/api/projectActivity.ts
@@ -19,14 +19,19 @@
*/
import { getJSON, postJSON, post, RequestData } from '../helpers/request';
import throwGlobalError from '../app/utils/throwGlobalError';
+import { Paging } from '../app/types';
-interface GetProjectActivityResponse {
- analyses: any[];
- paging: {
- total: number;
- pageIndex: number;
- pageSize: number;
- };
+export interface Event {
+ key: string;
+ name: string;
+ category: string;
+ description?: string;
+}
+
+export interface Analysis {
+ key: string;
+ date: string;
+ events: Event[];
}
export function getProjectActivity(data: {
@@ -35,7 +40,7 @@ export function getProjectActivity(data: {
category?: string;
p?: number;
ps?: number;
-}): Promise<GetProjectActivityResponse> {
+}): Promise<{ analyses: Analysis[]; paging: Paging }> {
return getJSON('/api/project_analyses/search', data).catch(throwGlobalError);
}
diff --git a/server/sonar-web/src/main/js/api/projectLinks.ts b/server/sonar-web/src/main/js/api/projectLinks.ts
index 16a492bca9f..e91b200c4fe 100644
--- a/server/sonar-web/src/main/js/api/projectLinks.ts
+++ b/server/sonar-web/src/main/js/api/projectLinks.ts
@@ -18,11 +18,19 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import { getJSON, post, postJSON } from '../helpers/request';
+import throwGlobalError from '../app/utils/throwGlobalError';
-export function getProjectLinks(projectKey: string): Promise<any> {
+export interface ProjectLink {
+ id: string;
+ name: string;
+ type: string;
+ url: string;
+}
+
+export function getProjectLinks(projectKey: string): Promise<ProjectLink[]> {
const url = '/api/project_links/search';
const data = { projectKey };
- return getJSON(url, data).then(r => r.links);
+ return getJSON(url, data).then(r => r.links, throwGlobalError);
}
export function deleteLink(linkId: string): Promise<void> {
diff --git a/server/sonar-web/src/main/js/api/quality-gates.ts b/server/sonar-web/src/main/js/api/quality-gates.ts
index 5a50564b36f..b40e6130b28 100644
--- a/server/sonar-web/src/main/js/api/quality-gates.ts
+++ b/server/sonar-web/src/main/js/api/quality-gates.ts
@@ -19,6 +19,7 @@
*/
import { getJSON, post, postJSON } from '../helpers/request';
import throwGlobalError from '../app/utils/throwGlobalError';
+import { Metric } from '../app/types';
export interface ConditionBase {
error: string;
@@ -148,9 +149,33 @@ export function dissociateGateWithProject(data: {
return post('/api/qualitygates/deselect', data).catch(throwGlobalError);
}
+export interface ConditionAnalysis {
+ comparator: string;
+ errorThreshold?: string;
+ metric: string;
+ periodIndex?: number;
+ onLeak?: boolean;
+ status: string;
+ value: string;
+ warningThreshold?: string;
+}
+
+export interface ApplicationProject {
+ key: string;
+ name: string;
+ status: string;
+ conditions: ConditionAnalysis[];
+}
+
+export interface ApplicationQualityGate {
+ metrics: Metric[];
+ projects: ApplicationProject[];
+ status: string;
+}
+
export function getApplicationQualityGate(data: {
application: string;
organization?: string;
-}): Promise<void | Response> {
+}): Promise<ApplicationQualityGate> {
return getJSON('/api/qualitygates/application_status', data).catch(throwGlobalError);
}
diff --git a/server/sonar-web/src/main/js/api/time-machine.ts b/server/sonar-web/src/main/js/api/time-machine.ts
index e6c01eba852..2f25912b191 100644
--- a/server/sonar-web/src/main/js/api/time-machine.ts
+++ b/server/sonar-web/src/main/js/api/time-machine.ts
@@ -19,6 +19,7 @@
*/
import { getJSON } from '../helpers/request';
import { Paging } from '../app/types';
+import throwGlobalError from '../app/utils/throwGlobalError';
export interface HistoryItem {
date: Date;
@@ -47,7 +48,7 @@ export function getTimeMachineData(
metrics: metrics.join(),
ps: 1000,
...other
- });
+ }).catch(throwGlobalError);
}
export function getAllTimeMachineData(
diff --git a/server/sonar-web/src/main/js/app/components/ComponentContainer.tsx b/server/sonar-web/src/main/js/app/components/ComponentContainer.tsx
index e109a142861..de3102a3957 100644
--- a/server/sonar-web/src/main/js/app/components/ComponentContainer.tsx
+++ b/server/sonar-web/src/main/js/app/components/ComponentContainer.tsx
@@ -43,7 +43,7 @@ interface Props {
interface State {
branches: Branch[];
loading: boolean;
- component: Component | null;
+ component?: Component;
currentTask?: Task;
isInProgress?: boolean;
isPending?: boolean;
@@ -54,7 +54,7 @@ export class ComponentContainer extends React.PureComponent<Props, State> {
constructor(props: Props) {
super(props);
- this.state = { branches: [], loading: true, component: null };
+ this.state = { branches: [], loading: true };
}
componentDidMount() {
diff --git a/server/sonar-web/src/main/js/app/types.ts b/server/sonar-web/src/main/js/app/types.ts
index 7a2a64d4e26..dedfabe68c2 100644
--- a/server/sonar-web/src/main/js/app/types.ts
+++ b/server/sonar-web/src/main/js/app/types.ts
@@ -68,19 +68,25 @@ export interface Breadcrumb {
qualifier: string;
}
-export interface Component {
+export interface LightComponent {
+ key: string;
+ organization: string;
+ qualifier: string;
+}
+
+export interface Component extends LightComponent {
analysisDate?: string;
breadcrumbs: Breadcrumb[];
configuration?: ComponentConfiguration;
description?: string;
extensions?: Extension[];
isFavorite?: boolean;
- key: string;
name: string;
- organization: string;
path?: string;
- qualifier: string;
refKey?: string;
+ qualityProfiles?: { key: string; language: string; name: string }[];
+ qualityGate?: { isDefault?: boolean; key: string; name: string };
+ tags?: string[];
version?: string;
visibility?: string;
}
@@ -105,7 +111,7 @@ export interface Metric {
domain?: string;
hidden?: boolean;
key: string;
- name?: string;
+ name: string;
qualitative?: boolean;
type: string;
}
diff --git a/server/sonar-web/src/main/js/apps/code/components/ComponentMeasure.tsx b/server/sonar-web/src/main/js/apps/code/components/ComponentMeasure.tsx
index d0bdd18e303..bc900211a0e 100644
--- a/server/sonar-web/src/main/js/apps/code/components/ComponentMeasure.tsx
+++ b/server/sonar-web/src/main/js/apps/code/components/ComponentMeasure.tsx
@@ -42,7 +42,5 @@ export default function ComponentMeasure({ component, metricKey, metricType }: P
return <span />;
}
- return (
- <Measure measure={{ ...measure, metric: { key: finalMetricKey, type: finalMetricType } }} />
- );
+ return <Measure value={measure.value} metricKey={finalMetricKey} metricType={finalMetricType} />;
}
diff --git a/server/sonar-web/src/main/js/apps/component-measures/components/MeasureHeader.js b/server/sonar-web/src/main/js/apps/component-measures/components/MeasureHeader.js
index f59b58ee56f..c7964eb56a1 100644
--- a/server/sonar-web/src/main/js/apps/component-measures/components/MeasureHeader.js
+++ b/server/sonar-web/src/main/js/apps/component-measures/components/MeasureHeader.js
@@ -44,7 +44,7 @@ import { isDiffMetric } from '../../../helpers/measures';
export default function MeasureHeader(props /*: Props*/) {
const { branch, component, leakPeriod, measure, secondaryMeasure } = props;
- const metric = measure.metric;
+ const { metric } = measure;
const isDiff = isDiffMetric(metric.key);
return (
<div className="measure-details-header big-spacer-bottom">
@@ -55,9 +55,14 @@ export default function MeasureHeader(props /*: Props*/) {
<span className="measure-details-value spacer-left">
<strong>
{isDiff ? (
- <Measure className="domain-measures-leak" measure={measure} metric={metric} />
+ <Measure
+ className="domain-measures-leak"
+ value={measure.leak}
+ metricKey={metric.key}
+ metricType={metric.type}
+ />
) : (
- <Measure measure={measure} metric={metric} />
+ <Measure value={measure.value} metricKey={metric.key} metricType={metric.type} />
)}
</strong>
</span>
diff --git a/server/sonar-web/src/main/js/apps/component-measures/components/__tests__/__snapshots__/MeasureHeader-test.js.snap b/server/sonar-web/src/main/js/apps/component-measures/components/__tests__/__snapshots__/MeasureHeader-test.js.snap
index e58ba900cd7..d6c9bceb55a 100644
--- a/server/sonar-web/src/main/js/apps/component-measures/components/__tests__/__snapshots__/MeasureHeader-test.js.snap
+++ b/server/sonar-web/src/main/js/apps/component-measures/components/__tests__/__snapshots__/MeasureHeader-test.js.snap
@@ -68,30 +68,9 @@ exports[`should render correctly 1`] = `
>
<strong>
<Measure
- measure={
- Object {
- "leak": "0.0",
- "metric": Object {
- "key": "reliability_rating",
- "name": "Reliability Rating",
- "type": "RATING",
- },
- "periods": Array [
- Object {
- "index": 1,
- "value": "0.0",
- },
- ],
- "value": "3.0",
- }
- }
- metric={
- Object {
- "key": "reliability_rating",
- "name": "Reliability Rating",
- "type": "RATING",
- }
- }
+ metricKey="reliability_rating"
+ metricType="RATING"
+ value="3.0"
/>
</strong>
</span>
@@ -165,29 +144,9 @@ exports[`should render correctly for leak 1`] = `
<strong>
<Measure
className="domain-measures-leak"
- measure={
- Object {
- "leak": "3.0",
- "metric": Object {
- "key": "new_reliability_rating",
- "name": "Reliability Rating on New Code",
- "type": "RATING",
- },
- "periods": Array [
- Object {
- "index": 1,
- "value": "3.0",
- },
- ],
- }
- }
- metric={
- Object {
- "key": "new_reliability_rating",
- "name": "Reliability Rating on New Code",
- "type": "RATING",
- }
- }
+ metricKey="new_reliability_rating"
+ metricType="RATING"
+ value="3.0"
/>
</strong>
</span>
diff --git a/server/sonar-web/src/main/js/apps/component-measures/drilldown/ComponentsListRow.js b/server/sonar-web/src/main/js/apps/component-measures/drilldown/ComponentsListRow.js
index 30b74e4aab4..e87b224967f 100644
--- a/server/sonar-web/src/main/js/apps/component-measures/drilldown/ComponentsListRow.js
+++ b/server/sonar-web/src/main/js/apps/component-measures/drilldown/ComponentsListRow.js
@@ -52,11 +52,8 @@ export default function ComponentsListRow(props /*: Props */) {
{otherMeasures.map(measure => (
<MeasureCell
key={measure.metric.key}
- component={{
- ...component,
- value: measure.value,
- leak: measure.leak
- }}
+ component={component}
+ measure={measure}
metric={measure.metric}
/>
))}
diff --git a/server/sonar-web/src/main/js/apps/component-measures/drilldown/MeasureCell.js b/server/sonar-web/src/main/js/apps/component-measures/drilldown/MeasureCell.js
index d5109091646..0934587ccf2 100644
--- a/server/sonar-web/src/main/js/apps/component-measures/drilldown/MeasureCell.js
+++ b/server/sonar-web/src/main/js/apps/component-measures/drilldown/MeasureCell.js
@@ -20,6 +20,7 @@
// @flow
import React from 'react';
import Measure from '../../../components/measure/Measure';
+import { isDiffMetric } from '../../../helpers/measures';
/*:: import type { Component } from '../types'; */
/*:: import type { Metric } from '../../../store/metrics/actions'; */
@@ -32,7 +33,11 @@ export default function MeasureCell({ component, metric } /*: Props */) {
return (
<td className="thin nowrap text-right">
<span id={`component-measures-component-measure-${component.key}-${metric.key}`}>
- <Measure measure={{ metric, value: component.value, leak: component.leak }} />
+ <Measure
+ value={isDiffMetric(metric.key) ? component.leak : component.value}
+ metricKey={metric.key}
+ metricType={metric.type}
+ />
</span>
</td>
);
diff --git a/server/sonar-web/src/main/js/apps/component-measures/sidebar/FacetMeasureValue.js b/server/sonar-web/src/main/js/apps/component-measures/sidebar/FacetMeasureValue.js
index d4060ac29c7..93d7ff58493 100644
--- a/server/sonar-web/src/main/js/apps/component-measures/sidebar/FacetMeasureValue.js
+++ b/server/sonar-web/src/main/js/apps/component-measures/sidebar/FacetMeasureValue.js
@@ -29,14 +29,22 @@ export default function FacetMeasureValue({ measure } /*: { measure: MeasureEnha
<div
id={`measure-${measure.metric.key}-leak`}
className="domain-measures-value domain-measures-leak">
- <Measure measure={measure} />
+ <Measure
+ value={measure.leak}
+ metricKey={measure.metric.key}
+ metricType={measure.metric.type}
+ />
</div>
);
}
return (
<div id={`measure-${measure.metric.key}-value`} className="domain-measures-value">
- <Measure measure={measure} />
+ <Measure
+ value={measure.value}
+ metricKey={measure.metric.key}
+ metricType={measure.metric.type}
+ />
</div>
);
}
diff --git a/server/sonar-web/src/main/js/apps/component-measures/sidebar/__tests__/__snapshots__/FacetMeasureValue-test.js.snap b/server/sonar-web/src/main/js/apps/component-measures/sidebar/__tests__/__snapshots__/FacetMeasureValue-test.js.snap
index 9bd6a3e7e00..228f8a3e6d9 100644
--- a/server/sonar-web/src/main/js/apps/component-measures/sidebar/__tests__/__snapshots__/FacetMeasureValue-test.js.snap
+++ b/server/sonar-web/src/main/js/apps/component-measures/sidebar/__tests__/__snapshots__/FacetMeasureValue-test.js.snap
@@ -6,23 +6,9 @@ exports[`should display leak measure value 1`] = `
id="measure-new_bugs-leak"
>
<Measure
- measure={
- Object {
- "leak": "5",
- "metric": Object {
- "domain": "Reliability",
- "key": "new_bugs",
- "name": "New Bugs",
- "type": "INT",
- },
- "periods": Array [
- Object {
- "index": 1,
- "value": "5",
- },
- ],
- }
- }
+ metricKey="new_bugs"
+ metricType="INT"
+ value="5"
/>
</div>
`;
@@ -33,24 +19,9 @@ exports[`should display measure value 1`] = `
id="measure-bugs-value"
>
<Measure
- measure={
- Object {
- "leak": "5",
- "metric": Object {
- "domain": "Reliability",
- "key": "bugs",
- "name": "Bugs",
- "type": "INT",
- },
- "periods": Array [
- Object {
- "index": 1,
- "value": "5",
- },
- ],
- "value": "5",
- }
- }
+ metricKey="bugs"
+ metricType="INT"
+ value="5"
/>
</div>
`;
diff --git a/server/sonar-web/src/main/js/apps/overview/badges/BadgesModal.tsx b/server/sonar-web/src/main/js/apps/overview/badges/BadgesModal.tsx
index d8d23b2182c..7e4e0daf249 100644
--- a/server/sonar-web/src/main/js/apps/overview/badges/BadgesModal.tsx
+++ b/server/sonar-web/src/main/js/apps/overview/badges/BadgesModal.tsx
@@ -27,7 +27,7 @@ import { translate } from '../../../helpers/l10n';
import './styles.css';
interface Props {
- branch: string;
+ branch?: string;
project: string;
}
diff --git a/server/sonar-web/src/main/js/apps/overview/components/App.tsx b/server/sonar-web/src/main/js/apps/overview/components/App.tsx
new file mode 100644
index 00000000000..03d898d4e9e
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/overview/components/App.tsx
@@ -0,0 +1,86 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 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 * as PropTypes from 'prop-types';
+import OverviewApp from './OverviewApp';
+import EmptyOverview from './EmptyOverview';
+import { getBranchName, isShortLivingBranch } from '../../../helpers/branches';
+import { getProjectBranchUrl, getCodeUrl } from '../../../helpers/urls';
+import { Branch, Component } from '../../../app/types';
+
+interface Props {
+ branch?: Branch;
+ component: Component;
+ isInProgress?: boolean;
+ isPending?: boolean;
+ onComponentChange: (changes: Partial<Component>) => void;
+}
+
+export default class App extends React.PureComponent<Props> {
+ static contextTypes = {
+ router: PropTypes.object
+ };
+
+ componentDidMount() {
+ const { branch, component } = this.props;
+
+ if (this.isPortfolio()) {
+ this.context.router.replace({
+ pathname: '/portfolio',
+ query: { id: component.key }
+ });
+ } else if (this.isFile()) {
+ this.context.router.replace(
+ getCodeUrl(component.breadcrumbs[0].key, getBranchName(branch), component.key)
+ );
+ } else if (isShortLivingBranch(branch)) {
+ this.context.router.replace(getProjectBranchUrl(component.key, branch));
+ }
+ }
+
+ isPortfolio = () => ['VW', 'SVW'].includes(this.props.component.qualifier);
+
+ isFile = () => ['FIL', 'UTS'].includes(this.props.component.qualifier);
+
+ render() {
+ const { branch, component } = this.props;
+
+ if (this.isPortfolio() || this.isFile() || isShortLivingBranch(branch)) {
+ return null;
+ }
+
+ if (!component.analysisDate) {
+ return (
+ <EmptyOverview
+ component={component.key}
+ showWarning={!this.props.isPending && !this.props.isInProgress}
+ />
+ );
+ }
+
+ return (
+ <OverviewApp
+ branch={branch}
+ component={component}
+ onComponentChange={this.props.onComponentChange}
+ />
+ );
+ }
+}
diff --git a/server/sonar-web/src/main/js/apps/overview/components/OverviewApp.js b/server/sonar-web/src/main/js/apps/overview/components/OverviewApp.tsx
index 0271e1ecdc1..07d22017edf 100644
--- a/server/sonar-web/src/main/js/apps/overview/components/OverviewApp.js
+++ b/server/sonar-web/src/main/js/apps/overview/components/OverviewApp.tsx
@@ -17,8 +17,7 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-// @flow
-import React from 'react';
+import * as React from 'react';
import { uniq } from 'lodash';
import QualityGate from '../qualityGate/QualityGate';
import ApplicationQualityGate from '../qualityGate/ApplicationQualityGate';
@@ -29,54 +28,46 @@ import Duplications from '../main/Duplications';
import Meta from '../meta/Meta';
import throwGlobalError from '../../../app/utils/throwGlobalError';
import { getMeasuresAndMeta } from '../../../api/measures';
-import { getAllTimeMachineData } from '../../../api/time-machine';
+import { getAllTimeMachineData, History } from '../../../api/time-machine';
import { parseDate } from '../../../helpers/dates';
-import { enhanceMeasuresWithMetrics } from '../../../helpers/measures';
-import { getLeakPeriod } from '../../../helpers/periods';
+import { enhanceMeasuresWithMetrics, MeasureEnhanced } from '../../../helpers/measures';
+import { getLeakPeriod, Period } from '../../../helpers/periods';
import { getCustomGraph, getGraph } from '../../../helpers/storage';
import { METRICS, HISTORY_METRICS_LIST } from '../utils';
import { DEFAULT_GRAPH, getDisplayedHistoryMetrics } from '../../projectActivity/utils';
import { getBranchName } from '../../../helpers/branches';
-/*:: import type { Component, History, MeasuresList, Period } from '../types'; */
+import { Branch, Component } from '../../../app/types';
import '../styles.css';
-/*::
-type Props = {
- branch?: { name: string },
- component: Component,
- onComponentChange: {} => void
-};
-*/
-
-/*::
-type State = {
- history?: History,
- historyStartDate?: Date,
- loading: boolean,
- measures: MeasuresList,
- periods?: Array<Period>
-};
-*/
-
-export default class OverviewApp extends React.PureComponent {
- /*:: mounted: boolean; */
- /*:: props: Props; */
- state /*: State */ = {
- loading: true,
- measures: []
- };
+interface Props {
+ branch?: Branch;
+ component: Component;
+ onComponentChange: (changes: {}) => void;
+}
+
+interface State {
+ history?: History;
+ historyStartDate?: Date;
+ loading: boolean;
+ measures: MeasureEnhanced[];
+ periods?: Period[];
+}
+
+export default class OverviewApp extends React.PureComponent<Props, State> {
+ mounted: boolean;
+ state: State = { loading: true, measures: [] };
componentDidMount() {
this.mounted = true;
- this.loadMeasures().then(this.loadHistory);
+ this.loadMeasures().then(this.loadHistory, () => {});
}
- componentDidUpdate(prevProps /*: Props */) {
+ componentDidUpdate(prevProps: Props) {
if (
this.props.component.key !== prevProps.component.key ||
this.props.branch !== prevProps.branch
) {
- this.loadMeasures().then(this.loadHistory);
+ this.loadMeasures().then(this.loadHistory, () => {});
}
}
@@ -90,10 +81,10 @@ export default class OverviewApp extends React.PureComponent {
return getMeasuresAndMeta(component.key, METRICS, {
additionalFields: 'metrics,periods',
- branch: branch && getBranchName(branch)
+ branch: getBranchName(branch)
}).then(
r => {
- if (this.mounted) {
+ if (this.mounted && r.metrics) {
this.setState({
loading: false,
measures: enhanceMeasuresWithMetrics(r.component.measures, r.metrics),
@@ -119,22 +110,22 @@ export default class OverviewApp extends React.PureComponent {
}
const metrics = uniq(HISTORY_METRICS_LIST.concat(graphMetrics));
- return getAllTimeMachineData(component.key, metrics, {
- branch: branch && getBranchName(branch)
- }).then(r => {
- if (this.mounted) {
- const history /*: History */ = {};
- r.measures.forEach(measure => {
- const measureHistory = measure.history.map(analysis => ({
- date: parseDate(analysis.date),
- value: analysis.value
- }));
- history[measure.metric] = measureHistory;
- });
- const historyStartDate = history[HISTORY_METRICS_LIST[0]][0].date;
- this.setState({ history, historyStartDate });
+ return getAllTimeMachineData(component.key, metrics, { branch: getBranchName(branch) }).then(
+ r => {
+ if (this.mounted) {
+ const history: History = {};
+ r.measures.forEach(measure => {
+ const measureHistory = measure.history.map(analysis => ({
+ date: parseDate(analysis.date),
+ value: analysis.value
+ }));
+ history[measure.metric] = measureHistory;
+ });
+ const historyStartDate = history[HISTORY_METRICS_LIST[0]][0].date;
+ this.setState({ history, historyStartDate });
+ }
}
- }, throwGlobalError);
+ );
};
getApplicationLeakPeriod = () =>
@@ -158,7 +149,7 @@ export default class OverviewApp extends React.PureComponent {
const leakPeriod =
component.qualifier === 'APP' ? this.getApplicationLeakPeriod() : getLeakPeriod(periods);
- const branchName = branch && getBranchName(branch);
+ const branchName = getBranchName(branch);
const domainProps = {
branch: branchName,
component,
diff --git a/server/sonar-web/src/main/js/apps/overview/components/Timeline.js b/server/sonar-web/src/main/js/apps/overview/components/Timeline.tsx
index 15dde5221d3..1b2bd3d04ec 100644
--- a/server/sonar-web/src/main/js/apps/overview/components/Timeline.js
+++ b/server/sonar-web/src/main/js/apps/overview/components/Timeline.tsx
@@ -17,20 +17,20 @@
* 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 PropTypes from 'prop-types';
+import * as React from 'react';
import { max } from 'd3-array';
import { LineChart } from '../../../components/charts/line-chart';
+import { HistoryItem } from '../../../api/time-machine';
const HEIGHT = 80;
-export default class Timeline extends React.PureComponent {
- static propTypes = {
- history: PropTypes.arrayOf(PropTypes.object).isRequired,
- before: PropTypes.object,
- after: PropTypes.object
- };
+interface Props {
+ history: HistoryItem[];
+ before?: Date;
+ after?: Date;
+}
+export default class Timeline extends React.PureComponent<Props> {
filterSnapshots() {
const { history, before, after } = this.props;
diff --git a/server/sonar-web/src/main/js/apps/overview/components/__tests__/App-test.tsx b/server/sonar-web/src/main/js/apps/overview/components/__tests__/App-test.tsx
new file mode 100644
index 00000000000..4edd63ffba8
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/overview/components/__tests__/App-test.tsx
@@ -0,0 +1,68 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 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 { mount, shallow } from 'enzyme';
+import App from '../App';
+import OverviewApp from '../OverviewApp';
+import EmptyOverview from '../EmptyOverview';
+import { BranchType, LongLivingBranch } from '../../../../app/types';
+
+const component = {
+ key: 'foo',
+ analysisDate: '2016-01-01',
+ breadcrumbs: [],
+ name: 'Foo',
+ organization: 'org',
+ qualifier: 'TRK',
+ version: '0.0.1'
+};
+
+it('should render OverviewApp', () => {
+ expect(getWrapper().type()).toBe(OverviewApp);
+});
+
+it('should render EmptyOverview', () => {
+ const output = getWrapper({ component: { key: 'foo' } });
+ expect(output.type()).toBe(EmptyOverview);
+});
+
+it('redirects on Code page for files', () => {
+ const branch: LongLivingBranch = { isMain: false, name: 'b', type: BranchType.LONG };
+ const newComponent = {
+ ...component,
+ breadcrumbs: [
+ { key: 'project', name: 'Project', qualifier: 'TRK' },
+ { key: 'foo', name: 'Foo', qualifier: 'DIR' }
+ ],
+ qualifier: 'FIL'
+ };
+ const replace = jest.fn();
+ mount(<App branch={branch} component={newComponent} onComponentChange={jest.fn()} />, {
+ context: { router: { replace } }
+ });
+ expect(replace).toBeCalledWith({
+ pathname: '/code',
+ query: { branch: 'b', id: 'project', selected: 'foo' }
+ });
+});
+
+function getWrapper(props = {}) {
+ return shallow(<App component={component} onComponentChange={jest.fn()} {...props} />);
+}
diff --git a/server/sonar-web/src/main/js/apps/overview/events/AnalysesList.js b/server/sonar-web/src/main/js/apps/overview/events/AnalysesList.tsx
index bff7894acb7..30a3d98e7b1 100644
--- a/server/sonar-web/src/main/js/apps/overview/events/AnalysesList.js
+++ b/server/sonar-web/src/main/js/apps/overview/events/AnalysesList.tsx
@@ -17,47 +17,41 @@
* 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 * as React from 'react';
import { Link } from 'react-router';
import Analysis from './Analysis';
import { getAllMetrics } from '../../../api/metrics';
-import { getProjectActivity } from '../../../api/projectActivity';
+import { getProjectActivity, Analysis as IAnalysis } from '../../../api/projectActivity';
import PreviewGraph from '../../../components/preview-graph/PreviewGraph';
import { translate } from '../../../helpers/l10n';
-/*:: import type { Analysis as AnalysisType } from '../../projectActivity/types'; */
-/*:: import type { History, Metric } from '../types'; */
-
-/*::
-type Props = {
- branch?: string,
- component: Object,
- history: ?History,
- qualifier: string
-};
-*/
-
-/*::
-type State = {
- analyses: Array<AnalysisType>,
- loading: boolean,
- metrics: Array<Metric>
-};
-*/
+import { Metric, Component } from '../../../app/types';
+import { History } from '../../../api/time-machine';
+
+interface Props {
+ branch?: string;
+ component: Component;
+ history?: History;
+ qualifier: string;
+}
+
+interface State {
+ analyses: IAnalysis[];
+ loading: boolean;
+ metrics: Metric[];
+}
const PAGE_SIZE = 3;
-export default class AnalysesList extends React.PureComponent {
- /*:: mounted: boolean; */
- /*:: props: Props; */
- state /*: State */ = { analyses: [], loading: true, metrics: [] };
+export default class AnalysesList extends React.PureComponent<Props, State> {
+ mounted: boolean;
+ state: State = { analyses: [], loading: true, metrics: [] };
componentDidMount() {
this.mounted = true;
this.fetchData();
}
- componentDidUpdate(prevProps /*: Props */) {
+ componentDidUpdate(prevProps: Props) {
if (prevProps.component !== this.props.component) {
this.fetchData();
}
@@ -79,7 +73,7 @@ export default class AnalysesList extends React.PureComponent {
return component.breadcrumbs[current].key;
};
- fetchData() {
+ fetchData = () => {
this.setState({ loading: true });
Promise.all([
getProjectActivity({
@@ -89,13 +83,9 @@ export default class AnalysesList extends React.PureComponent {
}),
getAllMetrics()
]).then(
- response => {
+ ([{ analyses }, metrics]) => {
if (this.mounted) {
- this.setState({
- analyses: response[0].analyses,
- metrics: response[1],
- loading: false
- });
+ this.setState({ analyses, metrics, loading: false });
}
},
() => {
@@ -104,9 +94,9 @@ export default class AnalysesList extends React.PureComponent {
}
}
);
- }
+ };
- renderList(analyses /*: Array<AnalysisType> */) {
+ renderList(analyses: IAnalysis[]) {
if (!analyses.length) {
return <p className="spacer-top note">{translate('no_results')}</p>;
}
diff --git a/server/sonar-web/src/main/js/apps/overview/events/Analysis.js b/server/sonar-web/src/main/js/apps/overview/events/Analysis.tsx
index 3addf419677..f80ce5646b8 100644
--- a/server/sonar-web/src/main/js/apps/overview/events/Analysis.js
+++ b/server/sonar-web/src/main/js/apps/overview/events/Analysis.tsx
@@ -17,27 +17,23 @@
* 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 * as React from 'react';
import { sortBy } from 'lodash';
import Event from './Event';
import DateTooltipFormatter from '../../../components/intl/DateTooltipFormatter';
+import { Analysis as IAnalysis, Event as IEvent } from '../../../api/projectActivity';
import { translate } from '../../../helpers/l10n';
-/*:: import type { Analysis as AnalysisType, Event as EventType } from '../../projectActivity/types'; */
-/*::
-type Props = {
- analysis: AnalysisType,
- qualifier: string
-};
-*/
+interface Props {
+ analysis: IAnalysis;
+ qualifier: string;
+}
-export default function Analysis(props /*: Props */) {
- const { analysis } = props;
- const sortedEvents /*: Array<EventType> */ = sortBy(
+export default function Analysis({ analysis, ...props }: Props) {
+ const sortedEvents: Array<IEvent> = sortBy(
analysis.events,
// versions first
- (event /*: EventType */) => (event.category === 'VERSION' ? 0 : 1),
+ (event: IEvent) => (event.category === 'VERSION' ? 0 : 1),
// then the rest sorted by category
'category'
);
diff --git a/server/sonar-web/src/main/js/apps/overview/events/Event.js b/server/sonar-web/src/main/js/apps/overview/events/Event.tsx
index ca2982c0d0b..f90d318845a 100644
--- a/server/sonar-web/src/main/js/apps/overview/events/Event.js
+++ b/server/sonar-web/src/main/js/apps/overview/events/Event.tsx
@@ -17,19 +17,20 @@
* 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 * as React from 'react';
import Tooltip from '../../../components/controls/Tooltip';
+import { Event as IEvent } from '../../../api/projectActivity';
import { translate } from '../../../helpers/l10n';
-/*:: import type { Event as EventType } from '../../projectActivity/types'; */
-export default function Event(props /*: { event: EventType } */) {
- const { event } = props;
+interface Props {
+ event: IEvent;
+}
+export default function Event({ event }: Props) {
if (event.category === 'VERSION') {
return (
- <Tooltip overlay={`${translate('version')} ${props.event.name}`} mouseEnterDelay={0.5}>
- <span className="overview-analysis-event badge">{props.event.name}</span>
+ <Tooltip overlay={`${translate('version')} ${event.name}`} mouseEnterDelay={0.5}>
+ <span className="overview-analysis-event badge">{event.name}</span>
</Tooltip>
);
}
diff --git a/server/sonar-web/src/main/js/apps/overview/events/__tests__/Analysis-test.js b/server/sonar-web/src/main/js/apps/overview/events/__tests__/Analysis-test.tsx
index 7c6fdb452ad..16c481b42db 100644
--- a/server/sonar-web/src/main/js/apps/overview/events/__tests__/Analysis-test.js
+++ b/server/sonar-web/src/main/js/apps/overview/events/__tests__/Analysis-test.tsx
@@ -17,7 +17,7 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-import React from 'react';
+import * as React from 'react';
import { shallow } from 'enzyme';
import Analysis from '../Analysis';
@@ -31,5 +31,5 @@ const ANALYSIS = {
};
it('should sort the events with version first', () => {
- expect(shallow(<Analysis analysis={ANALYSIS} />)).toMatchSnapshot();
+ expect(shallow(<Analysis analysis={ANALYSIS} qualifier="TRK" />)).toMatchSnapshot();
});
diff --git a/server/sonar-web/src/main/js/apps/overview/events/__tests__/Event-test.js b/server/sonar-web/src/main/js/apps/overview/events/__tests__/Event-test.tsx
index 496bf250aee..e15be764817 100644
--- a/server/sonar-web/src/main/js/apps/overview/events/__tests__/Event-test.js
+++ b/server/sonar-web/src/main/js/apps/overview/events/__tests__/Event-test.tsx
@@ -17,7 +17,7 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-import React from 'react';
+import * as React from 'react';
import { shallow } from 'enzyme';
import Event from '../Event';
diff --git a/server/sonar-web/src/main/js/apps/overview/events/__tests__/__snapshots__/Analysis-test.js.snap b/server/sonar-web/src/main/js/apps/overview/events/__tests__/__snapshots__/Analysis-test.tsx.snap
index a9296187266..a9296187266 100644
--- a/server/sonar-web/src/main/js/apps/overview/events/__tests__/__snapshots__/Analysis-test.js.snap
+++ b/server/sonar-web/src/main/js/apps/overview/events/__tests__/__snapshots__/Analysis-test.tsx.snap
diff --git a/server/sonar-web/src/main/js/apps/overview/events/__tests__/__snapshots__/Event-test.js.snap b/server/sonar-web/src/main/js/apps/overview/events/__tests__/__snapshots__/Event-test.tsx.snap
index f6b5bdfc0e6..f6b5bdfc0e6 100644
--- a/server/sonar-web/src/main/js/apps/overview/events/__tests__/__snapshots__/Event-test.js.snap
+++ b/server/sonar-web/src/main/js/apps/overview/events/__tests__/__snapshots__/Event-test.tsx.snap
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 d8f4a118c43..ecc08743527 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
@@ -19,7 +19,7 @@
*/
import React from 'react';
import enhance from './enhance';
-import { DrilldownLink } from '../../../components/shared/drilldown-link';
+import DrilldownLink from '../../../components/shared/DrilldownLink';
import { getMetricName } from '../helpers/metrics';
import { formatMeasure, getPeriodValue } from '../../../helpers/measures';
import { translate } from '../../../helpers/l10n';
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 3a04c3cc306..e668ff8efc2 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
@@ -19,7 +19,7 @@
*/
import React from 'react';
import enhance from './enhance';
-import { DrilldownLink } from '../../../components/shared/drilldown-link';
+import DrilldownLink from '../../../components/shared/DrilldownLink';
import { getMetricName } from '../helpers/metrics';
import { formatMeasure, getPeriodValue } from '../../../helpers/measures';
import { translate } from '../../../helpers/l10n';
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.tsx
index 8aac3e3985b..142cdf3eb90 100644
--- a/server/sonar-web/src/main/js/apps/overview/main/enhance.js
+++ b/server/sonar-web/src/main/js/apps/overview/main/enhance.tsx
@@ -17,9 +17,9 @@
* 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 * as React from 'react';
import { Link } from 'react-router';
-import { DrilldownLink } from '../../../components/shared/drilldown-link';
+import DrilldownLink from '../../../components/shared/DrilldownLink';
import BubblesIcon from '../../../components/icons-components/BubblesIcon';
import DateTimeFormatter from '../../../components/intl/DateTimeFormatter';
import HistoryIcon from '../../../components/icons-components/HistoryIcon';
@@ -28,11 +28,11 @@ import Timeline from '../components/Timeline';
import Tooltip from '../../../components/controls/Tooltip';
import {
formatMeasure,
- formatMeasureVariation,
isDiffMetric,
getPeriodValue,
getShortType,
- getRatingTooltip
+ getRatingTooltip,
+ MeasureEnhanced
} from '../../../helpers/measures';
import { translateWithParameters, getLocalizedMetricName } from '../../../helpers/l10n';
import { getPeriodDate } from '../../../helpers/periods';
@@ -41,24 +41,43 @@ import {
getComponentIssuesUrl,
getMeasureHistoryUrl
} from '../../../helpers/urls';
+import { Component } from '../../../app/types';
+import { History } from '../../../api/time-machine';
+
+export interface EnhanceProps {
+ branch?: string;
+ component: Component;
+ measures: MeasureEnhanced[];
+ leakPeriod?: { index: number; date?: string };
+ history?: History;
+ historyStartDate?: Date;
+}
+
+export interface ComposedProps extends EnhanceProps {
+ getValue: (measure: MeasureEnhanced) => string | undefined;
+ renderHeader: (domain: string, label: string) => React.ReactNode;
+ renderMeasure: (metricKey: string) => React.ReactNode;
+ renderRating: (metricKey: string) => React.ReactNode;
+ renderIssues: (metric: string, type: string) => React.ReactNode;
+ renderHistoryLink: (metricKey: string) => React.ReactNode;
+ renderTimeline: (metricKey: string, range: string, children?: React.ReactNode) => React.ReactNode;
+}
-export default function enhance(ComposedComponent) {
- return class extends React.PureComponent {
+export default function enhance(ComposedComponent: React.ComponentType<ComposedProps>) {
+ return class extends React.PureComponent<EnhanceProps> {
static displayName = `enhance(${ComposedComponent.displayName})}`;
- getValue = measure => {
+ getValue = (measure: MeasureEnhanced) => {
const { leakPeriod } = this.props;
-
if (!measure) {
- return 0;
+ return '0';
}
-
return isDiffMetric(measure.metric.key)
- ? getPeriodValue(measure, leakPeriod.index)
+ ? getPeriodValue(measure, leakPeriod ? leakPeriod.index : 0)
: measure.value;
};
- renderHeader = (domain, label) => {
+ renderHeader = (domain: string, label: string) => {
const { branch, component } = this.props;
return (
<div className="overview-card-header">
@@ -74,11 +93,10 @@ export default function enhance(ComposedComponent) {
);
};
- renderMeasure = metricKey => {
+ renderMeasure = (metricKey: string) => {
const { branch, measures, component } = this.props;
const measure = measures.find(measure => measure.metric.key === metricKey);
-
- if (measure == null) {
+ if (!measure) {
return null;
}
@@ -100,32 +118,15 @@ export default function enhance(ComposedComponent) {
);
};
- renderMeasureVariation = (metricKey, customLabel) => {
- const NO_VALUE = '—';
- const { measures, leakPeriod } = this.props;
- const measure = measures.find(measure => measure.metric.key === metricKey);
- const periodValue = getPeriodValue(measure, leakPeriod.index);
- const formatted =
- periodValue != null
- ? formatMeasureVariation(periodValue, getShortType(measure.metric.type))
- : NO_VALUE;
- return (
- <div className="overview-domain-measure">
- <div className="overview-domain-measure-value">{formatted}</div>
-
- <div className="overview-domain-measure-label">{customLabel || measure.metric.name}</div>
- </div>
- );
- };
-
- renderRating = metricKey => {
+ renderRating = (metricKey: string) => {
const { branch, component, measures } = this.props;
const measure = measures.find(measure => measure.metric.key === metricKey);
if (!measure) {
return null;
}
+
const value = this.getValue(measure);
- const title = getRatingTooltip(metricKey, value);
+ const title = value && getRatingTooltip(metricKey, value);
return (
<Tooltip overlay={title} placement="top">
<div className="overview-domain-measure-sup">
@@ -141,16 +142,20 @@ export default function enhance(ComposedComponent) {
);
};
- renderIssues = (metric, type) => {
+ renderIssues = (metric: string, type: string) => {
const { branch, measures, component } = this.props;
const measure = measures.find(measure => measure.metric.key === metric);
+ if (!measure) {
+ return null;
+ }
+
const value = this.getValue(measure);
const params = { branch, resolved: 'false', types: type };
if (isDiffMetric(metric)) {
Object.assign(params, { sinceLeakPeriod: 'true' });
}
- const tooltip = (
+ const tooltip = component.analysisDate && (
<DateTimeFormatter date={component.analysisDate}>
{formattedAnalysisDate => (
<span>
@@ -169,7 +174,7 @@ export default function enhance(ComposedComponent) {
);
};
- renderHistoryLink = metricKey => {
+ renderHistoryLink = (metricKey: string) => {
const linkClass = 'button button-small spacer-left overview-domain-measure-history-link';
return (
<Link
@@ -180,7 +185,7 @@ export default function enhance(ComposedComponent) {
);
};
- renderTimeline = (metricKey, range, children) => {
+ renderTimeline = (metricKey: string, range: 'before' | 'after', children?: React.ReactNode) => {
if (!this.props.history) {
return null;
}
@@ -188,10 +193,7 @@ export default function enhance(ComposedComponent) {
if (!history) {
return null;
}
- const props = {
- history,
- [range]: getPeriodDate(this.props.leakPeriod)
- };
+ const props = { history, [range]: getPeriodDate(this.props.leakPeriod) };
return (
<div className="overview-domain-timeline">
<Timeline {...props} />
@@ -208,7 +210,6 @@ export default function enhance(ComposedComponent) {
renderHeader={this.renderHeader}
renderHistoryLink={this.renderHistoryLink}
renderMeasure={this.renderMeasure}
- renderMeasureVariation={this.renderMeasureVariation}
renderRating={this.renderRating}
renderIssues={this.renderIssues}
renderTimeline={this.renderTimeline}
diff --git a/server/sonar-web/src/main/js/apps/overview/meta/Meta.js b/server/sonar-web/src/main/js/apps/overview/meta/Meta.tsx
index 0422440aa99..bfffecd1f7c 100644
--- a/server/sonar-web/src/main/js/apps/overview/meta/Meta.js
+++ b/server/sonar-web/src/main/js/apps/overview/meta/Meta.tsx
@@ -17,7 +17,7 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-import React from 'react';
+import * as React from 'react';
import { connect } from 'react-redux';
import MetaKey from './MetaKey';
import MetaOrganizationKey from './MetaOrganizationKey';
@@ -29,17 +29,25 @@ import MetaSize from './MetaSize';
import MetaTags from './MetaTags';
import BadgesModal from '../badges/BadgesModal';
import { areThereCustomOrganizations, getGlobalSettingValue } from '../../../store/rootReducer';
-import { Visibility } from '../../../app/types';
-
-const Meta = ({
- branch,
- component,
- history,
- measures,
- areThereCustomOrganizations,
- onComponentChange,
- onSonarCloud
-}) => {
+import { Visibility, Component } from '../../../app/types';
+import { History } from '../../../api/time-machine';
+import { MeasureEnhanced } from '../../../helpers/measures';
+
+interface OwnProps {
+ branch?: string;
+ component: Component;
+ history?: History;
+ measures: MeasureEnhanced[];
+ onComponentChange: (changes: {}) => void;
+}
+
+interface StateToProps {
+ areThereCustomOrganizations: boolean;
+ onSonarCloud: boolean;
+}
+
+export function Meta(props: OwnProps & StateToProps) {
+ const { branch, component, areThereCustomOrganizations } = props;
const { qualifier, description, qualityProfiles, qualityGate, visibility } = component;
const isProject = qualifier === 'TRK';
@@ -59,15 +67,15 @@ const Meta = ({
<div className="overview-meta-card overview-meta-description">{description}</div>
)}
- <MetaSize branch={branch} component={component} measures={measures} />
+ <MetaSize branch={branch} component={component} measures={props.measures} />
- {isProject && <MetaTags component={component} onComponentChange={onComponentChange} />}
+ {isProject && <MetaTags component={component} onComponentChange={props.onComponentChange} />}
<AnalysesList
branch={branch}
component={component}
qualifier={component.qualifier}
- history={history}
+ history={props.history}
/>
{shouldShowQualityGate && (
@@ -91,14 +99,14 @@ const Meta = ({
{hasOrganization && <MetaOrganizationKey component={component} />}
- {onSonarCloud &&
+ {props.onSonarCloud &&
isProject &&
!isPrivate && <BadgesModal branch={branch} project={component.key} />}
</div>
);
-};
+}
-const mapStateToProps = state => {
+const mapStateToProps = (state: any): StateToProps => {
const sonarCloudSetting = getGlobalSettingValue(state, 'sonar.sonarcloud.enabled');
return {
areThereCustomOrganizations: areThereCustomOrganizations(state),
@@ -106,4 +114,4 @@ const mapStateToProps = state => {
};
};
-export default connect(mapStateToProps)(Meta);
+export default connect<StateToProps, {}, OwnProps>(mapStateToProps)(Meta);
diff --git a/server/sonar-web/src/main/js/apps/overview/meta/MetaLink.js b/server/sonar-web/src/main/js/apps/overview/meta/MetaLink.tsx
index a59e818bc16..b704420b5ed 100644
--- a/server/sonar-web/src/main/js/apps/overview/meta/MetaLink.js
+++ b/server/sonar-web/src/main/js/apps/overview/meta/MetaLink.tsx
@@ -17,43 +17,33 @@
* 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 * as React from 'react';
import { isProvided, isClickable } from '../../project-admin/links/utils';
import BugTrackerIcon from '../../../components/ui/BugTrackerIcon';
+import { ProjectLink } from '../../../api/projectLinks';
-/*::
-type Link = {
- id: string,
- name: string,
- url: string,
- type: string
-};
-*/
+interface Props {
+ link: ProjectLink;
+}
-/*::
-type State = {|
- expanded: boolean
-|};
-*/
+interface State {
+ expanded: boolean;
+}
-export default class MetaLink extends React.PureComponent {
- /*:: props: {
- link: Link
- };
-*/
+export default class MetaLink extends React.PureComponent<Props, State> {
+ state: State = { expanded: false };
- state /*: State */ = {
- expanded: false
+ handleClick = (e: React.SyntheticEvent<HTMLAnchorElement>) => {
+ e.preventDefault();
+ e.currentTarget.blur();
+ this.setState((s: State) => ({ expanded: !s.expanded }));
};
- handleClick = (e /*: Object */) => {
- e.preventDefault();
- e.target.blur();
- this.setState((s /*: State */) => ({ expanded: !s.expanded }));
+ handleInputClick = (e: React.SyntheticEvent<HTMLInputElement>) => {
+ e.currentTarget.select();
};
- renderLinkIcon(link /*: Link */) {
+ renderLinkIcon = (link: ProjectLink) => {
if (link.type === 'issue') {
return <BugTrackerIcon />;
}
@@ -63,7 +53,7 @@ export default class MetaLink extends React.PureComponent {
) : (
<i className="icon-color-link icon-detach" />
);
- }
+ };
render() {
const { link } = this.props;
@@ -86,7 +76,7 @@ export default class MetaLink extends React.PureComponent {
className="overview-key"
value={link.url}
readOnly={true}
- onClick={e => e.target.select()}
+ onClick={this.handleInputClick}
/>
</div>
)}
diff --git a/server/sonar-web/src/main/js/apps/overview/meta/MetaLinks.js b/server/sonar-web/src/main/js/apps/overview/meta/MetaLinks.tsx
index 7e2ca4c1761..66980dda926 100644
--- a/server/sonar-web/src/main/js/apps/overview/meta/MetaLinks.js
+++ b/server/sonar-web/src/main/js/apps/overview/meta/MetaLinks.tsx
@@ -17,25 +17,30 @@
* 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 PropTypes from 'prop-types';
+import * as React from 'react';
import MetaLink from './MetaLink';
-import { getProjectLinks } from '../../../api/projectLinks';
+import { getProjectLinks, ProjectLink } from '../../../api/projectLinks';
import { orderLinks } from '../../project-admin/links/utils';
+import { LightComponent } from '../../../app/types';
-export default class MetaLinks extends React.PureComponent {
- static propTypes = {
- component: PropTypes.object.isRequired
- };
+interface Props {
+ component: LightComponent;
+}
+
+interface State {
+ links?: ProjectLink[];
+}
- state = {};
+export default class MetaLinks extends React.PureComponent<Props, State> {
+ mounted: boolean;
+ state: State = {};
componentDidMount() {
this.mounted = true;
this.loadLinks();
}
- componentDidUpdate(prevProps) {
+ componentDidUpdate(prevProps: Props) {
if (prevProps.component.key !== this.props.component.key) {
this.loadLinks();
}
@@ -45,18 +50,20 @@ export default class MetaLinks extends React.PureComponent {
this.mounted = false;
}
- loadLinks() {
- getProjectLinks(this.props.component.key).then(links => {
- if (this.mounted) {
- this.setState({ links });
- }
- });
- }
+ loadLinks = () =>
+ getProjectLinks(this.props.component.key).then(
+ links => {
+ if (this.mounted) {
+ this.setState({ links });
+ }
+ },
+ () => {}
+ );
render() {
const { links } = this.state;
- if (links == null || links.length === 0) {
+ if (!links || links.length === 0) {
return null;
}
diff --git a/server/sonar-web/src/main/js/apps/overview/meta/MetaSize.js b/server/sonar-web/src/main/js/apps/overview/meta/MetaSize.tsx
index 9d34ec90c2c..6465c861817 100644
--- a/server/sonar-web/src/main/js/apps/overview/meta/MetaSize.js
+++ b/server/sonar-web/src/main/js/apps/overview/meta/MetaSize.tsx
@@ -17,31 +17,31 @@
* 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 PropTypes from 'prop-types';
-import classNames from 'classnames';
-import { DrilldownLink } from '../../../components/shared/drilldown-link';
+import * as React from 'react';
+import * as classNames from 'classnames';
+import DrilldownLink from '../../../components/shared/DrilldownLink';
import LanguageDistributionContainer from '../../../components/charts/LanguageDistributionContainer';
import SizeRating from '../../../components/ui/SizeRating';
-import { formatMeasure } from '../../../helpers/measures';
+import { formatMeasure, MeasureEnhanced } from '../../../helpers/measures';
import { getMetricName } from '../helpers/metrics';
import { translate } from '../../../helpers/l10n';
+import { LightComponent } from '../../../app/types';
-export default class MetaSize extends React.PureComponent {
- static propTypes = {
- branch: PropTypes.string,
- component: PropTypes.object.isRequired,
- measures: PropTypes.array.isRequired
- };
+interface Props {
+ branch?: string;
+ component: LightComponent;
+ measures: MeasureEnhanced[];
+}
- renderLoC = ncloc => (
+export default class MetaSize extends React.PureComponent<Props> {
+ renderLoC = (ncloc: MeasureEnhanced) => (
<div
id="overview-ncloc"
className={classNames('overview-meta-size-ncloc', {
'is-half-width': this.props.component.qualifier === 'APP'
})}>
<span className="spacer-right">
- <SizeRating value={ncloc.value} />
+ <SizeRating value={Number(ncloc.value)} />
</span>
<DrilldownLink branch={this.props.branch} component={this.props.component.key} metric="ncloc">
{formatMeasure(ncloc.value, 'SHORT_INT')}
diff --git a/server/sonar-web/src/main/js/apps/overview/meta/MetaTags.js b/server/sonar-web/src/main/js/apps/overview/meta/MetaTags.tsx
index 409f3049e9a..f08c08252fe 100644
--- a/server/sonar-web/src/main/js/apps/overview/meta/MetaTags.js
+++ b/server/sonar-web/src/main/js/apps/overview/meta/MetaTags.tsx
@@ -17,48 +17,32 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-//@flow
-import React from 'react';
+import * as React from 'react';
import { setProjectTags } from '../../../api/components';
import { translate } from '../../../helpers/l10n';
import TagsList from '../../../components/tags/TagsList';
import MetaTagsSelector from './MetaTagsSelector';
+import { BubblePopupPosition } from '../../../components/common/BubblePopup';
+import { Component } from '../../../app/types';
-/*::
-type Props = {
- component: {
- key: string,
- tags: Array<string>,
- configuration?: {
- showSettings?: boolean
- }
- },
- onComponentChange: {} => void
-};
-*/
+interface Props {
+ component: Component;
+ onComponentChange: (changes: {}) => void;
+}
-/*::
-type State = {
- popupOpen: boolean,
- popupPosition: { top: number, right: number }
-};
-*/
+interface State {
+ popupOpen: boolean;
+ popupPosition: BubblePopupPosition;
+}
-export default class MetaTags extends React.PureComponent {
- /*:: card: HTMLElement; */
- /*:: tagsList: HTMLElement; */
- /*:: tagsSelector: HTMLElement; */
- /*:: props: Props; */
- state /*: State */ = {
- popupOpen: false,
- popupPosition: {
- top: 0,
- right: 0
- }
- };
+export default class MetaTags extends React.PureComponent<Props, State> {
+ card: HTMLDivElement | null;
+ tagsList: HTMLButtonElement | null;
+ tagsSelector: HTMLDivElement | null;
+ state: State = { popupOpen: false, popupPosition: { top: 0, right: 0 } };
componentDidMount() {
- if (this.canUpdateTags()) {
+ if (this.canUpdateTags() && this.tagsList && this.card) {
const buttonPos = this.tagsList.getBoundingClientRect();
const cardPos = this.card.getBoundingClientRect();
this.setState({ popupPosition: this.getPopupPos(buttonPos, cardPos) });
@@ -73,40 +57,35 @@ export default class MetaTags extends React.PureComponent {
window.removeEventListener('click', this.handleOutsideClick);
}
- handleKey = (evt /*: KeyboardEvent */) => {
+ handleKey = (evt: KeyboardEvent) => {
// Escape key
if (evt.keyCode === 27) {
this.setState({ popupOpen: false });
}
};
- handleOutsideClick = (evt /*: SyntheticInputEvent */) => {
- if (!this.tagsSelector || !this.tagsSelector.contains(evt.target)) {
+ handleOutsideClick = (evt: Event) => {
+ if (!this.tagsSelector || !this.tagsSelector.contains(evt.target as Node)) {
this.setState({ popupOpen: false });
}
};
- handleClick = (evt /*: MouseEvent */) => {
+ handleClick = (evt: React.SyntheticEvent<HTMLButtonElement>) => {
evt.stopPropagation();
this.setState(state => ({ popupOpen: !state.popupOpen }));
};
- canUpdateTags() {
+ canUpdateTags = () => {
const { configuration } = this.props.component;
return configuration && configuration.showSettings;
- }
+ };
- getPopupPos(
- eltPos /*: { height: number, width: number } */,
- containerPos /*: { width: number } */
- ) {
- return {
- top: eltPos.height,
- right: containerPos.width - eltPos.width
- };
- }
+ getPopupPos = (eltPos: ClientRect, containerPos: ClientRect) => ({
+ top: eltPos.height,
+ right: containerPos.width - eltPos.width
+ });
- handleSetProjectTags = (tags /*: Array<string> */) => {
+ handleSetProjectTags = (tags: string[]) => {
setProjectTags({ project: this.props.component.key, tags: tags.join(',') }).then(
() => this.props.onComponentChange({ tags }),
() => {}
@@ -114,8 +93,9 @@ export default class MetaTags extends React.PureComponent {
};
render() {
- const { tags, key } = this.props.component;
+ const { key } = this.props.component;
const { popupOpen, popupPosition } = this.state;
+ const tags = this.props.component.tags || [];
if (this.canUpdateTags()) {
return (
diff --git a/server/sonar-web/src/main/js/apps/overview/meta/MetaTagsSelector.js b/server/sonar-web/src/main/js/apps/overview/meta/MetaTagsSelector.tsx
index f728a15225d..2e2bb774a80 100644
--- a/server/sonar-web/src/main/js/apps/overview/meta/MetaTagsSelector.js
+++ b/server/sonar-web/src/main/js/apps/overview/meta/MetaTagsSelector.tsx
@@ -17,51 +17,44 @@
* 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 * as React from 'react';
import { without } from 'lodash';
import TagsSelector from '../../../components/tags/TagsSelector';
+import { BubblePopupPosition } from '../../../components/common/BubblePopup';
import { searchProjectTags } from '../../../api/components';
-/*::
-type Props = {
- position: {},
- project: string,
- selectedTags: Array<string>,
- setProjectTags: (Array<string>) => void
-};
-*/
+interface Props {
+ position: BubblePopupPosition;
+ project: string;
+ selectedTags: string[];
+ setProjectTags: (tags: string[]) => void;
+}
-/*::
-type State = {
- searchResult: Array<string>
-};
-*/
+interface State {
+ searchResult: string[];
+}
const LIST_SIZE = 10;
-export default class MetaTagsSelector extends React.PureComponent {
- /*:: props: Props; */
- state /*: State */ = { searchResult: [] };
+export default class MetaTagsSelector extends React.PureComponent<Props, State> {
+ state: State = { searchResult: [] };
componentDidMount() {
this.onSearch('');
}
- onSearch = (query /*: string */) => {
+ onSearch = (query: string) => {
searchProjectTags({
q: query,
ps: Math.min(this.props.selectedTags.length - 1 + LIST_SIZE, 100)
- }).then(result => {
- this.setState({ searchResult: result.tags });
- });
+ }).then(result => this.setState({ searchResult: result.tags }), () => {});
};
- onSelect = (tag /*: string */) => {
+ onSelect = (tag: string) => {
this.props.setProjectTags([...this.props.selectedTags, tag]);
};
- onUnselect = (tag /*: string */) => {
+ onUnselect = (tag: string) => {
this.props.setProjectTags(without(this.props.selectedTags, tag));
};
diff --git a/server/sonar-web/src/main/js/apps/overview/meta/__tests__/MetaLink-test.js b/server/sonar-web/src/main/js/apps/overview/meta/__tests__/MetaLink-test.tsx
index 2499c2e3c36..0bea70841d8 100644
--- a/server/sonar-web/src/main/js/apps/overview/meta/__tests__/MetaLink-test.js
+++ b/server/sonar-web/src/main/js/apps/overview/meta/__tests__/MetaLink-test.tsx
@@ -17,7 +17,7 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-import React from 'react';
+import * as React from 'react';
import { shallow } from 'enzyme';
import MetaLink from '../MetaLink';
import { click } from '../../../../helpers/testUtils';
diff --git a/server/sonar-web/src/main/js/apps/overview/meta/__tests__/MetaTags-test.js b/server/sonar-web/src/main/js/apps/overview/meta/__tests__/MetaTags-test.tsx
index 9a621ce7aa9..1479225a022 100644
--- a/server/sonar-web/src/main/js/apps/overview/meta/__tests__/MetaTags-test.js
+++ b/server/sonar-web/src/main/js/apps/overview/meta/__tests__/MetaTags-test.tsx
@@ -17,7 +17,7 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-import React from 'react';
+import * as React from 'react';
import { shallow } from 'enzyme';
import { click } from '../../../../helpers/testUtils';
import MetaTags from '../MetaTags';
@@ -27,7 +27,11 @@ const component = {
tags: [],
configuration: {
showSettings: false
- }
+ },
+ organization: 'foo',
+ qualifier: 'TRK',
+ name: 'MyProject',
+ breadcrumbs: []
};
const componentWithTags = {
@@ -35,25 +39,36 @@ const componentWithTags = {
tags: ['foo', 'bar'],
configuration: {
showSettings: true
- }
+ },
+ organization: 'foo',
+ qualifier: 'TRK',
+ name: 'MySecondProject',
+ breadcrumbs: []
};
it('should render without tags and admin rights', () => {
expect(
- shallow(<MetaTags component={component} />, { disableLifecycleMethods: true })
+ shallow(<MetaTags component={component} onComponentChange={jest.fn()} />, {
+ disableLifecycleMethods: true
+ })
).toMatchSnapshot();
});
it('should render with tags and admin rights', () => {
expect(
- shallow(<MetaTags component={componentWithTags} />, { disableLifecycleMethods: true })
+ shallow(<MetaTags component={componentWithTags} onComponentChange={jest.fn()} />, {
+ disableLifecycleMethods: true
+ })
).toMatchSnapshot();
});
it('should open the tag selector on click', () => {
- const wrapper = shallow(<MetaTags component={componentWithTags} />, {
- disableLifecycleMethods: true
- });
+ const wrapper = shallow(
+ <MetaTags component={componentWithTags} onComponentChange={jest.fn()} />,
+ {
+ disableLifecycleMethods: true
+ }
+ );
expect(wrapper).toMatchSnapshot();
// open
diff --git a/server/sonar-web/src/main/js/apps/overview/meta/__tests__/MetaTagsSelector-test.js b/server/sonar-web/src/main/js/apps/overview/meta/__tests__/MetaTagsSelector-test.tsx
index 2f7a364d101..aefeb8d6fb6 100644
--- a/server/sonar-web/src/main/js/apps/overview/meta/__tests__/MetaTagsSelector-test.js
+++ b/server/sonar-web/src/main/js/apps/overview/meta/__tests__/MetaTagsSelector-test.tsx
@@ -18,7 +18,7 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/* eslint-disable import/order, import/first */
-import React from 'react';
+import * as React from 'react';
import { mount, shallow } from 'enzyme';
import MetaTagsSelector from '../MetaTagsSelector';
@@ -35,9 +35,16 @@ jest.mock('lodash', () => {
import { searchProjectTags } from '../../../../api/components';
it('searches tags on mount', () => {
- searchProjectTags.mockImplementation(() => Promise.resolve({ tags: ['foo', 'bar'] }));
+ (searchProjectTags as jest.Mock).mockImplementation(() =>
+ Promise.resolve({ tags: ['foo', 'bar'] })
+ );
mount(
- <MetaTagsSelector position={{}} project="foo" selectedTags={[]} setProjectTags={jest.fn()} />
+ <MetaTagsSelector
+ position={{ top: 0, right: 0 }}
+ project="foo"
+ selectedTags={[]}
+ setProjectTags={jest.fn()}
+ />
);
expect(searchProjectTags).toBeCalledWith({ ps: 9, q: '' });
});
@@ -46,17 +53,18 @@ it('selects and deselects tags', () => {
const setProjectTags = jest.fn();
const wrapper = shallow(
<MetaTagsSelector
- position={{}}
+ position={{ top: 0, right: 0 }}
project="foo"
selectedTags={['foo', 'bar']}
setProjectTags={setProjectTags}
/>
);
- wrapper.find('TagsSelector').prop('onSelect')('baz');
+ const tagSelect: any = wrapper.find('TagsSelector');
+ tagSelect.prop('onSelect')('baz');
expect(setProjectTags).toHaveBeenLastCalledWith(['foo', 'bar', 'baz']);
// note that the `selectedTags` is a prop and so it wasn't changed
- wrapper.find('TagsSelector').prop('onUnselect')('bar');
+ tagSelect.prop('onUnselect')('bar');
expect(setProjectTags).toHaveBeenLastCalledWith(['foo']);
});
diff --git a/server/sonar-web/src/main/js/apps/overview/meta/__tests__/__snapshots__/MetaLink-test.js.snap b/server/sonar-web/src/main/js/apps/overview/meta/__tests__/__snapshots__/MetaLink-test.tsx.snap
index 20c6a30481a..20c6a30481a 100644
--- a/server/sonar-web/src/main/js/apps/overview/meta/__tests__/__snapshots__/MetaLink-test.js.snap
+++ b/server/sonar-web/src/main/js/apps/overview/meta/__tests__/__snapshots__/MetaLink-test.tsx.snap
diff --git a/server/sonar-web/src/main/js/apps/overview/meta/__tests__/__snapshots__/MetaTags-test.js.snap b/server/sonar-web/src/main/js/apps/overview/meta/__tests__/__snapshots__/MetaTags-test.tsx.snap
index 875302462d5..875302462d5 100644
--- a/server/sonar-web/src/main/js/apps/overview/meta/__tests__/__snapshots__/MetaTags-test.js.snap
+++ b/server/sonar-web/src/main/js/apps/overview/meta/__tests__/__snapshots__/MetaTags-test.tsx.snap
diff --git a/server/sonar-web/src/main/js/apps/overview/qualityGate/ApplicationQualityGate.js b/server/sonar-web/src/main/js/apps/overview/qualityGate/ApplicationQualityGate.tsx
index 6528d5a44e8..3d8202f0d9d 100644
--- a/server/sonar-web/src/main/js/apps/overview/qualityGate/ApplicationQualityGate.js
+++ b/server/sonar-web/src/main/js/apps/overview/qualityGate/ApplicationQualityGate.tsx
@@ -17,47 +17,35 @@
* 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 * as React from 'react';
import { keyBy } from 'lodash';
import ApplicationQualityGateProject from './ApplicationQualityGateProject';
import Level from '../../../components/ui/Level';
-import { getApplicationQualityGate } from '../../../api/quality-gates';
+import { getApplicationQualityGate, ApplicationProject } from '../../../api/quality-gates';
import { translate } from '../../../helpers/l10n';
+import { LightComponent, Metric } from '../../../app/types';
-/*::
-type Props = {
- component: { key: string, organization?: string }
-};
-*/
+interface Props {
+ component: LightComponent;
+}
-/*::
type State = {
- loading: boolean,
- metrics?: { [string]: Object },
- projects?: Array<{
- conditions: Array<Object>,
- key: string,
- name: string,
- status: string
- }>,
- status?: string
+ loading: boolean;
+ metrics?: { [key: string]: Metric };
+ projects?: ApplicationProject[];
+ status?: string;
};
-*/
-export default class ApplicationQualityGate extends React.PureComponent {
- /*:: mounted: boolean; */
- /*:: props: Props; */
- state /*: State */ = {
- loading: true
- };
+export default class ApplicationQualityGate extends React.PureComponent<Props, State> {
+ mounted: boolean;
+ state: State = { loading: true };
componentDidMount() {
this.mounted = true;
this.fetchDetails();
}
- componentDidUpdate(prevProps /*: Props */) {
+ componentDidUpdate(prevProps: Props) {
if (prevProps.component.key !== this.props.component.key) {
this.fetchDetails();
}
@@ -103,21 +91,22 @@ export default class ApplicationQualityGate extends React.PureComponent {
{status != null && <Level level={status} />}
</h2>
- {projects != null && (
- <div
- id="overview-quality-gate-conditions-list"
- className="overview-quality-gate-conditions-list clearfix">
- {projects
- .filter(project => project.status !== 'OK')
- .map(project => (
- <ApplicationQualityGateProject
- key={project.key}
- metrics={metrics}
- project={project}
- />
- ))}
- </div>
- )}
+ {projects &&
+ metrics && (
+ <div
+ id="overview-quality-gate-conditions-list"
+ className="overview-quality-gate-conditions-list clearfix">
+ {projects
+ .filter(project => project.status !== 'OK')
+ .map(project => (
+ <ApplicationQualityGateProject
+ key={project.key}
+ metrics={metrics}
+ project={project}
+ />
+ ))}
+ </div>
+ )}
</div>
);
}
diff --git a/server/sonar-web/src/main/js/apps/overview/qualityGate/ApplicationQualityGateProject.js b/server/sonar-web/src/main/js/apps/overview/qualityGate/ApplicationQualityGateProject.tsx
index 451c808abc9..388b77005ee 100644
--- a/server/sonar-web/src/main/js/apps/overview/qualityGate/ApplicationQualityGateProject.js
+++ b/server/sonar-web/src/main/js/apps/overview/qualityGate/ApplicationQualityGateProject.tsx
@@ -17,49 +17,23 @@
* 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 * as React from 'react';
+import * as classNames from 'classnames';
import { Link } from 'react-router';
-import classNames from 'classnames';
import { getLocalizedMetricName, translate } from '../../../helpers/l10n';
import { formatMeasure, isDiffMetric } from '../../../helpers/measures';
import { getProjectUrl } from '../../../helpers/urls';
import './ApplicationQualityGateProject.css';
+import { Metric } from '../../../app/types';
+import { ApplicationProject, ConditionAnalysis } from '../../../api/quality-gates';
-/*::
-type Condition = {
- comparator: string,
- errorThreshold?: string,
- metric: string,
- onLeak: boolean,
- status: string,
- value: string,
- warningThreshold?: string
-};
-*/
-
-/*::
-type Props = {
- metrics: {
- [string]: {
- key: string,
- name: string,
- type: string
- }
- },
- project: {
- conditions: Array<Condition>,
- key: string,
- name: string,
- status: string
- }
-};
-*/
-
-export default class ApplicationQualityGateProject extends React.PureComponent {
- /*:: props: Props; */
+interface Props {
+ metrics: { [key: string]: Metric };
+ project: ApplicationProject;
+}
- renderCondition = (condition /*: Condition */) => {
+export default class ApplicationQualityGateProject extends React.PureComponent<Props> {
+ renderCondition = (condition: ConditionAnalysis) => {
const metric = this.props.metrics[condition.metric];
const metricName = getLocalizedMetricName(metric);
const threshold = condition.errorThreshold || condition.warningThreshold;
diff --git a/server/sonar-web/src/main/js/apps/overview/qualityGate/QualityGateCondition.js b/server/sonar-web/src/main/js/apps/overview/qualityGate/QualityGateCondition.js
index 71eeccc2932..3301c33ef6f 100644
--- a/server/sonar-web/src/main/js/apps/overview/qualityGate/QualityGateCondition.js
+++ b/server/sonar-web/src/main/js/apps/overview/qualityGate/QualityGateCondition.js
@@ -21,7 +21,7 @@
import React from 'react';
import classNames from 'classnames';
import { Link } from 'react-router';
-import { DrilldownLink } from '../../../components/shared/drilldown-link';
+import DrilldownLink from '../../../components/shared/DrilldownLink';
import Measure from '../../../components/measure/Measure';
import IssueTypeIcon from '../../../components/ui/IssueTypeIcon';
import { getPeriodValue, isDiffMetric, formatMeasure } from '../../../helpers/measures';
@@ -146,7 +146,12 @@ export default class QualityGateCondition extends React.PureComponent {
return this.wrapWithLink(
<div className="overview-quality-gate-condition-container">
<div className="overview-quality-gate-condition-value">
- <Measure measure={{ ...measure, value: actual, leak: actual }} decimals={decimals} />
+ <Measure
+ decimals={decimals}
+ value={actual}
+ metricKey={measure.metric.key}
+ metricType={measure.metric.type}
+ />
</div>
<div>
diff --git a/server/sonar-web/src/main/js/apps/overview/qualityGate/__tests__/ApplicationQualityGate-test.js b/server/sonar-web/src/main/js/apps/overview/qualityGate/__tests__/ApplicationQualityGate-test.tsx
index 5d6170c69ea..fc15b30e10b 100644
--- a/server/sonar-web/src/main/js/apps/overview/qualityGate/__tests__/ApplicationQualityGate-test.js
+++ b/server/sonar-web/src/main/js/apps/overview/qualityGate/__tests__/ApplicationQualityGate-test.tsx
@@ -17,13 +17,14 @@
* 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 * as React from 'react';
import { shallow } from 'enzyme';
import ApplicationQualityGate from '../ApplicationQualityGate';
it('renders', () => {
- const wrapper = shallow(<ApplicationQualityGate component={{ key: 'foo' }} />);
+ const wrapper = shallow(
+ <ApplicationQualityGate component={{ key: 'foo', organization: 'foo', qualifier: 'TRK' }} />
+ );
expect(wrapper).toMatchSnapshot();
wrapper.setState({
loading: false,
diff --git a/server/sonar-web/src/main/js/apps/overview/qualityGate/__tests__/ApplicationQualityGateProject-test.js b/server/sonar-web/src/main/js/apps/overview/qualityGate/__tests__/ApplicationQualityGateProject-test.tsx
index 87d7f69861d..3f7904c67e6 100644
--- a/server/sonar-web/src/main/js/apps/overview/qualityGate/__tests__/ApplicationQualityGateProject-test.js
+++ b/server/sonar-web/src/main/js/apps/overview/qualityGate/__tests__/ApplicationQualityGateProject-test.tsx
@@ -17,8 +17,7 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-// @flow
-import React from 'react';
+import * as React from 'react';
import { shallow } from 'enzyme';
import ApplicationQualityGateProject from '../ApplicationQualityGateProject';
diff --git a/server/sonar-web/src/main/js/apps/overview/qualityGate/__tests__/__snapshots__/ApplicationQualityGate-test.js.snap b/server/sonar-web/src/main/js/apps/overview/qualityGate/__tests__/__snapshots__/ApplicationQualityGate-test.tsx.snap
index 5a7f39cf4d9..5a7f39cf4d9 100644
--- a/server/sonar-web/src/main/js/apps/overview/qualityGate/__tests__/__snapshots__/ApplicationQualityGate-test.js.snap
+++ b/server/sonar-web/src/main/js/apps/overview/qualityGate/__tests__/__snapshots__/ApplicationQualityGate-test.tsx.snap
diff --git a/server/sonar-web/src/main/js/apps/overview/qualityGate/__tests__/__snapshots__/ApplicationQualityGateProject-test.js.snap b/server/sonar-web/src/main/js/apps/overview/qualityGate/__tests__/__snapshots__/ApplicationQualityGateProject-test.tsx.snap
index 64d2bf86cfb..64d2bf86cfb 100644
--- a/server/sonar-web/src/main/js/apps/overview/qualityGate/__tests__/__snapshots__/ApplicationQualityGateProject-test.js.snap
+++ b/server/sonar-web/src/main/js/apps/overview/qualityGate/__tests__/__snapshots__/ApplicationQualityGateProject-test.tsx.snap
diff --git a/server/sonar-web/src/main/js/apps/overview/qualityGate/__tests__/__snapshots__/QualityGateCondition-test.js.snap b/server/sonar-web/src/main/js/apps/overview/qualityGate/__tests__/__snapshots__/QualityGateCondition-test.js.snap
index 2c31f8e7d5b..e286b3da99d 100644
--- a/server/sonar-web/src/main/js/apps/overview/qualityGate/__tests__/__snapshots__/QualityGateCondition-test.js.snap
+++ b/server/sonar-web/src/main/js/apps/overview/qualityGate/__tests__/__snapshots__/QualityGateCondition-test.js.snap
@@ -26,23 +26,9 @@ exports[`new_maintainability_rating 1`] = `
>
<Measure
decimals={null}
- measure={
- Object {
- "leak": "3",
- "metric": Object {
- "key": "new_maintainability_rating",
- "name": "new_maintainability_rating",
- "type": "RATING",
- },
- "periods": Array [
- Object {
- "index": 1,
- "value": "3",
- },
- ],
- "value": "3",
- }
- }
+ metricKey="new_maintainability_rating"
+ metricType="RATING"
+ value="3"
/>
</div>
<div>
@@ -82,23 +68,9 @@ exports[`new_open_issues 1`] = `
>
<Measure
decimals={null}
- measure={
- Object {
- "leak": "10",
- "metric": Object {
- "key": "new_open_issues",
- "name": "new_open_issues",
- "type": "INT",
- },
- "periods": Array [
- Object {
- "index": 1,
- "value": "10",
- },
- ],
- "value": "10",
- }
- }
+ metricKey="new_open_issues"
+ metricType="INT"
+ value="10"
/>
</div>
<div>
@@ -150,23 +122,9 @@ exports[`new_reliability_rating 1`] = `
>
<Measure
decimals={null}
- measure={
- Object {
- "leak": "3",
- "metric": Object {
- "key": "new_reliability_rating",
- "name": "new_reliability_rating",
- "type": "RATING",
- },
- "periods": Array [
- Object {
- "index": 1,
- "value": "3",
- },
- ],
- "value": "3",
- }
- }
+ metricKey="new_reliability_rating"
+ metricType="RATING"
+ value="3"
/>
</div>
<div>
@@ -218,23 +176,9 @@ exports[`new_security_rating 1`] = `
>
<Measure
decimals={null}
- measure={
- Object {
- "leak": "3",
- "metric": Object {
- "key": "new_security_rating",
- "name": "new_security_rating",
- "type": "RATING",
- },
- "periods": Array [
- Object {
- "index": 1,
- "value": "3",
- },
- ],
- "value": "3",
- }
- }
+ metricKey="new_security_rating"
+ metricType="RATING"
+ value="3"
/>
</div>
<div>
@@ -274,17 +218,9 @@ exports[`open_issues 1`] = `
>
<Measure
decimals={null}
- measure={
- Object {
- "leak": "10",
- "metric": Object {
- "key": "open_issues",
- "name": "Open open_issues",
- "type": "INT",
- },
- "value": "10",
- }
- }
+ metricKey="open_issues"
+ metricType="INT"
+ value="10"
/>
</div>
<div>
@@ -335,17 +271,9 @@ exports[`reliability_rating 1`] = `
>
<Measure
decimals={null}
- measure={
- Object {
- "leak": "3",
- "metric": Object {
- "key": "reliability_rating",
- "name": "reliability_rating",
- "type": "RATING",
- },
- "value": "3",
- }
- }
+ metricKey="reliability_rating"
+ metricType="RATING"
+ value="3"
/>
</div>
<div>
@@ -396,17 +324,9 @@ exports[`security_rating 1`] = `
>
<Measure
decimals={null}
- measure={
- Object {
- "leak": "3",
- "metric": Object {
- "key": "security_rating",
- "name": "security_rating",
- "type": "RATING",
- },
- "value": "3",
- }
- }
+ metricKey="security_rating"
+ metricType="RATING"
+ value="3"
/>
</div>
<div>
@@ -457,17 +377,9 @@ exports[`should work with branch 1`] = `
>
<Measure
decimals={null}
- measure={
- Object {
- "leak": "3",
- "metric": Object {
- "key": "new_maintainability_rating",
- "name": "new_maintainability_rating",
- "type": "RATING",
- },
- "value": "3",
- }
- }
+ metricKey="new_maintainability_rating"
+ metricType="RATING"
+ value="3"
/>
</div>
<div>
@@ -517,17 +429,9 @@ exports[`sqale_rating 1`] = `
>
<Measure
decimals={null}
- measure={
- Object {
- "leak": "3",
- "metric": Object {
- "key": "sqale_rating",
- "name": "sqale_rating",
- "type": "RATING",
- },
- "value": "3",
- }
- }
+ metricKey="sqale_rating"
+ metricType="RATING"
+ value="3"
/>
</div>
<div>
diff --git a/server/sonar-web/src/main/js/apps/portfolio/components/Effort.tsx b/server/sonar-web/src/main/js/apps/portfolio/components/Effort.tsx
index 69bd9c4b254..4029dbe7a38 100644
--- a/server/sonar-web/src/main/js/apps/portfolio/components/Effort.tsx
+++ b/server/sonar-web/src/main/js/apps/portfolio/components/Effort.tsx
@@ -42,11 +42,11 @@ export default function Effort({ component, effort, metricKey }: Props) {
<Link to={getComponentDrilldownUrl(component, metricKey)}>
<span>
<Measure
- measure={{
- metric: { key: 'projects', type: 'SHORT_INT' },
- value: String(effort.projects)
- }}
- />{' '}
+ className="little-spacer-right"
+ metricKey="projects"
+ metricType="SHORT_INT"
+ value={String(effort.projects)}
+ />
{translate('projects_')}
</span>
</Link>
diff --git a/server/sonar-web/src/main/js/apps/portfolio/components/ReleasabilityBox.tsx b/server/sonar-web/src/main/js/apps/portfolio/components/ReleasabilityBox.tsx
index 5a57b31cd9d..ff7a2dd2f15 100644
--- a/server/sonar-web/src/main/js/apps/portfolio/components/ReleasabilityBox.tsx
+++ b/server/sonar-web/src/main/js/apps/portfolio/components/ReleasabilityBox.tsx
@@ -55,8 +55,11 @@ export default function ReleasabilityBox({ component, measures }: Props) {
<Link to={getComponentDrilldownUrl(component, 'alert_status')}>
<span>
<Measure
- measure={{ metric: { key: 'projects', type: 'SHORT_INT' }, value: effort }}
- />{' '}
+ className="little-spacer-right"
+ metricKey="projects"
+ metricType="SHORT_INT"
+ value={effort}
+ />
{Number(effort) === 1 ? 'project' : 'projects'}
</span>
</Link>{' '}
diff --git a/server/sonar-web/src/main/js/apps/portfolio/components/Summary.tsx b/server/sonar-web/src/main/js/apps/portfolio/components/Summary.tsx
index 3279b530d70..75ef3f32723 100644
--- a/server/sonar-web/src/main/js/apps/portfolio/components/Summary.tsx
+++ b/server/sonar-web/src/main/js/apps/portfolio/components/Summary.tsx
@@ -41,9 +41,7 @@ export default function Summary({ component, measures }: Props) {
<li>
<div className="portfolio-measure-secondary-value">
<Link to={getComponentDrilldownUrl(component.key, 'projects')}>
- <Measure
- measure={{ metric: { key: 'projects', type: 'SHORT_INT' }, value: projects }}
- />
+ <Measure metricKey="projects" metricType="SHORT_INT" value={projects} />
</Link>
</div>
<div className="spacer-top text-muted">{translate('projects')}</div>
@@ -51,7 +49,7 @@ export default function Summary({ component, measures }: Props) {
<li>
<div className="portfolio-measure-secondary-value">
<Link to={getComponentDrilldownUrl(component.key, 'ncloc')}>
- <Measure measure={{ metric: { key: 'ncloc', type: 'SHORT_INT' }, value: ncloc }} />
+ <Measure metricKey="ncloc" metricType="SHORT_INT" value={ncloc} />
</Link>
</div>
<div className="spacer-top text-muted">{translate('metric.ncloc.name')}</div>
diff --git a/server/sonar-web/src/main/js/apps/portfolio/components/WorstProjects.tsx b/server/sonar-web/src/main/js/apps/portfolio/components/WorstProjects.tsx
index 3e297104882..2dc04f3278b 100644
--- a/server/sonar-web/src/main/js/apps/portfolio/components/WorstProjects.tsx
+++ b/server/sonar-web/src/main/js/apps/portfolio/components/WorstProjects.tsx
@@ -110,7 +110,7 @@ export default function WorstProjects({ component, subComponents, total }: Props
function renderCell(measures: { [key: string]: string | undefined }, metric: string, type: string) {
return (
<td className="text-center">
- <Measure measure={{ metric: { key: metric, type }, value: measures[metric] }} />
+ <Measure metricKey={metric} metricType={type} value={measures[metric]} />
</td>
);
}
@@ -121,12 +121,7 @@ function renderNcloc(measures: { [key: string]: string | undefined }, maxLoc: nu
return (
<td className="text-right">
<span className="note">
- <Measure
- measure={{
- metric: { key: 'ncloc', type: 'SHORT_INT' },
- value: measures['ncloc']
- }}
- />
+ <Measure metricKey="ncloc" metricType="SHORT_INT" value={measures['ncloc']} />
</span>
{maxLoc > 0 && (
<svg width="50" height="16" className="spacer-left">
diff --git a/server/sonar-web/src/main/js/apps/portfolio/components/__tests__/__snapshots__/Effort-test.tsx.snap b/server/sonar-web/src/main/js/apps/portfolio/components/__tests__/__snapshots__/Effort-test.tsx.snap
index 989531cad1e..8918c9e4b99 100644
--- a/server/sonar-web/src/main/js/apps/portfolio/components/__tests__/__snapshots__/Effort-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/portfolio/components/__tests__/__snapshots__/Effort-test.tsx.snap
@@ -25,17 +25,11 @@ exports[`renders 1`] = `
>
<span>
<Measure
- measure={
- Object {
- "metric": Object {
- "key": "projects",
- "type": "SHORT_INT",
- },
- "value": "3",
- }
- }
+ className="little-spacer-right"
+ metricKey="projects"
+ metricType="SHORT_INT"
+ value="3"
/>
-
projects_
</span>
</Link>,
diff --git a/server/sonar-web/src/main/js/apps/portfolio/components/__tests__/__snapshots__/ReleasabilityBox-test.tsx.snap b/server/sonar-web/src/main/js/apps/portfolio/components/__tests__/__snapshots__/ReleasabilityBox-test.tsx.snap
index 3db58b7d539..c2120360b56 100644
--- a/server/sonar-web/src/main/js/apps/portfolio/components/__tests__/__snapshots__/ReleasabilityBox-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/portfolio/components/__tests__/__snapshots__/ReleasabilityBox-test.tsx.snap
@@ -50,17 +50,11 @@ exports[`renders 1`] = `
>
<span>
<Measure
- measure={
- Object {
- "metric": Object {
- "key": "projects",
- "type": "SHORT_INT",
- },
- "value": "7",
- }
- }
+ className="little-spacer-right"
+ metricKey="projects"
+ metricType="SHORT_INT"
+ value="7"
/>
-
projects
</span>
</Link>
diff --git a/server/sonar-web/src/main/js/apps/portfolio/components/__tests__/__snapshots__/Summary-test.tsx.snap b/server/sonar-web/src/main/js/apps/portfolio/components/__tests__/__snapshots__/Summary-test.tsx.snap
index f8f2706777d..149c818b286 100644
--- a/server/sonar-web/src/main/js/apps/portfolio/components/__tests__/__snapshots__/Summary-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/portfolio/components/__tests__/__snapshots__/Summary-test.tsx.snap
@@ -32,15 +32,9 @@ exports[`renders 1`] = `
}
>
<Measure
- measure={
- Object {
- "metric": Object {
- "key": "projects",
- "type": "SHORT_INT",
- },
- "value": "15",
- }
- }
+ metricKey="projects"
+ metricType="SHORT_INT"
+ value="15"
/>
</Link>
</div>
@@ -69,15 +63,9 @@ exports[`renders 1`] = `
}
>
<Measure
- measure={
- Object {
- "metric": Object {
- "key": "ncloc",
- "type": "SHORT_INT",
- },
- "value": "1234",
- }
- }
+ metricKey="ncloc"
+ metricType="SHORT_INT"
+ value="1234"
/>
</Link>
</div>
diff --git a/server/sonar-web/src/main/js/apps/portfolio/components/__tests__/__snapshots__/WorstProjects-test.tsx.snap b/server/sonar-web/src/main/js/apps/portfolio/components/__tests__/__snapshots__/WorstProjects-test.tsx.snap
index c36279d6709..736ab248060 100644
--- a/server/sonar-web/src/main/js/apps/portfolio/components/__tests__/__snapshots__/WorstProjects-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/portfolio/components/__tests__/__snapshots__/WorstProjects-test.tsx.snap
@@ -70,60 +70,36 @@ exports[`renders 1`] = `
className="text-center"
>
<Measure
- measure={
- Object {
- "metric": Object {
- "key": "releasability_rating",
- "type": "RATING",
- },
- "value": "3",
- }
- }
+ metricKey="releasability_rating"
+ metricType="RATING"
+ value="3"
/>
</td>
<td
className="text-center"
>
<Measure
- measure={
- Object {
- "metric": Object {
- "key": "reliability_rating",
- "type": "RATING",
- },
- "value": "2",
- }
- }
+ metricKey="reliability_rating"
+ metricType="RATING"
+ value="2"
/>
</td>
<td
className="text-center"
>
<Measure
- measure={
- Object {
- "metric": Object {
- "key": "security_rating",
- "type": "RATING",
- },
- "value": "1",
- }
- }
+ metricKey="security_rating"
+ metricType="RATING"
+ value="1"
/>
</td>
<td
className="text-center"
>
<Measure
- measure={
- Object {
- "metric": Object {
- "key": "sqale_rating",
- "type": "RATING",
- },
- "value": "4",
- }
- }
+ metricKey="sqale_rating"
+ metricType="RATING"
+ value="4"
/>
</td>
<td
@@ -133,15 +109,9 @@ exports[`renders 1`] = `
className="note"
>
<Measure
- measure={
- Object {
- "metric": Object {
- "key": "ncloc",
- "type": "SHORT_INT",
- },
- "value": "200",
- }
- }
+ metricKey="ncloc"
+ metricType="SHORT_INT"
+ value="200"
/>
</span>
<svg
@@ -188,60 +158,36 @@ exports[`renders 1`] = `
className="text-center"
>
<Measure
- measure={
- Object {
- "metric": Object {
- "key": "alert_status",
- "type": "LEVEL",
- },
- "value": "ERROR",
- }
- }
+ metricKey="alert_status"
+ metricType="LEVEL"
+ value="ERROR"
/>
</td>
<td
className="text-center"
>
<Measure
- measure={
- Object {
- "metric": Object {
- "key": "reliability_rating",
- "type": "RATING",
- },
- "value": "2",
- }
- }
+ metricKey="reliability_rating"
+ metricType="RATING"
+ value="2"
/>
</td>
<td
className="text-center"
>
<Measure
- measure={
- Object {
- "metric": Object {
- "key": "security_rating",
- "type": "RATING",
- },
- "value": "1",
- }
- }
+ metricKey="security_rating"
+ metricType="RATING"
+ value="1"
/>
</td>
<td
className="text-center"
>
<Measure
- measure={
- Object {
- "metric": Object {
- "key": "sqale_rating",
- "type": "RATING",
- },
- "value": "4",
- }
- }
+ metricKey="sqale_rating"
+ metricType="RATING"
+ value="4"
/>
</td>
<td
@@ -251,15 +197,9 @@ exports[`renders 1`] = `
className="note"
>
<Measure
- measure={
- Object {
- "metric": Object {
- "key": "ncloc",
- "type": "SHORT_INT",
- },
- "value": "100",
- }
- }
+ metricKey="ncloc"
+ metricType="SHORT_INT"
+ value="100"
/>
</span>
<svg
@@ -306,60 +246,36 @@ exports[`renders 1`] = `
className="text-center"
>
<Measure
- measure={
- Object {
- "metric": Object {
- "key": "alert_status",
- "type": "LEVEL",
- },
- "value": "WARN",
- }
- }
+ metricKey="alert_status"
+ metricType="LEVEL"
+ value="WARN"
/>
</td>
<td
className="text-center"
>
<Measure
- measure={
- Object {
- "metric": Object {
- "key": "reliability_rating",
- "type": "RATING",
- },
- "value": "2",
- }
- }
+ metricKey="reliability_rating"
+ metricType="RATING"
+ value="2"
/>
</td>
<td
className="text-center"
>
<Measure
- measure={
- Object {
- "metric": Object {
- "key": "security_rating",
- "type": "RATING",
- },
- "value": "1",
- }
- }
+ metricKey="security_rating"
+ metricType="RATING"
+ value="1"
/>
</td>
<td
className="text-center"
>
<Measure
- measure={
- Object {
- "metric": Object {
- "key": "sqale_rating",
- "type": "RATING",
- },
- "value": "4",
- }
- }
+ metricKey="sqale_rating"
+ metricType="RATING"
+ value="4"
/>
</td>
<td
@@ -369,15 +285,9 @@ exports[`renders 1`] = `
className="note"
>
<Measure
- measure={
- Object {
- "metric": Object {
- "key": "ncloc",
- "type": "SHORT_INT",
- },
- "value": "150",
- }
- }
+ metricKey="ncloc"
+ metricType="SHORT_INT"
+ value="150"
/>
</span>
<svg
diff --git a/server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityAppContainer.js b/server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityAppContainer.js
index 25157da7d59..51d28646604 100644
--- a/server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityAppContainer.js
+++ b/server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityAppContainer.js
@@ -198,7 +198,7 @@ export default class ProjectActivityAppContainer extends React.PureComponent {
value: analysis.value
}))
})),
- throwGlobalError
+ () => {}
);
};
diff --git a/server/sonar-web/src/main/js/apps/projects/components/ProjectCardLeakMeasures.tsx b/server/sonar-web/src/main/js/apps/projects/components/ProjectCardLeakMeasures.tsx
index 4efd5855aff..50c440bda9c 100644
--- a/server/sonar-web/src/main/js/apps/projects/components/ProjectCardLeakMeasures.tsx
+++ b/server/sonar-web/src/main/js/apps/projects/components/ProjectCardLeakMeasures.tsx
@@ -37,10 +37,9 @@ export default function ProjectCardLeakMeasures({ measures }: Props) {
<div className="project-card-measure-number">
<Measure
className="spacer-right"
- measure={{
- metric: { key: 'new_bugs', type: 'SHORT_INT' },
- leak: measures['new_bugs']
- }}
+ metricKey="new_bugs"
+ metricType="SHORT_INT"
+ value={measures['new_bugs']}
/>
<Rating value={measures['new_reliability_rating']} />
</div>
@@ -56,10 +55,9 @@ export default function ProjectCardLeakMeasures({ measures }: Props) {
<div className="project-card-measure-number">
<Measure
className="spacer-right"
- measure={{
- metric: { key: 'new_vulnerabilities', type: 'SHORT_INT' },
- leak: measures['new_vulnerabilities']
- }}
+ metricKey="new_vulnerabilities"
+ metricType="SHORT_INT"
+ value={measures['new_vulnerabilities']}
/>
<Rating value={measures['new_security_rating']} />
</div>
@@ -75,10 +73,9 @@ export default function ProjectCardLeakMeasures({ measures }: Props) {
<div className="project-card-measure-number">
<Measure
className="spacer-right"
- measure={{
- metric: { key: 'new_code_smells', type: 'SHORT_INT' },
- leak: measures['new_code_smells']
- }}
+ metricKey="new_code_smells"
+ metricType="SHORT_INT"
+ value={measures['new_code_smells']}
/>
<Rating value={measures['new_maintainability_rating']} />
</div>
@@ -93,10 +90,9 @@ export default function ProjectCardLeakMeasures({ measures }: Props) {
<div className="project-card-measure-inner">
<div className="project-card-measure-number">
<Measure
- measure={{
- metric: { key: 'new_coverage', type: 'PERCENT' },
- leak: measures['new_coverage']
- }}
+ metricKey="new_coverage"
+ metricType="PERCENT"
+ value={measures['new_coverage']}
/>
</div>
<div className="project-card-measure-label">{translate('metric.coverage.name')}</div>
@@ -107,10 +103,9 @@ export default function ProjectCardLeakMeasures({ measures }: Props) {
<div className="project-card-measure-inner">
<div className="project-card-measure-number">
<Measure
- measure={{
- metric: { key: 'new_duplicated_lines_density', type: 'PERCENT' },
- leak: measures['new_duplicated_lines_density']
- }}
+ metricKey="new_duplicated_lines_density"
+ metricType="PERCENT"
+ value={measures['new_duplicated_lines_density']}
/>
</div>
<div className="project-card-measure-label">
@@ -122,12 +117,7 @@ export default function ProjectCardLeakMeasures({ measures }: Props) {
<div className="project-card-measure smaller-card project-card-ncloc" data-key="new_lines">
<div className="project-card-measure-inner">
<div className="project-card-measure-number">
- <Measure
- measure={{
- metric: { key: 'new_lines', type: 'SHORT_INT' },
- leak: measures['new_lines']
- }}
- />
+ <Measure metricKey="new_lines" metricType="SHORT_INT" value={measures['new_lines']} />
</div>
<div className="project-card-measure-label">{translate('metric.lines.name')}</div>
</div>
diff --git a/server/sonar-web/src/main/js/apps/projects/components/ProjectCardOverallMeasures.tsx b/server/sonar-web/src/main/js/apps/projects/components/ProjectCardOverallMeasures.tsx
index 63dba2d25f4..e11c8e5b80d 100644
--- a/server/sonar-web/src/main/js/apps/projects/components/ProjectCardOverallMeasures.tsx
+++ b/server/sonar-web/src/main/js/apps/projects/components/ProjectCardOverallMeasures.tsx
@@ -45,10 +45,9 @@ export default function ProjectCardOverallMeasures({ measures }: Props) {
<div className="project-card-measure-number">
<Measure
className="spacer-right"
- measure={{
- metric: { key: 'bugs', type: 'SHORT_INT' },
- value: measures['bugs']
- }}
+ metricKey="bugs"
+ metricType="SHORT_INT"
+ value={measures['bugs']}
/>
<Rating value={measures['reliability_rating']} />
</div>
@@ -64,10 +63,9 @@ export default function ProjectCardOverallMeasures({ measures }: Props) {
<div className="project-card-measure-number">
<Measure
className="spacer-right"
- measure={{
- metric: { key: 'vulnerabilities', type: 'SHORT_INT' },
- value: measures['vulnerabilities']
- }}
+ metricKey="vulnerabilities"
+ metricType="SHORT_INT"
+ value={measures['vulnerabilities']}
/>
<Rating value={measures['security_rating']} />
</div>
@@ -83,10 +81,9 @@ export default function ProjectCardOverallMeasures({ measures }: Props) {
<div className="project-card-measure-number">
<Measure
className="spacer-right"
- measure={{
- metric: { key: 'code_smells', type: 'SHORT_INT' },
- value: measures['code_smells']
- }}
+ metricKey="code_smells"
+ metricType="SHORT_INT"
+ value={measures['code_smells']}
/>
<Rating value={measures['sqale_rating']} />
</div>
@@ -105,12 +102,7 @@ export default function ProjectCardOverallMeasures({ measures }: Props) {
<CoverageRating value={measures['coverage']} />
</span>
)}
- <Measure
- measure={{
- metric: { key: 'coverage', type: 'PERCENT' },
- value: measures['coverage']
- }}
- />
+ <Measure metricKey="coverage" metricType="PERCENT" value={measures['coverage']} />
</div>
<div className="project-card-measure-label">{translate('metric.coverage.name')}</div>
</div>
@@ -125,10 +117,9 @@ export default function ProjectCardOverallMeasures({ measures }: Props) {
</span>
)}
<Measure
- measure={{
- metric: { key: 'duplicated_lines_density', type: 'PERCENT' },
- value: measures['duplicated_lines_density']
- }}
+ metricKey="duplicated_lines_density"
+ metricType="PERCENT"
+ value={measures['duplicated_lines_density']}
/>
</div>
<div className="project-card-measure-label">
@@ -141,12 +132,7 @@ export default function ProjectCardOverallMeasures({ measures }: Props) {
<div className="project-card-measure project-card-ncloc" data-key="ncloc">
<div className="project-card-measure-inner pull-right">
<div className="project-card-measure-number">
- <Measure
- measure={{
- metric: { key: 'ncloc', type: 'SHORT_INT' },
- value: measures['ncloc']
- }}
- />
+ <Measure metricKey="ncloc" metricType="SHORT_INT" value={measures['ncloc']} />
<span className="spacer-left">
<SizeRating value={Number(measures['ncloc'])} />
</span>
diff --git a/server/sonar-web/src/main/js/apps/projects/components/__tests__/__snapshots__/ProjectCardLeakMeasures-test.tsx.snap b/server/sonar-web/src/main/js/apps/projects/components/__tests__/__snapshots__/ProjectCardLeakMeasures-test.tsx.snap
index 0ccdace41b1..5dbdbd4a074 100644
--- a/server/sonar-web/src/main/js/apps/projects/components/__tests__/__snapshots__/ProjectCardLeakMeasures-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/projects/components/__tests__/__snapshots__/ProjectCardLeakMeasures-test.tsx.snap
@@ -16,15 +16,9 @@ exports[`should render correctly with all data 1`] = `
>
<Measure
className="spacer-right"
- measure={
- Object {
- "leak": "8",
- "metric": Object {
- "key": "new_bugs",
- "type": "SHORT_INT",
- },
- }
- }
+ metricKey="new_bugs"
+ metricType="SHORT_INT"
+ value="8"
/>
<Rating
value="1.0"
@@ -52,15 +46,9 @@ exports[`should render correctly with all data 1`] = `
>
<Measure
className="spacer-right"
- measure={
- Object {
- "leak": "2",
- "metric": Object {
- "key": "new_vulnerabilities",
- "type": "SHORT_INT",
- },
- }
- }
+ metricKey="new_vulnerabilities"
+ metricType="SHORT_INT"
+ value="2"
/>
<Rating
value="2.0"
@@ -88,15 +76,9 @@ exports[`should render correctly with all data 1`] = `
>
<Measure
className="spacer-right"
- measure={
- Object {
- "leak": "0",
- "metric": Object {
- "key": "new_code_smells",
- "type": "SHORT_INT",
- },
- }
- }
+ metricKey="new_code_smells"
+ metricType="SHORT_INT"
+ value="0"
/>
<Rating
value="1.0"
@@ -123,15 +105,9 @@ exports[`should render correctly with all data 1`] = `
className="project-card-measure-number"
>
<Measure
- measure={
- Object {
- "leak": "26.55",
- "metric": Object {
- "key": "new_coverage",
- "type": "PERCENT",
- },
- }
- }
+ metricKey="new_coverage"
+ metricType="PERCENT"
+ value="26.55"
/>
</div>
<div
@@ -152,15 +128,9 @@ exports[`should render correctly with all data 1`] = `
className="project-card-measure-number"
>
<Measure
- measure={
- Object {
- "leak": "0.55",
- "metric": Object {
- "key": "new_duplicated_lines_density",
- "type": "PERCENT",
- },
- }
- }
+ metricKey="new_duplicated_lines_density"
+ metricType="PERCENT"
+ value="0.55"
/>
</div>
<div
@@ -181,15 +151,9 @@ exports[`should render correctly with all data 1`] = `
className="project-card-measure-number"
>
<Measure
- measure={
- Object {
- "leak": "87",
- "metric": Object {
- "key": "new_lines",
- "type": "SHORT_INT",
- },
- }
- }
+ metricKey="new_lines"
+ metricType="SHORT_INT"
+ value="87"
/>
</div>
<div
@@ -218,15 +182,9 @@ exports[`should render no data style new coverage, new duplications and new line
>
<Measure
className="spacer-right"
- measure={
- Object {
- "leak": "8",
- "metric": Object {
- "key": "new_bugs",
- "type": "SHORT_INT",
- },
- }
- }
+ metricKey="new_bugs"
+ metricType="SHORT_INT"
+ value="8"
/>
<Rating
value="1.0"
@@ -254,15 +212,9 @@ exports[`should render no data style new coverage, new duplications and new line
>
<Measure
className="spacer-right"
- measure={
- Object {
- "leak": "2",
- "metric": Object {
- "key": "new_vulnerabilities",
- "type": "SHORT_INT",
- },
- }
- }
+ metricKey="new_vulnerabilities"
+ metricType="SHORT_INT"
+ value="2"
/>
<Rating
value="2.0"
@@ -290,15 +242,9 @@ exports[`should render no data style new coverage, new duplications and new line
>
<Measure
className="spacer-right"
- measure={
- Object {
- "leak": "0",
- "metric": Object {
- "key": "new_code_smells",
- "type": "SHORT_INT",
- },
- }
- }
+ metricKey="new_code_smells"
+ metricType="SHORT_INT"
+ value="0"
/>
<Rating
value="1.0"
@@ -325,15 +271,8 @@ exports[`should render no data style new coverage, new duplications and new line
className="project-card-measure-number"
>
<Measure
- measure={
- Object {
- "leak": undefined,
- "metric": Object {
- "key": "new_coverage",
- "type": "PERCENT",
- },
- }
- }
+ metricKey="new_coverage"
+ metricType="PERCENT"
/>
</div>
<div
@@ -354,15 +293,8 @@ exports[`should render no data style new coverage, new duplications and new line
className="project-card-measure-number"
>
<Measure
- measure={
- Object {
- "leak": undefined,
- "metric": Object {
- "key": "new_duplicated_lines_density",
- "type": "PERCENT",
- },
- }
- }
+ metricKey="new_duplicated_lines_density"
+ metricType="PERCENT"
/>
</div>
<div
@@ -383,15 +315,8 @@ exports[`should render no data style new coverage, new duplications and new line
className="project-card-measure-number"
>
<Measure
- measure={
- Object {
- "leak": undefined,
- "metric": Object {
- "key": "new_lines",
- "type": "SHORT_INT",
- },
- }
- }
+ metricKey="new_lines"
+ metricType="SHORT_INT"
/>
</div>
<div
diff --git a/server/sonar-web/src/main/js/apps/projects/components/__tests__/__snapshots__/ProjectCardOverallMeasures-test.tsx.snap b/server/sonar-web/src/main/js/apps/projects/components/__tests__/__snapshots__/ProjectCardOverallMeasures-test.tsx.snap
index 74ef1f08cfe..2c300ec6258 100644
--- a/server/sonar-web/src/main/js/apps/projects/components/__tests__/__snapshots__/ProjectCardOverallMeasures-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/projects/components/__tests__/__snapshots__/ProjectCardOverallMeasures-test.tsx.snap
@@ -12,15 +12,8 @@ exports[`should not render coverage 1`] = `
className="project-card-measure-number"
>
<Measure
- measure={
- Object {
- "metric": Object {
- "key": "coverage",
- "type": "PERCENT",
- },
- "value": undefined,
- }
- }
+ metricKey="coverage"
+ metricType="PERCENT"
/>
</div>
<div
@@ -44,15 +37,8 @@ exports[`should not render duplications 1`] = `
className="project-card-measure-number"
>
<Measure
- measure={
- Object {
- "metric": Object {
- "key": "duplicated_lines_density",
- "type": "PERCENT",
- },
- "value": undefined,
- }
- }
+ metricKey="duplicated_lines_density"
+ metricType="PERCENT"
/>
</div>
<div
@@ -80,15 +66,9 @@ exports[`should render correctly with all data 1`] = `
>
<Measure
className="spacer-right"
- measure={
- Object {
- "metric": Object {
- "key": "bugs",
- "type": "SHORT_INT",
- },
- "value": "17",
- }
- }
+ metricKey="bugs"
+ metricType="SHORT_INT"
+ value="17"
/>
<Rating
value="1.0"
@@ -116,15 +96,9 @@ exports[`should render correctly with all data 1`] = `
>
<Measure
className="spacer-right"
- measure={
- Object {
- "metric": Object {
- "key": "vulnerabilities",
- "type": "SHORT_INT",
- },
- "value": "0",
- }
- }
+ metricKey="vulnerabilities"
+ metricType="SHORT_INT"
+ value="0"
/>
<Rating
value="1.0"
@@ -152,15 +126,9 @@ exports[`should render correctly with all data 1`] = `
>
<Measure
className="spacer-right"
- measure={
- Object {
- "metric": Object {
- "key": "code_smells",
- "type": "SHORT_INT",
- },
- "value": "132",
- }
- }
+ metricKey="code_smells"
+ metricType="SHORT_INT"
+ value="132"
/>
<Rating
value="1.0"
@@ -194,15 +162,9 @@ exports[`should render correctly with all data 1`] = `
/>
</span>
<Measure
- measure={
- Object {
- "metric": Object {
- "key": "coverage",
- "type": "PERCENT",
- },
- "value": "88.3",
- }
- }
+ metricKey="coverage"
+ metricType="PERCENT"
+ value="88.3"
/>
</div>
<div
@@ -230,15 +192,9 @@ exports[`should render correctly with all data 1`] = `
/>
</span>
<Measure
- measure={
- Object {
- "metric": Object {
- "key": "duplicated_lines_density",
- "type": "PERCENT",
- },
- "value": "9.8",
- }
- }
+ metricKey="duplicated_lines_density"
+ metricType="PERCENT"
+ value="9.8"
/>
</div>
<div
@@ -259,15 +215,9 @@ exports[`should render correctly with all data 1`] = `
className="project-card-measure-number"
>
<Measure
- measure={
- Object {
- "metric": Object {
- "key": "ncloc",
- "type": "SHORT_INT",
- },
- "value": "2053",
- }
- }
+ metricKey="ncloc"
+ metricType="SHORT_INT"
+ value="2053"
/>
<span
className="spacer-left"
@@ -299,15 +249,9 @@ exports[`should render ncloc correctly 1`] = `
className="project-card-measure-number"
>
<Measure
- measure={
- Object {
- "metric": Object {
- "key": "ncloc",
- "type": "SHORT_INT",
- },
- "value": "16549887",
- }
- }
+ metricKey="ncloc"
+ metricType="SHORT_INT"
+ value="16549887"
/>
<span
className="spacer-left"
diff --git a/server/sonar-web/src/main/js/apps/projects/filters/TagsFilter.tsx b/server/sonar-web/src/main/js/apps/projects/filters/TagsFilter.tsx
index 091bd3c95b5..963333ba5c1 100644
--- a/server/sonar-web/src/main/js/apps/projects/filters/TagsFilter.tsx
+++ b/server/sonar-web/src/main/js/apps/projects/filters/TagsFilter.tsx
@@ -82,11 +82,14 @@ export default class TagsFilter extends React.PureComponent<Props, State> {
searchProjectTags({
q: search,
ps: size(this.props.facet || {}) + LIST_SIZE
- }).then(result => {
- if (this.mounted) {
- this.setState({ isLoading: false, tags: result.tags });
- }
- });
+ }).then(
+ result => {
+ if (this.mounted) {
+ this.setState({ isLoading: false, tags: result.tags });
+ }
+ },
+ () => {}
+ );
}
};
diff --git a/server/sonar-web/src/main/js/components/common/BubblePopup.tsx b/server/sonar-web/src/main/js/components/common/BubblePopup.tsx
index deb5f3d7882..18b7dbd6f95 100644
--- a/server/sonar-web/src/main/js/components/common/BubblePopup.tsx
+++ b/server/sonar-web/src/main/js/components/common/BubblePopup.tsx
@@ -20,10 +20,15 @@
import * as React from 'react';
import * as classNames from 'classnames';
+export interface BubblePopupPosition {
+ top: number;
+ right: number;
+}
+
interface Props {
customClass?: string;
children: React.ReactNode;
- position: { top: number; right: number };
+ position: BubblePopupPosition;
}
export default function BubblePopup(props: Props) {
diff --git a/server/sonar-web/src/main/js/components/common/MultiSelect.js b/server/sonar-web/src/main/js/components/common/MultiSelect.tsx
index 2921ab1ad76..b88ccd430cf 100644
--- a/server/sonar-web/src/main/js/components/common/MultiSelect.js
+++ b/server/sonar-web/src/main/js/components/common/MultiSelect.tsx
@@ -17,47 +17,46 @@
* 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 * as React from 'react';
import { difference } from 'lodash';
import MultiSelectOption from './MultiSelectOption';
import SearchBox from '../controls/SearchBox';
-import { translate } from '../../helpers/l10n';
-/*::
-type Props = {
- selectedElements: Array<string>,
- elements: Array<string>,
- listSize: number,
- onSearch: string => void,
- onSelect: string => void,
- onUnselect: string => void,
- validateSearchInput: string => string,
- placeholder: string
-};
-*/
+interface Props {
+ selectedElements: Array<string>;
+ elements: Array<string>;
+ listSize?: number;
+ onSearch: (query: string) => void;
+ onSelect: (item: string) => void;
+ onUnselect: (item: string) => void;
+ validateSearchInput?: (value: string) => string;
+ placeholder: string;
+}
+
+interface State {
+ query: string;
+ selectedElements: Array<string>;
+ unselectedElements: Array<string>;
+ activeIdx: number;
+}
-/*::
-type State = {
- query: string,
- selectedElements: Array<string>,
- unselectedElements: Array<string>,
- activeIdx: number
-};
-*/
+interface DefaultProps {
+ listSize: number;
+ validateSearchInput: (value: string) => string;
+}
+
+type PropsWithDefault = Props & DefaultProps;
-export default class MultiSelect extends React.PureComponent {
- /*:: container: HTMLElement; */
- /*:: searchInput: HTMLInputElement; */
- /*:: props: Props; */
- /*:: state: State; */
+export default class MultiSelect extends React.PureComponent<Props, State> {
+ container: HTMLDivElement | null;
+ searchInput: HTMLInputElement | null;
- static defaultProps = {
+ static defaultProps: DefaultProps = {
listSize: 10,
- validateSearchInput: (value /*: string */) => value
+ validateSearchInput: (value: string) => value
};
- constructor(props /*: Props */) {
+ constructor(props: Props) {
super(props);
this.state = {
query: '',
@@ -69,13 +68,13 @@ export default class MultiSelect extends React.PureComponent {
componentDidMount() {
this.updateSelectedElements(this.props);
- this.updateUnselectedElements(this.props);
+ this.updateUnselectedElements(this.props as PropsWithDefault);
if (this.container) {
this.container.addEventListener('keydown', this.handleKeyboard, true);
}
}
- componentWillReceiveProps(nextProps /*: Props */) {
+ componentWillReceiveProps(nextProps: PropsWithDefault) {
if (
this.props.elements !== nextProps.elements ||
this.props.selectedElements !== nextProps.selectedElements
@@ -91,14 +90,18 @@ export default class MultiSelect extends React.PureComponent {
}
componentDidUpdate() {
- this.searchInput && this.searchInput.focus();
+ if (this.searchInput) {
+ this.searchInput.focus();
+ }
}
componentWillUnmount() {
- this.container.removeEventListener('keydown', this.handleKeyboard);
+ if (this.container) {
+ this.container.removeEventListener('keydown', this.handleKeyboard);
+ }
}
- handleSelectChange = (item /*: string */, selected /*: boolean */) => {
+ handleSelectChange = (item: string, selected: boolean) => {
if (selected) {
this.onSelectItem(item);
} else {
@@ -106,17 +109,17 @@ export default class MultiSelect extends React.PureComponent {
}
};
- handleSearchChange = (value /*: string */) => {
- this.onSearchQuery(this.props.validateSearchInput(value));
+ handleSearchChange = (value: string) => {
+ this.onSearchQuery((this.props as PropsWithDefault).validateSearchInput(value));
};
- handleElementHover = (element /*: string */) => {
+ handleElementHover = (element: string) => {
this.setState((prevState, props) => {
return { activeIdx: this.getAllElements(props, prevState).indexOf(element) };
});
};
- handleKeyboard = (evt /*: KeyboardEvent */) => {
+ handleKeyboard = (evt: KeyboardEvent) => {
switch (evt.keyCode) {
case 40: // down
this.setState(this.selectNextElement);
@@ -140,28 +143,25 @@ export default class MultiSelect extends React.PureComponent {
}
};
- onSearchQuery(query /*: string */) {
+ onSearchQuery = (query: string) => {
this.setState({ query, activeIdx: 0 });
this.props.onSearch(query);
- }
+ };
- onSelectItem(item /*: string */) {
+ onSelectItem = (item: string) => {
if (this.isNewElement(item, this.props)) {
this.onSearchQuery('');
}
this.props.onSelect(item);
- }
+ };
- onUnselectItem(item /*: string */) {
- this.props.onUnselect(item);
- }
+ onUnselectItem = (item: string) => this.props.onUnselect(item);
- isNewElement(elem /*: string */, { selectedElements, elements } /*: Props */) {
- return elem && selectedElements.indexOf(elem) === -1 && elements.indexOf(elem) === -1;
- }
+ isNewElement = (elem: string, { selectedElements, elements }: Props) =>
+ elem && selectedElements.indexOf(elem) === -1 && elements.indexOf(elem) === -1;
- updateSelectedElements(props /*: Props */) {
- this.setState((state /*: State */) => {
+ updateSelectedElements = (props: Props) => {
+ this.setState((state: State) => {
if (state.query) {
return {
selectedElements: [...props.selectedElements.filter(elem => elem.includes(state.query))]
@@ -170,10 +170,10 @@ export default class MultiSelect extends React.PureComponent {
return { selectedElements: [...props.selectedElements] };
}
});
- }
+ };
- updateUnselectedElements(props /*: Props */) {
- this.setState((state /*: State */) => {
+ updateUnselectedElements = (props: PropsWithDefault) => {
+ this.setState((state: State) => {
if (props.listSize < state.selectedElements.length) {
return { unselectedElements: [] };
} else {
@@ -185,21 +185,19 @@ export default class MultiSelect extends React.PureComponent {
};
}
});
- }
+ };
- getAllElements(props /*: Props */, state /*: State */) {
+ getAllElements = (props: Props, state: State) => {
if (this.isNewElement(state.query, props)) {
return [...state.selectedElements, ...state.unselectedElements, state.query];
} else {
return [...state.selectedElements, ...state.unselectedElements];
}
- }
+ };
- setElementActive(idx /*: number */) {
- this.setState({ activeIdx: idx });
- }
+ setElementActive = (idx: number) => this.setState({ activeIdx: idx });
- selectNextElement = (state /*: State */, props /*: Props */) => {
+ selectNextElement = (state: State, props: Props) => {
const { activeIdx } = state;
const allElements = this.getAllElements(props, state);
if (activeIdx < 0 || activeIdx >= allElements.length - 1) {
@@ -209,7 +207,7 @@ export default class MultiSelect extends React.PureComponent {
}
};
- selectPreviousElement = (state /*: State */, props /*: Props */) => {
+ selectPreviousElement = (state: State, props: Props) => {
const { activeIdx } = state;
const allElements = this.getAllElements(props, state);
if (activeIdx <= 0) {
@@ -220,13 +218,13 @@ export default class MultiSelect extends React.PureComponent {
}
};
- toggleSelect(item /*: string */) {
+ toggleSelect = (item: string) => {
if (this.props.selectedElements.indexOf(item) === -1) {
this.onSelectItem(item);
} else {
this.onUnselectItem(item);
}
- }
+ };
render() {
const { query, activeIdx, selectedElements, unselectedElements } = this.state;
diff --git a/server/sonar-web/src/main/js/components/common/MultiSelectOption.js b/server/sonar-web/src/main/js/components/common/MultiSelectOption.tsx
index ad144f5cd9d..89429426d7e 100644
--- a/server/sonar-web/src/main/js/components/common/MultiSelectOption.js
+++ b/server/sonar-web/src/main/js/components/common/MultiSelectOption.tsx
@@ -17,40 +17,27 @@
* 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 classNames from 'classnames';
+import * as React from 'react';
+import * as classNames from 'classnames';
-/*::
-type Props = {
- element: string,
- selected: boolean,
- custom: boolean,
- active: boolean,
- onSelectChange: (string, boolean) => void,
- onHover: string => void
-};
-*/
-
-export default class MultiSelectOption extends React.PureComponent {
- /*:: props: Props; */
-
- static defaultProps = {
- selected: false,
- custom: false,
- active: false
- };
+interface Props {
+ element: string;
+ selected?: boolean;
+ custom?: boolean;
+ active?: boolean;
+ onSelectChange: (elem: string, selected: boolean) => void;
+ onHover: (elem: string) => void;
+}
- handleSelect = (evt /*: SyntheticInputEvent */) => {
+export default class MultiSelectOption extends React.PureComponent<Props> {
+ handleSelect = (evt: React.SyntheticEvent<HTMLAnchorElement>) => {
evt.stopPropagation();
evt.preventDefault();
- evt.target.blur();
+ evt.currentTarget.blur();
this.props.onSelectChange(this.props.element, !this.props.selected);
};
- handleHover = () => {
- this.props.onHover(this.props.element);
- };
+ handleHover = () => this.props.onHover(this.props.element);
render() {
const className = classNames('icon-checkbox', {
diff --git a/server/sonar-web/src/main/js/components/common/__tests__/MultiSelect-test.js b/server/sonar-web/src/main/js/components/common/__tests__/MultiSelect-test.tsx
index c843a7952bb..13bb1651866 100644
--- a/server/sonar-web/src/main/js/components/common/__tests__/MultiSelect-test.js
+++ b/server/sonar-web/src/main/js/components/common/__tests__/MultiSelect-test.tsx
@@ -17,8 +17,8 @@
* 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 { shallow, mount } from 'enzyme';
-import React from 'react';
import MultiSelect from '../MultiSelect';
const props = {
diff --git a/server/sonar-web/src/main/js/components/common/__tests__/MultiSelectOption-test.js b/server/sonar-web/src/main/js/components/common/__tests__/MultiSelectOption-test.tsx
index a15475bc149..5b72d18b21e 100644
--- a/server/sonar-web/src/main/js/components/common/__tests__/MultiSelectOption-test.js
+++ b/server/sonar-web/src/main/js/components/common/__tests__/MultiSelectOption-test.tsx
@@ -17,15 +17,12 @@
* 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 { shallow } from 'enzyme';
-import React from 'react';
import MultiSelectOption from '../MultiSelectOption';
const props = {
element: 'mytag',
- selected: false,
- custom: false,
- active: false,
onSelectChange: () => {},
onHover: () => {}
};
diff --git a/server/sonar-web/src/main/js/components/common/__tests__/__snapshots__/MultiSelect-test.js.snap b/server/sonar-web/src/main/js/components/common/__tests__/__snapshots__/MultiSelect-test.tsx.snap
index 5af710f8bb1..32dac980bbe 100644
--- a/server/sonar-web/src/main/js/components/common/__tests__/__snapshots__/MultiSelect-test.js.snap
+++ b/server/sonar-web/src/main/js/components/common/__tests__/__snapshots__/MultiSelect-test.tsx.snap
@@ -19,7 +19,6 @@ exports[`should render multiselect with selected elements 1`] = `
>
<MultiSelectOption
active={true}
- custom={false}
element="bar"
key="bar"
onHover={[Function]}
@@ -49,7 +48,6 @@ exports[`should render multiselect with selected elements 2`] = `
>
<MultiSelectOption
active={true}
- custom={false}
element="bar"
key="bar"
onHover={[Function]}
@@ -58,21 +56,17 @@ exports[`should render multiselect with selected elements 2`] = `
/>
<MultiSelectOption
active={false}
- custom={false}
element="foo"
key="foo"
onHover={[Function]}
onSelectChange={[Function]}
- selected={false}
/>
<MultiSelectOption
active={false}
- custom={false}
element="baz"
key="baz"
onHover={[Function]}
onSelectChange={[Function]}
- selected={false}
/>
</ul>
</div>
@@ -97,7 +91,6 @@ exports[`should render multiselect with selected elements 3`] = `
>
<MultiSelectOption
active={false}
- custom={false}
element="bar"
key="bar"
onHover={[Function]}
@@ -106,21 +99,17 @@ exports[`should render multiselect with selected elements 3`] = `
/>
<MultiSelectOption
active={false}
- custom={false}
element="foo"
key="foo"
onHover={[Function]}
onSelectChange={[Function]}
- selected={false}
/>
<MultiSelectOption
active={true}
- custom={false}
element="baz"
key="baz"
onHover={[Function]}
onSelectChange={[Function]}
- selected={false}
/>
</ul>
</div>
@@ -145,7 +134,6 @@ exports[`should render multiselect with selected elements 4`] = `
>
<MultiSelectOption
active={false}
- custom={false}
element="bar"
key="bar"
onHover={[Function]}
@@ -154,21 +142,17 @@ exports[`should render multiselect with selected elements 4`] = `
/>
<MultiSelectOption
active={false}
- custom={false}
element="foo"
key="foo"
onHover={[Function]}
onSelectChange={[Function]}
- selected={false}
/>
<MultiSelectOption
active={true}
- custom={false}
element="baz"
key="baz"
onHover={[Function]}
onSelectChange={[Function]}
- selected={false}
/>
<MultiSelectOption
active={false}
@@ -177,7 +161,6 @@ exports[`should render multiselect with selected elements 4`] = `
key="test"
onHover={[Function]}
onSelectChange={[Function]}
- selected={false}
/>
</ul>
</div>
diff --git a/server/sonar-web/src/main/js/components/common/__tests__/__snapshots__/MultiSelectOption-test.js.snap b/server/sonar-web/src/main/js/components/common/__tests__/__snapshots__/MultiSelectOption-test.tsx.snap
index b7b9f2a61c0..b7b9f2a61c0 100644
--- a/server/sonar-web/src/main/js/components/common/__tests__/__snapshots__/MultiSelectOption-test.js.snap
+++ b/server/sonar-web/src/main/js/components/common/__tests__/__snapshots__/MultiSelectOption-test.tsx.snap
diff --git a/server/sonar-web/src/main/js/components/issue/popups/SetIssueTagsPopup.js b/server/sonar-web/src/main/js/components/issue/popups/SetIssueTagsPopup.js
index 30c93818fff..c334412d5c0 100644
--- a/server/sonar-web/src/main/js/components/issue/popups/SetIssueTagsPopup.js
+++ b/server/sonar-web/src/main/js/components/issue/popups/SetIssueTagsPopup.js
@@ -77,7 +77,6 @@ export default class SetIssueTagsPopup extends React.PureComponent {
render() {
return (
- // $FlowFixMe `this.props.popupPosition` is passed from `BabelPopupHelper`
<TagsSelector
position={this.props.popupPosition}
tags={this.state.searchResult}
diff --git a/server/sonar-web/src/main/js/components/measure/Measure.tsx b/server/sonar-web/src/main/js/components/measure/Measure.tsx
index 200035f8016..ae12c4c480f 100644
--- a/server/sonar-web/src/main/js/components/measure/Measure.tsx
+++ b/server/sonar-web/src/main/js/components/measure/Measure.tsx
@@ -21,39 +21,32 @@ import * as React from 'react';
import Rating from '../ui/Rating';
import Level from '../ui/Level';
import Tooltips from '../controls/Tooltip';
-import { formatMeasure, isDiffMetric, MeasureEnhanced } from '../../helpers/measures';
-import { formatLeak, getRatingTooltip } from './utils';
+import { formatMeasure } from '../../helpers/measures';
+import { getRatingTooltip } from './utils';
interface Props {
className?: string;
decimals?: number | null;
- measure?: MeasureEnhanced;
+ value?: string;
+ metricKey: string;
+ metricType: string;
}
-export default function Measure({ className, decimals, measure }: Props) {
- if (measure === undefined) {
- return <span>{'–'}</span>;
- }
-
- const { metric } = measure;
- const value = isDiffMetric(metric.key) ? measure.leak : measure.value;
-
+export default function Measure({ className, decimals, metricKey, metricType, value }: Props) {
if (value === undefined) {
return <span>{'–'}</span>;
}
- if (metric.type === 'LEVEL') {
+ if (metricType === 'LEVEL') {
return <Level className={className} level={value} />;
}
- if (metric.type !== 'RATING') {
- const formattedValue = isDiffMetric(metric.key)
- ? formatLeak(measure.leak, metric.key, metric.type, { decimals })
- : formatMeasure(measure.value, metric.type, { decimals });
+ if (metricType !== 'RATING') {
+ const formattedValue = formatMeasure(value, metricType, { decimals });
return <span className={className}>{formattedValue != null ? formattedValue : '–'}</span>;
}
- const tooltip = getRatingTooltip(metric.key, Number(value));
+ const tooltip = getRatingTooltip(metricKey, Number(value));
const rating = <Rating value={value} />;
if (tooltip) {
return (
diff --git a/server/sonar-web/src/main/js/components/measure/__tests__/Measure-test.tsx b/server/sonar-web/src/main/js/components/measure/__tests__/Measure-test.tsx
index a62f16c513d..84aaf15fdb3 100644
--- a/server/sonar-web/src/main/js/components/measure/__tests__/Measure-test.tsx
+++ b/server/sonar-web/src/main/js/components/measure/__tests__/Measure-test.tsx
@@ -17,55 +17,46 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-/* eslint-disable import/first */
+import * as React from 'react';
+import { shallow } from 'enzyme';
+import Measure from '../Measure';
+
jest.mock('../../../helpers/measures', () => {
const measures = require.requireActual('../../../helpers/measures');
measures.getRatingTooltip = jest.fn(() => 'tooltip');
return measures;
});
-import * as React from 'react';
-import { shallow } from 'enzyme';
-import Measure from '../Measure';
-
it('renders trivial measure', () => {
- const measure = { metric: { key: 'coverage', name: 'Coverage', type: 'PERCENT' }, value: '73.0' };
- expect(shallow(<Measure measure={measure} />)).toMatchSnapshot();
+ expect(
+ shallow(<Measure metricKey="coverage" metricType="PERCENT" value="73.0" />)
+ ).toMatchSnapshot();
});
it('renders leak measure', () => {
- const measure = {
- metric: { key: 'new_coverage', name: 'Coverage on New Code', type: 'PERCENT' },
- leak: '36.0'
- };
- expect(shallow(<Measure measure={measure} />)).toMatchSnapshot();
+ expect(
+ shallow(<Measure metricKey="new_coverage" metricType="PERCENT" value="36.0" />)
+ ).toMatchSnapshot();
});
it('renders LEVEL', () => {
- const measure = {
- metric: { key: 'quality_gate_status', name: 'Quality Gate', type: 'LEVEL' },
- value: 'ERROR'
- };
- expect(shallow(<Measure measure={measure} />)).toMatchSnapshot();
+ expect(
+ shallow(<Measure metricKey="quality_gate_status" metricType="LEVEL" value="ERROR" />)
+ ).toMatchSnapshot();
});
it('renders known RATING', () => {
- const measure = {
- metric: { key: 'sqale_rating', name: 'Maintainability Rating', type: 'RATING' },
- value: '3'
- };
- expect(shallow(<Measure measure={measure} />)).toMatchSnapshot();
+ expect(
+ shallow(<Measure metricKey="sqale_rating" metricType="RATING" value="3" />)
+ ).toMatchSnapshot();
});
it('renders unknown RATING', () => {
- const measure = {
- metric: { key: 'foo_rating', name: 'Foo Rating', type: 'RATING' },
- value: '4'
- };
- expect(shallow(<Measure measure={measure} />)).toMatchSnapshot();
+ expect(
+ shallow(<Measure metricKey="foo_rating" metricType="RATING" value="4" />)
+ ).toMatchSnapshot();
});
it('renders undefined measure', () => {
- const measure = { metric: { key: 'foo', name: 'Foo', type: 'PERCENT' } };
- expect(shallow(<Measure measure={measure} />)).toMatchSnapshot();
+ expect(shallow(<Measure metricKey="foo" metricType="PERCENT" />)).toMatchSnapshot();
});
diff --git a/server/sonar-web/src/main/js/components/measure/utils.ts b/server/sonar-web/src/main/js/components/measure/utils.ts
index 8e932892152..626c65f552f 100644
--- a/server/sonar-web/src/main/js/components/measure/utils.ts
+++ b/server/sonar-web/src/main/js/components/measure/utils.ts
@@ -18,8 +18,6 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import {
- formatMeasure,
- formatMeasureVariation,
getRatingTooltip as nextGetRatingTooltip,
isDiffMetric,
Measure,
@@ -40,19 +38,6 @@ export function enhanceMeasure(
};
}
-export function formatLeak(
- value: string | undefined,
- metricKey: string,
- metricType: string,
- options: any
-): string {
- if (isDiffMetric(metricKey)) {
- return formatMeasure(value, metricType, options);
- } else {
- return formatMeasureVariation(value, metricType, options);
- }
-}
-
export function getLeakValue(measure: Measure | undefined): string | undefined {
if (!measure || !measure.periods) {
return undefined;
diff --git a/server/sonar-web/src/main/js/components/preview-graph/PreviewGraph.d.ts b/server/sonar-web/src/main/js/components/preview-graph/PreviewGraph.d.ts
new file mode 100644
index 00000000000..744eed0493d
--- /dev/null
+++ b/server/sonar-web/src/main/js/components/preview-graph/PreviewGraph.d.ts
@@ -0,0 +1,32 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 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 { History } from '../../api/time-machine';
+import { Metric } from '../../app/types';
+
+interface Props {
+ branch?: string;
+ history?: History;
+ metrics: Metric[];
+ project: string;
+ renderWhenEmpty?: () => void;
+}
+
+export default class PreviewGraph extends React.Component<Props> {}
diff --git a/server/sonar-web/src/main/js/components/shared/drilldown-link.js b/server/sonar-web/src/main/js/components/shared/DrilldownLink.tsx
index cdff767a2d9..1065e91e9ef 100644
--- a/server/sonar-web/src/main/js/components/shared/drilldown-link.js
+++ b/server/sonar-web/src/main/js/components/shared/DrilldownLink.tsx
@@ -17,8 +17,7 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-import React from 'react';
-import PropTypes from 'prop-types';
+import * as React from 'react';
import { Link } from 'react-router';
import { getComponentDrilldownUrl, getComponentIssuesUrl } from '../../helpers/urls';
@@ -47,21 +46,22 @@ const ISSUE_MEASURES = [
'new_vulnerabilities'
];
-export class DrilldownLink extends React.PureComponent {
- static propTypes = {
- branch: PropTypes.string,
- children: PropTypes.oneOfType([PropTypes.node, PropTypes.arrayOf(PropTypes.node)]),
- className: PropTypes.string,
- component: PropTypes.string.isRequired,
- metric: PropTypes.string.isRequired,
- sinceLeakPeriod: PropTypes.bool
- };
+interface Props {
+ branch?: string;
+ children?: React.ReactNode;
+ className?: string;
+ component: string;
+ metric: string;
+ sinceLeakPeriod?: boolean;
+}
+
+export default class DrilldownLink extends React.PureComponent<Props> {
isIssueMeasure = () => {
return ISSUE_MEASURES.indexOf(this.props.metric) !== -1;
};
propsToIssueParams = () => {
- const params = {};
+ const params: { [key: string]: string | boolean } = {};
if (this.props.sinceLeakPeriod) {
params.sinceLeakPeriod = true;
diff --git a/server/sonar-web/src/main/js/components/tags/TagsSelector.js b/server/sonar-web/src/main/js/components/tags/TagsSelector.tsx
index c257c31a5ed..f9ed202989c 100644
--- a/server/sonar-web/src/main/js/components/tags/TagsSelector.js
+++ b/server/sonar-web/src/main/js/components/tags/TagsSelector.tsx
@@ -17,26 +17,23 @@
* 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 BubblePopup from '../common/BubblePopup';
+import * as React from 'react';
+import BubblePopup, { BubblePopupPosition } from '../common/BubblePopup';
import MultiSelect from '../common/MultiSelect';
import { translate } from '../../helpers/l10n';
import './TagsList.css';
-/*::
-type Props = {
- position: {},
- tags: Array<string>,
- selectedTags: Array<string>,
- listSize: number,
- onSearch: string => void,
- onSelect: string => void,
- onUnselect: string => void
-};
-*/
+interface Props {
+ position: BubblePopupPosition;
+ tags: string[];
+ selectedTags: string[];
+ listSize: number;
+ onSearch: (query: string) => void;
+ onSelect: (item: string) => void;
+ onUnselect: (item: string) => void;
+}
-export default function TagsSelector(props /*: Props */) {
+export default function TagsSelector(props: Props) {
return (
<BubblePopup
position={props.position}
@@ -55,7 +52,7 @@ export default function TagsSelector(props /*: Props */) {
);
}
-export function validateTag(value /*: string */) {
+export function validateTag(value: string) {
// Allow only a-z, 0-9, '+', '-', '#', '.'
return value.toLowerCase().replace(/[^a-z0-9\+\-#.]/gi, '');
}
diff --git a/server/sonar-web/src/main/js/components/tags/__tests__/TagsSelector-test.js b/server/sonar-web/src/main/js/components/tags/__tests__/TagsSelector-test.tsx
index 98186daca4a..1b5169a2940 100644
--- a/server/sonar-web/src/main/js/components/tags/__tests__/TagsSelector-test.js
+++ b/server/sonar-web/src/main/js/components/tags/__tests__/TagsSelector-test.tsx
@@ -17,12 +17,13 @@
* 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 { shallow } from 'enzyme';
-import React from 'react';
import TagsSelector, { validateTag } from '../TagsSelector';
const props = {
- position: { left: 0, top: 0 },
+ position: { right: 0, top: 0 },
+ listSize: 10,
tags: ['foo', 'bar', 'baz'],
selectedTags: ['bar'],
onSearch: () => {},
diff --git a/server/sonar-web/src/main/js/components/tags/__tests__/__snapshots__/TagsSelector-test.js.snap b/server/sonar-web/src/main/js/components/tags/__tests__/__snapshots__/TagsSelector-test.tsx.snap
index e2d57569b31..c2d4623b8c8 100644
--- a/server/sonar-web/src/main/js/components/tags/__tests__/__snapshots__/TagsSelector-test.js.snap
+++ b/server/sonar-web/src/main/js/components/tags/__tests__/__snapshots__/TagsSelector-test.tsx.snap
@@ -5,7 +5,7 @@ exports[`should render with selected tags 1`] = `
customClass="bubble-popup-bottom-right bubble-popup-menu abs-width-300"
position={
Object {
- "left": 0,
+ "right": 0,
"top": 0,
}
}
@@ -38,7 +38,7 @@ exports[`should render without tags at all 1`] = `
customClass="bubble-popup-bottom-right bubble-popup-menu abs-width-300"
position={
Object {
- "left": 0,
+ "right": 0,
"top": 0,
}
}
diff --git a/server/sonar-web/src/main/js/helpers/__tests__/measures-test.ts b/server/sonar-web/src/main/js/helpers/__tests__/measures-test.ts
index 68ae35138a7..6cf02992461 100644
--- a/server/sonar-web/src/main/js/helpers/__tests__/measures-test.ts
+++ b/server/sonar-web/src/main/js/helpers/__tests__/measures-test.ts
@@ -18,7 +18,7 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import { resetBundle } from '../l10n';
-import { formatMeasure, formatMeasureVariation } from '../measures';
+import { formatMeasure } from '../measures';
const HOURS_IN_DAY = 8;
const ONE_MINUTE = 1;
@@ -170,92 +170,3 @@ describe('#formatMeasure()', () => {
expect(formatMeasure(undefined, 'INT')).toBe('');
});
});
-
-describe('#formatMeasureVariation()', () => {
- it('should format INT', () => {
- expect(formatMeasureVariation(0, 'INT')).toBe('+0');
- expect(formatMeasureVariation(1, 'INT')).toBe('+1');
- expect(formatMeasureVariation(-1, 'INT')).toBe('-1');
- expect(formatMeasureVariation(1529, 'INT')).toBe('+1,529');
- expect(formatMeasureVariation(-1529, 'INT')).toBe('-1,529');
- });
-
- it('should format SHORT_INT', () => {
- expect(formatMeasureVariation(0, 'SHORT_INT')).toBe('+0');
- expect(formatMeasureVariation(1, 'SHORT_INT')).toBe('+1');
- expect(formatMeasureVariation(-1, 'SHORT_INT')).toBe('-1');
- expect(formatMeasureVariation(1529, 'SHORT_INT')).toBe('+1.5k');
- expect(formatMeasureVariation(-1529, 'SHORT_INT')).toBe('-1.5k');
- expect(formatMeasureVariation(10678, 'SHORT_INT')).toBe('+11k');
- expect(formatMeasureVariation(-10678, 'SHORT_INT')).toBe('-11k');
- });
-
- it('should format FLOAT', () => {
- expect(formatMeasureVariation(0.0, 'FLOAT')).toBe('+0.0');
- expect(formatMeasureVariation(1.0, 'FLOAT')).toBe('+1.0');
- expect(formatMeasureVariation(-1.0, 'FLOAT')).toBe('-1.0');
- expect(formatMeasureVariation(50.89, 'FLOAT')).toBe('+50.89');
- expect(formatMeasureVariation(-50.89, 'FLOAT')).toBe('-50.89');
- });
-
- it('should respect FLOAT precision', () => {
- expect(formatMeasureVariation(0.1, 'FLOAT')).toBe('+0.1');
- expect(formatMeasureVariation(0.12, 'FLOAT')).toBe('+0.12');
- expect(formatMeasureVariation(0.12345, 'FLOAT')).toBe('+0.12345');
- expect(formatMeasureVariation(0.123456, 'FLOAT')).toBe('+0.12346');
- });
-
- it('should format PERCENT', () => {
- expect(formatMeasureVariation(0.0, 'PERCENT')).toBe('+0.0%');
- expect(formatMeasureVariation(1.0, 'PERCENT')).toBe('+1.0%');
- expect(formatMeasureVariation(-1.0, 'PERCENT')).toBe('-1.0%');
- expect(formatMeasureVariation(50.89, 'PERCENT')).toBe('+50.9%');
- expect(formatMeasureVariation(-50.89, 'PERCENT')).toBe('-50.9%');
- });
-
- it('should format WORK_DUR', () => {
- expect(formatMeasureVariation(0, 'WORK_DUR')).toBe('+0');
- expect(formatMeasureVariation(5 * ONE_DAY, 'WORK_DUR')).toBe('+5d');
- expect(formatMeasureVariation(2 * ONE_HOUR, 'WORK_DUR')).toBe('+2h');
- expect(formatMeasureVariation(ONE_MINUTE, 'WORK_DUR')).toBe('+1min');
- expect(formatMeasureVariation(-5 * ONE_DAY, 'WORK_DUR')).toBe('-5d');
- expect(formatMeasureVariation(-2 * ONE_HOUR, 'WORK_DUR')).toBe('-2h');
- expect(formatMeasureVariation(-1 * ONE_MINUTE, 'WORK_DUR')).toBe('-1min');
- });
-
- it('should format SHORT_WORK_DUR', () => {
- expect(formatMeasureVariation(0, 'SHORT_WORK_DUR')).toBe('+0');
- expect(formatMeasureVariation(5 * ONE_DAY, 'SHORT_WORK_DUR')).toBe('+5d');
- expect(formatMeasureVariation(2 * ONE_HOUR, 'SHORT_WORK_DUR')).toBe('+2h');
- expect(formatMeasureVariation(ONE_MINUTE, 'SHORT_WORK_DUR')).toBe('+1min');
- expect(formatMeasureVariation(30 * ONE_MINUTE, 'SHORT_WORK_DUR')).toBe('+30min');
- expect(formatMeasureVariation(58 * ONE_MINUTE, 'SHORT_WORK_DUR')).toBe('+1h');
- expect(formatMeasureVariation(5 * ONE_DAY + 2 * ONE_HOUR, 'SHORT_WORK_DUR')).toBe('+5d');
- expect(formatMeasureVariation(2 * ONE_HOUR + ONE_MINUTE, 'SHORT_WORK_DUR')).toBe('+2h');
- expect(formatMeasureVariation(ONE_HOUR + 55 * ONE_MINUTE, 'SHORT_WORK_DUR')).toBe('+2h');
- expect(formatMeasureVariation(3 * ONE_DAY + 6 * ONE_HOUR, 'SHORT_WORK_DUR')).toBe('+4d');
- expect(formatMeasureVariation(7 * ONE_HOUR + 59 * ONE_MINUTE, 'SHORT_WORK_DUR')).toBe('+1d');
- expect(formatMeasureVariation(5 * ONE_DAY + 2 * ONE_HOUR + ONE_MINUTE, 'SHORT_WORK_DUR')).toBe(
- '+5d'
- );
- expect(formatMeasureVariation(15 * ONE_DAY + 2 * ONE_HOUR + ONE_MINUTE, 'SHORT_WORK_DUR')).toBe(
- '+15d'
- );
- expect(formatMeasureVariation(7 * ONE_MINUTE, 'SHORT_WORK_DUR')).toBe('+7min');
- expect(formatMeasureVariation(-5 * ONE_DAY, 'SHORT_WORK_DUR')).toBe('-5d');
- expect(formatMeasureVariation(-2 * ONE_HOUR, 'SHORT_WORK_DUR')).toBe('-2h');
- expect(formatMeasureVariation(-1 * ONE_MINUTE, 'SHORT_WORK_DUR')).toBe('-1min');
-
- expect(formatMeasureVariation(1529 * ONE_DAY, 'SHORT_WORK_DUR')).toBe('+1.5kd');
- expect(formatMeasureVariation(1234567 * ONE_DAY, 'SHORT_WORK_DUR')).toBe('+1Md');
- expect(formatMeasureVariation(1234567 * ONE_DAY + 2 * ONE_HOUR, 'SHORT_WORK_DUR')).toBe('+1Md');
- });
-
- it('should not format unknown type', () => {
- expect(formatMeasureVariation('random value', 'RANDOM_TYPE')).toBe('random value');
- });
-
- it('should not fail with undefined', () => {
- expect(formatMeasureVariation(undefined, 'INT')).toBe('');
- });
-});
diff --git a/server/sonar-web/src/main/js/helpers/measures.ts b/server/sonar-web/src/main/js/helpers/measures.ts
index edb05d8ce85..b6354557ad1 100644
--- a/server/sonar-web/src/main/js/helpers/measures.ts
+++ b/server/sonar-web/src/main/js/helpers/measures.ts
@@ -55,16 +55,6 @@ export function formatMeasure(
return useFormatter(value, formatter, options);
}
-/** Format a measure variation for a given type */
-export function formatMeasureVariation(
- value: string | number | undefined,
- type: string,
- options?: any
-): string {
- const formatter = getVariationFormatter(type);
- return useFormatter(value, formatter, options);
-}
-
/** Return a localized metric name */
export function localizeMetric(metricKey: string): string {
return translate('metric', metricKey, 'name');
@@ -91,7 +81,10 @@ export function enhanceMeasuresWithMetrics(
}
/** Get period value of a measure */
-export function getPeriodValue(measure: Measure, periodIndex: number): string | undefined {
+export function getPeriodValue(
+ measure: Measure | MeasureEnhanced,
+ periodIndex: number
+): string | undefined {
const { periods } = measure;
const period = periods && periods.find(period => period.index === periodIndex);
return period ? period.value : undefined;
@@ -125,21 +118,6 @@ function getFormatter(type: string): Formatter {
return FORMATTERS[type] || noFormatter;
}
-function getVariationFormatter(type: string): Formatter {
- const FORMATTERS: { [type: string]: Formatter } = {
- INT: intVariationFormatter,
- SHORT_INT: shortIntVariationFormatter,
- FLOAT: floatVariationFormatter,
- PERCENT: percentVariationFormatter,
- WORK_DUR: durationVariationFormatter,
- SHORT_WORK_DUR: shortDurationVariationFormatter,
- RATING: emptyFormatter,
- LEVEL: emptyFormatter,
- MILLISEC: millisecondsVariationFormatter
- };
- return FORMATTERS[type] || noFormatter;
-}
-
function numberFormatter(
value: number,
minimumFractionDigits = 0,
@@ -156,19 +134,10 @@ function noFormatter(value: string | number): string | number {
return value;
}
-function emptyFormatter(): string {
- return '';
-}
-
function intFormatter(value: number): string {
return numberFormatter(value);
}
-function intVariationFormatter(value: number): string {
- const prefix = value < 0 ? '-' : '+';
- return prefix + intFormatter(Math.abs(value));
-}
-
function shortIntFormatter(value: number): string {
if (value >= 1e9) {
return numberFormatter(value / 1e9) + translate('short_number_suffix.g');
@@ -183,20 +152,10 @@ function shortIntFormatter(value: number): string {
}
}
-function shortIntVariationFormatter(value: number): string {
- const formatted = shortIntFormatter(Math.abs(value));
- return value < 0 ? `-${formatted}` : `+${formatted}`;
-}
-
function floatFormatter(value: number): string {
return numberFormatter(value, 1, 5);
}
-function floatVariationFormatter(value: number): string {
- const prefix = value < 0 ? '-' : '+';
- return prefix + floatFormatter(Math.abs(value));
-}
-
function percentFormatter(value: string | number, options: { decimals?: number } = {}): string {
if (typeof value === 'string') {
value = parseFloat(value);
@@ -207,17 +166,6 @@ function percentFormatter(value: string | number, options: { decimals?: number }
return value === 100 ? '100%' : numberFormatter(value, 1) + '%';
}
-function percentVariationFormatter(
- value: string | number,
- options: { decimals?: number } = {}
-): string {
- if (typeof value === 'string') {
- value = parseFloat(value);
- }
- const prefix = value < 0 ? '-' : '+';
- return prefix + percentFormatter(Math.abs(value), options);
-}
-
function ratingFormatter(value: string | number): string {
if (typeof value === 'string') {
value = parseInt(value, 10);
@@ -247,12 +195,6 @@ function millisecondsFormatter(value: number): string {
}
}
-function millisecondsVariationFormatter(value: number): string {
- const absValue = Math.abs(value);
- const formattedValue = millisecondsFormatter(absValue);
- return value < 0 ? `-${formattedValue}` : `+${formattedValue}`;
-}
-
/*
* Debt Formatters
*/
@@ -362,22 +304,6 @@ function shortDurationFormatter(value: string | number): string {
return formatDurationShort(isNegative, days, hours, remainingValue);
}
-function durationVariationFormatter(value: string | number): string {
- if (value === 0 || value === '0') {
- return '+0';
- }
- const formatted = durationFormatter(value);
- return formatted[0] !== '-' ? '+' + formatted : formatted;
-}
-
-function shortDurationVariationFormatter(value: string | number): string {
- if (value === 0 || value === '0') {
- return '+0';
- }
- const formatted = shortDurationFormatter(value);
- return formatted[0] !== '-' ? '+' + formatted : formatted;
-}
-
function getRatingGrid(): string {
// workaround cyclic dependencies
const getStore = require('../app/utils/getStore').default;
@@ -429,12 +355,12 @@ function getMaintainabilityRatingTooltip(rating: number): string {
);
}
-export function getRatingTooltip(metricKey: string, value: number): string {
+export function getRatingTooltip(metricKey: string, value: number | string): string {
const ratingLetter = formatMeasure(value, 'RATING');
- const finalMetricKey = metricKey.startsWith('new_') ? metricKey.substr(4) : metricKey;
+ const finalMetricKey = isDiffMetric(metricKey) ? metricKey.substr(4) : metricKey;
return finalMetricKey === 'sqale_rating' || finalMetricKey === 'maintainability_rating'
- ? getMaintainabilityRatingTooltip(value)
+ ? getMaintainabilityRatingTooltip(Number(value))
: translate('metric', finalMetricKey, 'tooltip', ratingLetter);
}
diff --git a/server/sonar-web/src/main/js/helpers/periods.ts b/server/sonar-web/src/main/js/helpers/periods.ts
index 110eb67cf2a..afc0edf1c49 100644
--- a/server/sonar-web/src/main/js/helpers/periods.ts
+++ b/server/sonar-web/src/main/js/helpers/periods.ts
@@ -54,8 +54,8 @@ export function getPeriodLabel(period: Period | undefined): string | undefined {
return translateWithParameters(`overview.period.${period.mode}`, parameter);
}
-export function getPeriodDate(period: Period | undefined): Date | undefined {
- return period ? parseDate(period.date) : undefined;
+export function getPeriodDate(period?: { date?: string }): Date | undefined {
+ return period && period.date ? parseDate(period.date) : undefined;
}
export function getLeakPeriodLabel(periods: Period[]): string | undefined {