diff options
Diffstat (limited to 'server/sonar-web/src')
-rw-r--r-- | server/sonar-web/src/main/js/components/widgets/barchart.js | 140 | ||||
-rw-r--r-- | server/sonar-web/src/main/js/helpers/__tests__/__snapshots__/query-test.ts.snap (renamed from server/sonar-web/src/main/js/helpers/__tests__/__snapshots__/query-test.js.snap) | 0 | ||||
-rw-r--r-- | server/sonar-web/src/main/js/helpers/__tests__/issues-test.ts (renamed from server/sonar-web/src/main/js/helpers/__tests__/issues-test.js) | 3 | ||||
-rw-r--r-- | server/sonar-web/src/main/js/helpers/__tests__/measures-test.ts (renamed from server/sonar-web/src/main/js/helpers/__tests__/measures-test.js) | 10 | ||||
-rw-r--r-- | server/sonar-web/src/main/js/helpers/__tests__/query-test.ts (renamed from server/sonar-web/src/main/js/helpers/__tests__/query-test.js) | 5 | ||||
-rw-r--r-- | server/sonar-web/src/main/js/helpers/issues.ts (renamed from server/sonar-web/src/main/js/helpers/issues.js) | 131 | ||||
-rw-r--r-- | server/sonar-web/src/main/js/helpers/measures.ts (renamed from server/sonar-web/src/main/js/helpers/measures.js) | 231 | ||||
-rw-r--r-- | server/sonar-web/src/main/js/helpers/periods.ts (renamed from server/sonar-web/src/main/js/helpers/periods.js) | 28 | ||||
-rw-r--r-- | server/sonar-web/src/main/js/helpers/query.ts (renamed from server/sonar-web/src/main/js/helpers/query.js) | 37 |
9 files changed, 233 insertions, 352 deletions
diff --git a/server/sonar-web/src/main/js/components/widgets/barchart.js b/server/sonar-web/src/main/js/components/widgets/barchart.js deleted file mode 100644 index ab376ca1a3d..00000000000 --- a/server/sonar-web/src/main/js/components/widgets/barchart.js +++ /dev/null @@ -1,140 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2017 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 $ from 'jquery'; -import { max } from 'd3-array'; -import { select } from 'd3-selection'; -import { scaleLinear, scaleBand } from 'd3-scale'; -import { isSameDay, parseDate, toNotSoISOString } from '../../helpers/dates'; - -function trans(left, top) { - return `translate(${left}, ${top})`; -} - -const defaults = function() { - return { - height: 140, - color: '#1f77b4', - - marginLeft: 1, - marginRight: 1, - marginTop: 18, - marginBottom: 1 - }; -}; - -/* - * data = [ - * { val: '2015-01-30', count: 30 }, - * ... - * ] - */ - -$.fn.barchart = function(data) { - $(this).each(function() { - const options = { ...defaults(), ...$(this).data() }; - Object.assign(options, { - width: options.width || $(this).width(), - endDate: options.endDate ? parseDate(options.endDate) : null - }); - - const container = select(this); - const svg = container - .append('svg') - .attr('width', options.width + 2) - .attr('height', options.height + 2) - .classed('sonar-d3', true); - const plot = svg.append('g').classed('plot', true); - const xScale = scaleBand().domain(data.map((d, i) => i)); - const yScaleMax = max(data, d => d.count); - const yScale = scaleLinear().domain([0, yScaleMax]); - - Object.assign(options, { - availableWidth: options.width - options.marginLeft - options.marginRight, - availableHeight: options.height - options.marginTop - options.marginBottom - }); - - plot.attr('transform', trans(options.marginLeft, options.marginTop)); - xScale.rangeRound([0, options.availableWidth]).paddingInner(0.05); - yScale.range([3, options.availableHeight]); - - const barWidth = xScale.bandwidth(); - const bars = plot.selectAll('g').data(data); - - if (barWidth > 0) { - const barsEnter = bars - .enter() - .append('g') - .attr('transform', (d, i) => - trans(xScale(i), Math.ceil(options.availableHeight - yScale(d.count))) - ); - - barsEnter - .append('rect') - .style('fill', options.color) - .attr('width', barWidth) - .attr('height', d => Math.floor(yScale(d.count))) - .style('cursor', 'pointer') - .attr('data-period-start', d => toNotSoISOString(d.val)) - .attr('data-period-end', (d, i) => { - const ending = i < data.length - 1 ? data[i + 1].val : options.endDate; - if (ending) { - return toNotSoISOString(ending); - } else { - return ''; - } - }) - .attr('title', (d, i) => { - const beginning = parseDate(d.val); - let ending = options.endDate; - if (i < data.length - 1) { - ending = parseDate(data[i + 1].val); - ending.setDate(ending.getDate() - 1); - } - if (ending) { - return ( - d.text + - '<br>' + - beginning.format('LL') + - (isSameDay(ending, beginning) ? '' : ' – ' + ending.format('LL')) - ); - } else { - return d.text + '<br>' + beginning.format('LL'); - } - }) - .attr('data-placement', 'bottom') - .attr('data-toggle', 'tooltip'); - const maxValue = max(data, d => d.count); - let isValueShown = false; - barsEnter - .append('text') - .classed('subtitle', true) - .attr('transform', trans(barWidth / 2, -4)) - .style('text-anchor', 'middle') - .text(d => { - const text = !isValueShown && d.count === maxValue ? d.text : ''; - isValueShown = d.count === maxValue; - return text; - }); - $(this) - .find('[data-toggle=tooltip]') - .tooltip({ container: 'body', html: true }); - } - }); -}; diff --git a/server/sonar-web/src/main/js/helpers/__tests__/__snapshots__/query-test.js.snap b/server/sonar-web/src/main/js/helpers/__tests__/__snapshots__/query-test.ts.snap index 4f0b5538ba8..4f0b5538ba8 100644 --- a/server/sonar-web/src/main/js/helpers/__tests__/__snapshots__/query-test.js.snap +++ b/server/sonar-web/src/main/js/helpers/__tests__/__snapshots__/query-test.ts.snap diff --git a/server/sonar-web/src/main/js/helpers/__tests__/issues-test.js b/server/sonar-web/src/main/js/helpers/__tests__/issues-test.ts index 49d9a67a68f..034fcb4a916 100644 --- a/server/sonar-web/src/main/js/helpers/__tests__/issues-test.js +++ b/server/sonar-web/src/main/js/helpers/__tests__/issues-test.ts @@ -17,7 +17,6 @@ * 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 { parseIssueFromResponse } from '../issues'; it('should populate comments data', () => { @@ -40,7 +39,7 @@ it('should populate comments data', () => { updatable: true } ] - }; + } as any; expect(parseIssueFromResponse(issue, undefined, users, undefined).comments).toEqual([ { author: 'admin', diff --git a/server/sonar-web/src/main/js/helpers/__tests__/measures-test.js b/server/sonar-web/src/main/js/helpers/__tests__/measures-test.ts index d36a63740eb..875b3eb9f75 100644 --- a/server/sonar-web/src/main/js/helpers/__tests__/measures-test.js +++ b/server/sonar-web/src/main/js/helpers/__tests__/measures-test.ts @@ -160,11 +160,11 @@ describe('#formatMeasure()', () => { }); it('should return null if value is empty string', () => { - expect(formatMeasure('', 'PERCENT')).toBeNull(); + expect(formatMeasure('', 'PERCENT')).toBe(''); }); - it('should not fail without parameters', () => { - expect(formatMeasure()).toBeNull(); + it('should not fail with undefined', () => { + expect(formatMeasure(undefined, 'INT')).toBe(''); }); }); @@ -252,7 +252,7 @@ describe('#formatMeasureVariation()', () => { expect(formatMeasureVariation('random value', 'RANDOM_TYPE')).toBe('random value'); }); - it('should not fail without parameters', () => { - expect(formatMeasureVariation()).toBeNull(); + it('should not fail with undefined', () => { + expect(formatMeasureVariation(undefined, 'INT')).toBe(''); }); }); diff --git a/server/sonar-web/src/main/js/helpers/__tests__/query-test.js b/server/sonar-web/src/main/js/helpers/__tests__/query-test.ts index 9c2c8c24b37..09bfc803b71 100644 --- a/server/sonar-web/src/main/js/helpers/__tests__/query-test.js +++ b/server/sonar-web/src/main/js/helpers/__tests__/query-test.ts @@ -42,7 +42,7 @@ describe('parseAsBoolean', () => { }); it('should return a default value', () => { - expect(query.parseAsBoolean(1)).toBeTruthy(); + expect(query.parseAsBoolean('1')).toBeTruthy(); expect(query.parseAsBoolean('foo')).toBeTruthy(); }); }); @@ -60,7 +60,7 @@ describe('parseAsString', () => { it('should parse strings correctly', () => { expect(query.parseAsString('random')).toBe('random'); expect(query.parseAsString('')).toBe(''); - expect(query.parseAsString(null)).toBe(''); + expect(query.parseAsString(undefined)).toBe(''); }); }); @@ -82,7 +82,6 @@ describe('serializeDate', () => { const date = parseDate('2016-06-20T13:09:48.256Z'); it('should serialize string correctly', () => { expect(query.serializeDate(date)).toBe('2016-06-20T13:09:48+0000'); - expect(query.serializeDate('')).toBeUndefined(); expect(query.serializeDate()).toBeUndefined(); }); }); diff --git a/server/sonar-web/src/main/js/helpers/issues.js b/server/sonar-web/src/main/js/helpers/issues.ts index a03d7ac807f..34cef95d7c6 100644 --- a/server/sonar-web/src/main/js/helpers/issues.js +++ b/server/sonar-web/src/main/js/helpers/issues.ts @@ -17,64 +17,71 @@ * 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 { flatten, sortBy } from 'lodash'; import { SEVERITIES } from './constants'; -/*:: import type { Issue, FlowLocation } from '../components/issue/types'; */ - -/*:: -type TextRange = { - startLine: number, - endLine: number, - startOffset: number, - endOffset: number -}; -*/ - -/*:: -type Comment = { - login: string -}; -*/ - -/*:: -type User = { - login: string -}; -*/ - -/*:: -type RawIssue = { - assignee?: string, - author: string, - comments?: Array<Comment>, - component: string, + +interface TextRange { + startLine: number; + endLine: number; + startOffset: number; + endOffset: number; +} + +interface FlowLocation { + msg: string; + textRange?: TextRange; +} + +interface Comment { + login: string; + [x: string]: any; +} + +interface User { + login: string; +} + +interface Rule {} + +interface Component {} + +interface IssueBase { + severity: string; + [x: string]: any; +} + +interface RawIssue extends IssueBase { + assignee?: string; + author?: string; + comments?: Array<Comment>; + component: string; flows?: Array<{ - locations?: Array<{ msg: string, textRange?: TextRange }> - }>, - key: string, - line?: number, - project: string, - rule: string, - status: string, - subProject?: string, - textRange?: TextRange -}; -*/ - -export function sortBySeverity(issues /*: Array<*> */) { + locations?: FlowLocation[]; + }>; + key: string; + line?: number; + project: string; + rule: string; + status: string; + subProject?: string; + textRange?: TextRange; +} + +interface Issue extends IssueBase {} + +export function sortBySeverity(issues: Issue[]): Issue[] { return sortBy(issues, issue => SEVERITIES.indexOf(issue.severity)); } function injectRelational( - issue /*: RawIssue | Comment */, - source /*: ?Array<*> */, - baseField /*: string */, - lookupField /*: string */ + issue: { [x: string]: any }, + source: any[] | undefined, + baseField: string, + lookupField: string ) { - const newFields = {}; + const newFields: { [x: string]: any } = {}; const baseValue = issue[baseField]; - if (baseValue != null && source != null) { + if (baseValue != undefined && source != undefined) { const lookupValue = source.find(candidate => candidate[lookupField] === baseValue); if (lookupValue != null) { Object.keys(lookupValue).forEach(key => { @@ -86,7 +93,7 @@ function injectRelational( return newFields; } -function injectCommentsRelational(issue /*: RawIssue */, users /*: ?Array<User> */) { +function injectCommentsRelational(issue: RawIssue, users?: User[]) { if (!issue.comments) { return {}; } @@ -100,11 +107,11 @@ function injectCommentsRelational(issue /*: RawIssue */, users /*: ?Array<User> return { comments }; } -function prepareClosed(issue /*: RawIssue */) { +function prepareClosed(issue: RawIssue): { flows?: undefined } { return issue.status === 'CLOSED' ? { flows: undefined } : {}; } -function ensureTextRange(issue /*: RawIssue */) { +function ensureTextRange(issue: RawIssue): { textRange?: TextRange } { return issue.line && !issue.textRange ? { textRange: { @@ -117,20 +124,18 @@ function ensureTextRange(issue /*: RawIssue */) { : {}; } -function reverseLocations(locations /*: Array<*> */) { +function reverseLocations(locations: FlowLocation[]): FlowLocation[] { const x = [...locations]; x.reverse(); return x; } function splitFlows( - issue /*: RawIssue */ - // $FlowFixMe textRange is not null -) /*: { secondaryLocations: Array<FlowLocation>, flows: Array<Array<FlowLocation>> } */ { + issue: RawIssue +): { secondaryLocations: Array<FlowLocation>; flows: Array<Array<FlowLocation>> } { const parsedFlows = (issue.flows || []) .filter(flow => flow.locations != null) - // $FlowFixMe flow.locations is not null - .map(flow => flow.locations.filter(location => location.textRange != null)); + .map(flow => flow.locations!.filter(location => location.textRange != null)); const onlySecondaryLocations = parsedFlows.every(flow => flow.length === 1); @@ -140,11 +145,11 @@ function splitFlows( } export function parseIssueFromResponse( - issue /*: Object */, - components /*: ?Array<*> */, - users /*: ?Array<*> */, - rules /*: ?Array<*> */ -) /*: Issue */ { + issue: RawIssue, + components?: Component[], + users?: User[], + rules?: Rule[] +): Issue { const { secondaryLocations, flows } = splitFlows(issue); return { ...issue, diff --git a/server/sonar-web/src/main/js/helpers/measures.js b/server/sonar-web/src/main/js/helpers/measures.ts index bdd207a6a28..41dec890089 100644 --- a/server/sonar-web/src/main/js/helpers/measures.js +++ b/server/sonar-web/src/main/js/helpers/measures.ts @@ -17,46 +17,55 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -import numeral from 'numeral'; +import * as numeral from 'numeral'; import { translate, translateWithParameters } from './l10n'; const HOURS_IN_DAY = 8; -/** - * Format a measure value for a given type - * @param {string|number} value - * @param {string} type - */ -export function formatMeasure(value, type, options) { +interface Measure { + metric: string; + periods?: any[]; +} + +interface EnhancedMeasure { + metric: Metric; +} + +interface Metric { + key: string; +} + +interface Formatter { + (value: string | number, options?: any): string; +} + +/** Format a measure value for a given type */ +export function formatMeasure( + value: string | number | undefined, + type: string, + options?: any +): string { const formatter = getFormatter(type); return useFormatter(value, formatter, options); } -/** - * Format a measure variation for a given type - * @param {string|number} value - * @param {string} type - */ -export function formatMeasureVariation(value, type, 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 - * @param {string} metricKey - * @returns {string} - */ -export function localizeMetric(metricKey) { +/** Return a localized metric name */ +export function localizeMetric(metricKey: string): string { return translate('metric', metricKey, 'name'); } -/** - * Return corresponding "short" for better display in UI - * @param {string} type - * @returns {string} - */ -export function getShortType(type) { +/** Return corresponding "short" for better display in UI */ +export function getShortType(type: string): string { if (type === 'INT') { return 'SHORT_INT'; } else if (type === 'WORK_DUR') { @@ -65,49 +74,38 @@ export function getShortType(type) { return type; } -/** - * Map metrics - * @param {Array} measures - * @param {Array} metrics - * @returns {Array} - */ -export function enhanceMeasuresWithMetrics(measures, metrics) { +export function enhanceMeasuresWithMetrics( + measures: Measure[], + metrics: Metric[] +): EnhancedMeasure[] { return measures.map(measure => { - const metric = metrics.find(metric => metric.key === measure.metric); + const metric = metrics.find(metric => metric.key === measure.metric) as Metric; return { ...measure, metric }; }); } -/** - * Get period value of a measure - * @param measure - * @param periodIndex - */ -export function getPeriodValue(measure, periodIndex) { +/** Get period value of a measure */ +export function getPeriodValue(measure: Measure, periodIndex: number): string | number | undefined { const { periods } = measure; - const period = periods.find(period => period.index === periodIndex); - return period ? period.value : null; + const period = periods && periods.find(period => period.index === periodIndex); + return period ? period.value : undefined; } -/** - * Check if metric is differential - * @param {string} metricKey - * @returns {boolean} - */ -export function isDiffMetric(metricKey) { +/** Check if metric is differential */ +export function isDiffMetric(metricKey: string): boolean { return metricKey.indexOf('new_') === 0; } -/* - * Helpers - */ - -function useFormatter(value, formatter, options) { - return value != null && value !== '' && formatter != null ? formatter(value, options) : null; +function useFormatter( + value: string | number | undefined, + formatter: Formatter, + options?: any +): string { + return value != undefined && value !== '' ? formatter(value, options) : ''; } -function getFormatter(type) { - const FORMATTERS = { +function getFormatter(type: string): Formatter { + const FORMATTERS: { [type: string]: Formatter } = { INT: intFormatter, SHORT_INT: shortIntFormatter, FLOAT: floatFormatter, @@ -121,8 +119,8 @@ function getFormatter(type) { return FORMATTERS[type] || noFormatter; } -function getVariationFormatter(type) { - const FORMATTERS = { +function getVariationFormatter(type: string): Formatter { + const FORMATTERS: { [type: string]: Formatter } = { INT: intVariationFormatter, SHORT_INT: shortIntVariationFormatter, FLOAT: floatVariationFormatter, @@ -136,31 +134,27 @@ function getVariationFormatter(type) { return FORMATTERS[type] || noFormatter; } -/* - * Formatters - */ - -function genericFormatter(value, formatValue) { +function genericNumberFormatter(value: number, formatValue?: string): string { return numeral(value).format(formatValue); } -function noFormatter(value) { +function noFormatter(value: string | number): string | number { return value; } -function emptyFormatter() { - return null; +function emptyFormatter(): string { + return ''; } -function intFormatter(value) { - return genericFormatter(value, '0,0'); +function intFormatter(value: number): string { + return genericNumberFormatter(value, '0,0'); } -function intVariationFormatter(value) { - return genericFormatter(value, '+0,0'); +function intVariationFormatter(value: number): string { + return genericNumberFormatter(value, '+0,0'); } -function shortIntFormatter(value) { +function shortIntFormatter(value: number): string { let format = '0,0'; if (value >= 1000) { format = '0.[0]a'; @@ -168,44 +162,53 @@ function shortIntFormatter(value) { if (value >= 10000) { format = '0a'; } - return genericFormatter(value, format); + return genericNumberFormatter(value, format); } -function shortIntVariationFormatter(value) { +function shortIntVariationFormatter(value: number): string { const formatted = shortIntFormatter(Math.abs(value)); return value < 0 ? `-${formatted}` : `+${formatted}`; } -function floatFormatter(value) { - return genericFormatter(value, '0,0.0[0000]'); +function floatFormatter(value: number): string { + return genericNumberFormatter(value, '0,0.0[0000]'); } -function floatVariationFormatter(value) { - return value === 0 ? '+0.0' : genericFormatter(value, '+0,0.0[0000]'); +function floatVariationFormatter(value: number): string { + return value === 0 ? '+0.0' : genericNumberFormatter(value, '+0,0.0[0000]'); } -function percentFormatter(value, options = {}) { - value = parseFloat(value); +function percentFormatter(value: string | number, options: { decimals?: number } = {}): string { + if (typeof value === 'string') { + value = parseFloat(value); + } if (options.decimals) { - return genericFormatter(value / 100, `0,0.${'0'.repeat(options.decimals)}%`); + return genericNumberFormatter(value / 100, `0,0.${'0'.repeat(options.decimals)}%`); } - return value === 100 ? '100%' : genericFormatter(value / 100, '0,0.0%'); + return value === 100 ? '100%' : genericNumberFormatter(value / 100, '0,0.0%'); } -function percentVariationFormatter(value, options = {}) { - value = parseFloat(value); +function percentVariationFormatter( + value: string | number, + options: { decimals?: number } = {} +): string { + if (typeof value === 'string') { + value = parseFloat(value); + } if (options.decimals) { - return genericFormatter(value / 100, `+0,0.${'0'.repeat(options.decimals)}%`); + return genericNumberFormatter(value / 100, `+0,0.${'0'.repeat(options.decimals)}%`); } - return value === 0 ? '+0.0%' : genericFormatter(value / 100, '+0,0.0%'); + return value === 0 ? '+0.0%' : genericNumberFormatter(value / 100, '+0,0.0%'); } -function ratingFormatter(value) { - value = parseInt(value, 10); +function ratingFormatter(value: string | number): string { + if (typeof value === 'string') { + value = parseInt(value, 10); + } return String.fromCharCode(97 + value - 1).toUpperCase(); } -function levelFormatter(value) { +function levelFormatter(value: string): string { const l10nKey = 'metric.level.' + value; const result = translate(l10nKey); @@ -213,7 +216,7 @@ function levelFormatter(value) { return l10nKey !== result ? result : value; } -function millisecondsFormatter(value) { +function millisecondsFormatter(value: number): string { const ONE_SECOND = 1000; const ONE_MINUTE = 60 * ONE_SECOND; if (value >= ONE_MINUTE) { @@ -227,7 +230,7 @@ function millisecondsFormatter(value) { } } -function millisecondsVariationFormatter(value) { +function millisecondsVariationFormatter(value: number): string { const absValue = Math.abs(value); const formattedValue = millisecondsFormatter(absValue); return value < 0 ? `-${formattedValue}` : `+${formattedValue}`; @@ -237,31 +240,31 @@ function millisecondsVariationFormatter(value) { * Debt Formatters */ -function shouldDisplayDays(days) { +function shouldDisplayDays(days: number): boolean { return days > 0; } -function shouldDisplayDaysInShortFormat(days) { +function shouldDisplayDaysInShortFormat(days: number): boolean { return days > 0.9; } -function shouldDisplayHours(days, hours) { +function shouldDisplayHours(days: number, hours: number): boolean { return hours > 0 && days < 10; } -function shouldDisplayHoursInShortFormat(hours) { +function shouldDisplayHoursInShortFormat(hours: number): boolean { return hours > 0.9; } -function shouldDisplayMinutes(days, hours, minutes) { +function shouldDisplayMinutes(days: number, hours: number, minutes: number): boolean { return minutes > 0 && hours < 10 && days === 0; } -function addSpaceIfNeeded(value) { +function addSpaceIfNeeded(value: string): string { return value.length > 0 ? value + ' ' : value; } -function formatDuration(isNegative, days, hours, minutes) { +function formatDuration(isNegative: boolean, days: number, hours: number, minutes: number): string { let formatted = ''; if (shouldDisplayDays(days)) { formatted += translateWithParameters('work_duration.x_days', isNegative ? -1 * days : days); @@ -283,7 +286,12 @@ function formatDuration(isNegative, days, hours, minutes) { return formatted; } -function formatDurationShort(isNegative, days, hours, minutes) { +function formatDurationShort( + isNegative: boolean, + days: number, + hours: number, + minutes: number +): string { if (shouldDisplayDaysInShortFormat(days)) { const roundedDays = Math.round(days); const formattedDays = formatMeasure(isNegative ? -1 * roundedDays : roundedDays, 'SHORT_INT'); @@ -303,8 +311,11 @@ function formatDurationShort(isNegative, days, hours, minutes) { return translateWithParameters('work_duration.x_minutes', formattedMinutes); } -function durationFormatter(value) { - if (value === 0 || value === '0') { +function durationFormatter(value: string | number): string { + if (typeof value === 'string') { + value = parseInt(value); + } + if (value === 0) { return '0'; } const hoursInDay = HOURS_IN_DAY; @@ -317,9 +328,11 @@ function durationFormatter(value) { return formatDuration(isNegative, days, hours, remainingValue); } -function shortDurationFormatter(value) { - value = parseInt(value, 10); - if (value === 0 || value === '0') { +function shortDurationFormatter(value: string | number): string { + if (typeof value === 'string') { + value = parseInt(value); + } + if (value === 0) { return '0'; } const hoursInDay = HOURS_IN_DAY; @@ -332,7 +345,7 @@ function shortDurationFormatter(value) { return formatDurationShort(isNegative, days, hours, remainingValue); } -function durationVariationFormatter(value) { +function durationVariationFormatter(value: string | number): string { if (value === 0 || value === '0') { return '+0'; } @@ -340,7 +353,7 @@ function durationVariationFormatter(value) { return formatted[0] !== '-' ? '+' + formatted : formatted; } -function shortDurationVariationFormatter(value) { +function shortDurationVariationFormatter(value: string | number): string { if (value === 0 || value === '0') { return '+0'; } @@ -348,7 +361,7 @@ function shortDurationVariationFormatter(value) { return formatted[0] !== '-' ? '+' + formatted : formatted; } -function getRatingGrid() { +function getRatingGrid(): string { // workaround cyclic dependencies const getStore = require('../app/utils/getStore').default; const { getGlobalSettingValue } = require('../store/rootReducer'); @@ -358,8 +371,8 @@ function getRatingGrid() { return settingValue ? settingValue.value : ''; } -let maintainabilityRatingGrid; -function getMaintainabilityRatingGrid() { +let maintainabilityRatingGrid: number[]; +function getMaintainabilityRatingGrid(): number[] { if (maintainabilityRatingGrid) { return maintainabilityRatingGrid; } @@ -379,7 +392,7 @@ function getMaintainabilityRatingGrid() { return maintainabilityRatingGrid; } -function getMaintainabilityRatingTooltip(rating) { +function getMaintainabilityRatingTooltip(rating: number): string { const maintainabilityGrid = getMaintainabilityRatingGrid(); const maintainabilityRatingThreshold = maintainabilityGrid[Math.floor(rating) - 2]; @@ -399,7 +412,7 @@ function getMaintainabilityRatingTooltip(rating) { ); } -export function getRatingTooltip(metricKey, value) { +export function getRatingTooltip(metricKey: string, value: number): string { const ratingLetter = formatMeasure(value, 'RATING'); const finalMetricKey = metricKey.startsWith('new_') ? metricKey.substr(4) : metricKey; diff --git a/server/sonar-web/src/main/js/helpers/periods.js b/server/sonar-web/src/main/js/helpers/periods.ts index d458a1931eb..138e67606d6 100644 --- a/server/sonar-web/src/main/js/helpers/periods.js +++ b/server/sonar-web/src/main/js/helpers/periods.ts @@ -20,21 +20,29 @@ import { translate, translateWithParameters } from './l10n'; import { parseDate } from './dates'; -export function getPeriod(periods, index) { +interface Period { + date: string; + index: number; + mode: string; + modeParam?: string; + parameter: string; +} + +export function getPeriod(periods: Period[] | undefined, index: number): Period | undefined { if (!Array.isArray(periods)) { - return null; + return undefined; } return periods.find(period => period.index === index); } -export function getLeakPeriod(periods) { +export function getLeakPeriod(periods: Period[] | undefined): Period | undefined { return getPeriod(periods, 1); } -export function getPeriodLabel(period) { +export function getPeriodLabel(period: Period | undefined): string | undefined { if (!period) { - return null; + return undefined; } const parameter = period.modeParam || period.parameter; @@ -46,14 +54,10 @@ export function getPeriodLabel(period) { return translateWithParameters(`overview.period.${period.mode}`, parameter); } -export function getPeriodDate(period) { - if (!period) { - return null; - } - - return parseDate(period.date); +export function getPeriodDate(period: Period | undefined): Date | undefined { + return period ? parseDate(period.date) : undefined; } -export function getLeakPeriodLabel(periods) { +export function getLeakPeriodLabel(periods: Period[]): string | undefined { return getPeriodLabel(getLeakPeriod(periods)); } diff --git a/server/sonar-web/src/main/js/helpers/query.js b/server/sonar-web/src/main/js/helpers/query.ts index 400390e65b8..8517917de18 100644 --- a/server/sonar-web/src/main/js/helpers/query.js +++ b/server/sonar-web/src/main/js/helpers/query.ts @@ -17,15 +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 { isNil, omitBy } from 'lodash'; import { isValidDate, parseDate, toNotSoISOString } from './dates'; -/*:: -export type RawQuery = { [string]: any }; -*/ +export interface RawQuery { + [x: string]: any; +} -function arraysEqual(a, b) { +function arraysEqual(a: RawQuery, b: RawQuery): boolean { if (a.length !== b.length) { return false; } @@ -37,7 +36,7 @@ function arraysEqual(a, b) { return true; } -export function queriesEqual(a /*: Object */, b /*: Object */) /*: boolean */ { +export function queriesEqual(a: RawQuery, b: RawQuery): boolean { const keysA = Object.keys(a); const keysB = Object.keys(b); @@ -53,48 +52,50 @@ export function queriesEqual(a /*: Object */, b /*: Object */) /*: boolean */ { ); } -export function cleanQuery(query /*: { [string]: ?string } */) /*: RawQuery */ { +export function cleanQuery(query: RawQuery): RawQuery { return omitBy(query, isNil); } -export function parseAsBoolean( - value /*: ?string */, - defaultValue /*: boolean */ = true -) /*: boolean */ { +export function parseAsBoolean(value: string | undefined, defaultValue: boolean = true): boolean { return value === 'false' ? false : value === 'true' ? true : defaultValue; } -export function parseAsDate(value /*: ?string */) /*: Date | void */ { +export function parseAsDate(value?: string): Date | undefined { if (value) { const date = parseDate(value); if (isValidDate(date)) { return date; } } + return undefined; } -export function parseAsFacetMode(facetMode /*: string */) { +export function parseAsFacetMode(facetMode: string): string { return facetMode === 'debt' || facetMode === 'effort' ? 'effort' : 'count'; } -export function parseAsString(value /*: ?string */) /*: string */ { +export function parseAsString(value: string | undefined): string { return value || ''; } -export function parseAsArray(value /*: ?string */, itemParser /*: string => * */) /*: Array<*> */ { +export function parseAsArray( + value: string | undefined, + itemParser: (x: string) => string +): string[] { return value ? value.split(',').map(itemParser) : []; } -export function serializeDate(value /*: ?Date */) /*: string | void */ { +export function serializeDate(value?: Date): string | undefined { if (value != null && value.toISOString) { return toNotSoISOString(value); } + return undefined; } -export function serializeString(value /*: string */) /*: ?string */ { +export function serializeString(value: string): string | undefined { return value || undefined; } -export function serializeStringArray(value /*: ?Array<string> */) /*: ?string */ { +export function serializeStringArray(value: string[] | undefined[]): string | undefined { return value && value.length ? value.join() : undefined; } |