diff options
author | Viktor Vorona <viktor.vorona@sonarsource.com> | 2024-08-16 12:16:11 +0200 |
---|---|---|
committer | sonartech <sonartech@sonarsource.com> | 2024-08-26 20:03:07 +0000 |
commit | d248246c6370c9666c2f0f1e2a19256ccd9a1e7a (patch) | |
tree | c113bd35908f5706a7b5ef8c618fd52781416aa9 | |
parent | c498831a11a373cc23604e5defe95602028304b8 (diff) | |
download | sonarqube-d248246c6370c9666c2f0f1e2a19256ccd9a1e7a.tar.gz sonarqube-d248246c6370c9666c2f0f1e2a19256ccd9a1e7a.zip |
SONAR-22728 Portfolio overview
5 files changed, 122 insertions, 3 deletions
diff --git a/server/sonar-web/design-system/src/components/DonutChart.tsx b/server/sonar-web/design-system/src/components/DonutChart.tsx index f8443d8d2c3..14c4ec3782b 100644 --- a/server/sonar-web/design-system/src/components/DonutChart.tsx +++ b/server/sonar-web/design-system/src/components/DonutChart.tsx @@ -25,8 +25,10 @@ export interface DataPoint { } export interface DonutChartProps { + cornerRadius?: number; data: DataPoint[]; height: number; + minPercent?: number; padAngle?: number; padding?: [number, number, number, number]; thickness: number; @@ -34,7 +36,7 @@ export interface DonutChartProps { } export function DonutChart(props: DonutChartProps) { - const { height, padding = [0, 0, 0, 0], width } = props; + const { height, cornerRadius, minPercent = 0, padding = [0, 0, 0, 0], width } = props; const availableWidth = width - padding[1] - padding[3]; const availableHeight = height - padding[0] - padding[2]; @@ -42,9 +44,11 @@ export function DonutChart(props: DonutChartProps) { const size = Math.min(availableWidth, availableHeight); const radius = Math.floor(size / 2); + const total = props.data.reduce((acc, d) => acc + d.value, 0); + const pie = d3Pie<any, DataPoint>() .sort(null) - .value((d) => d.value); + .value((d) => Math.max(d.value, (total / 100) * minPercent)); if (props.padAngle !== undefined) { pie.padAngle(props.padAngle); @@ -53,6 +57,7 @@ export function DonutChart(props: DonutChartProps) { const sectors = pie(props.data).map((d, i) => { return ( <Sector + cornerRadius={cornerRadius} data={d} fill={props.data[i].fill} key={i} @@ -72,6 +77,7 @@ export function DonutChart(props: DonutChartProps) { } interface SectorProps { + cornerRadius?: number; data: PieArcDatum<DataPoint>; fill: string; radius: number; @@ -82,6 +88,10 @@ function Sector(props: SectorProps) { const arc = d3Arc<any, PieArcDatum<DataPoint>>() .outerRadius(props.radius) .innerRadius(props.radius - props.thickness); + + if (props.cornerRadius) { + arc.cornerRadius(props.cornerRadius); + } const d = arc(props.data) as string; return <path d={d} style={{ fill: props.fill }} />; } diff --git a/server/sonar-web/design-system/src/theme/light.ts b/server/sonar-web/design-system/src/theme/light.ts index dce350b51b6..8c8304dcc1d 100644 --- a/server/sonar-web/design-system/src/theme/light.ts +++ b/server/sonar-web/design-system/src/theme/light.ts @@ -478,6 +478,44 @@ export const lightTheme = { 'rating.D': COLORS.red[200], 'rating.E': COLORS.red[200], + 'portfolio.rating.A.text': COLORS.green[900], + 'portfolio.rating.A.background': COLORS.green[100], + 'portfolio.rating.A.border': COLORS.green[400], + 'portfolio.rating.B.text': COLORS.yellowGreen[900], + 'portfolio.rating.B.background': COLORS.yellowGreen[100], + 'portfolio.rating.B.border': COLORS.yellowGreen[400], + 'portfolio.rating.C.text': COLORS.yellow[900], + 'portfolio.rating.C.background': COLORS.yellow[100], + 'portfolio.rating.C.border': COLORS.yellow[500], + 'portfolio.rating.D.text': COLORS.red[900], + 'portfolio.rating.D.background': COLORS.red[100], + 'portfolio.rating.D.border': COLORS.red[400], + 'portfolio.rating.E.text': COLORS.red[900], + 'portfolio.rating.E.background': COLORS.red[100], + 'portfolio.rating.E.border': COLORS.red[400], + 'portfolio.rating.NONE.text': COLORS.blueGrey[300], + 'portfolio.rating.NONE.background': COLORS.blueGrey[50], + 'portfolio.rating.NONE.border': COLORS.blueGrey[200], + + 'portfolio.rating.legacy.A.text': COLORS.green[900], + 'portfolio.rating.legacy.A.background': COLORS.green[100], + 'portfolio.rating.legacy.A.border': COLORS.green[400], + 'portfolio.rating.legacy.B.text': COLORS.yellowGreen[900], + 'portfolio.rating.legacy.B.background': COLORS.yellowGreen[100], + 'portfolio.rating.legacy.B.border': COLORS.yellowGreen[400], + 'portfolio.rating.legacy.C.text': COLORS.yellow[900], + 'portfolio.rating.legacy.C.background': COLORS.yellow[100], + 'portfolio.rating.legacy.C.border': COLORS.yellow[500], + 'portfolio.rating.legacy.D.text': COLORS.orange[900], + 'portfolio.rating.legacy.D.background': COLORS.orange[100], + 'portfolio.rating.legacy.D.border': COLORS.orange[300], + 'portfolio.rating.legacy.E.text': COLORS.red[900], + 'portfolio.rating.legacy.E.background': COLORS.red[100], + 'portfolio.rating.legacy.E.border': COLORS.red[400], + 'portfolio.rating.legacy.NONE.text': COLORS.blueGrey[300], + 'portfolio.rating.legacy.NONE.background': COLORS.blueGrey[50], + 'portfolio.rating.legacy.NONE.border': COLORS.blueGrey[200], + // rating donut outside circle indicators 'ratingDonut.A': COLORS.green[400], 'ratingDonut.B': COLORS.yellowGreen[400], diff --git a/server/sonar-web/src/main/js/helpers/constants.ts b/server/sonar-web/src/main/js/helpers/constants.ts index 82c0fd1ca6e..64f92f5c95a 100644 --- a/server/sonar-web/src/main/js/helpers/constants.ts +++ b/server/sonar-web/src/main/js/helpers/constants.ts @@ -192,10 +192,19 @@ export const DEPRECATED_ACTIVITY_METRICS = [ export const SOFTWARE_QUALITY_RATING_METRICS_MAP: Record<string, MetricKey> = { [MetricKey.releasability_rating]: MetricKey.software_quality_releasability_rating, + [MetricKey.releasability_rating_distribution]: + MetricKey.software_quality_releasability_rating_distribution, [MetricKey.sqale_rating]: MetricKey.software_quality_maintainability_rating, + [MetricKey.maintainability_rating_distribution]: + MetricKey.software_quality_maintainability_rating_distribution, [MetricKey.security_rating]: MetricKey.software_quality_security_rating, + [MetricKey.security_rating_distribution]: MetricKey.software_quality_security_rating_distribution, [MetricKey.reliability_rating]: MetricKey.software_quality_reliability_rating, + [MetricKey.reliability_rating_distribution]: + MetricKey.software_quality_reliability_rating_distribution, [MetricKey.security_review_rating]: MetricKey.software_quality_security_review_rating, + [MetricKey.security_review_rating_distribution]: + MetricKey.software_quality_security_review_rating_distribution, [MetricKey.reliability_remediation_effort]: MetricKey.software_quality_reliability_remediation_effort, [MetricKey.security_remediation_effort]: MetricKey.software_quality_security_remediation_effort, @@ -204,9 +213,17 @@ export const SOFTWARE_QUALITY_RATING_METRICS_MAP: Record<string, MetricKey> = { [MetricKey.effort_to_reach_maintainability_rating_a]: MetricKey.effort_to_reach_software_quality_maintainability_rating_a, [MetricKey.new_maintainability_rating]: MetricKey.new_software_quality_maintainability_rating, + [MetricKey.new_maintainability_rating_distribution]: + MetricKey.new_software_quality_maintainability_rating_distribution, [MetricKey.new_security_rating]: MetricKey.new_software_quality_security_rating, + [MetricKey.new_security_rating_distribution]: + MetricKey.new_software_quality_security_rating_distribution, [MetricKey.new_reliability_rating]: MetricKey.new_software_quality_reliability_rating, + [MetricKey.new_reliability_rating_distribution]: + MetricKey.new_software_quality_reliability_rating_distribution, [MetricKey.new_security_review_rating]: MetricKey.new_software_quality_security_review_rating, + [MetricKey.new_security_review_rating_distribution]: + MetricKey.new_software_quality_security_review_rating_distribution, [MetricKey.new_technical_debt]: MetricKey.new_software_quality_maintainability_remediation_effort, [MetricKey.new_reliability_remediation_effort]: MetricKey.new_software_quality_reliability_remediation_effort, diff --git a/server/sonar-web/src/main/js/helpers/doc-links.ts b/server/sonar-web/src/main/js/helpers/doc-links.ts index 0f4c5a2f83b..b02acce18ad 100644 --- a/server/sonar-web/src/main/js/helpers/doc-links.ts +++ b/server/sonar-web/src/main/js/helpers/doc-links.ts @@ -63,6 +63,7 @@ export enum DocLink { Issues = '/user-guide/issues/introduction/', IssueStatuses = '/user-guide/issues/solution-overview/#life-cycle', MainBranchAnalysis = '/project-administration/maintaining-the-branches-of-your-project/', + ManagingPortfolios = '/project-administration/managing-portfolios/', MetricDefinitions = '/user-guide/code-metrics/metrics-definition/', Monorepos = '/project-administration/monorepos/', NewCodeDefinition = '/project-administration/clean-as-you-code-settings/defining-new-code/', diff --git a/server/sonar-web/src/main/js/queries/measures.ts b/server/sonar-web/src/main/js/queries/measures.ts index 57a5f6fb182..68cc602ea89 100644 --- a/server/sonar-web/src/main/js/queries/measures.ts +++ b/server/sonar-web/src/main/js/queries/measures.ts @@ -38,7 +38,7 @@ import { getBranchLikeQuery } from '../sonar-aligned/helpers/branch-like'; import { MetricKey } from '../sonar-aligned/types/metrics'; import { BranchLike } from '../types/branch-like'; import { Measure } from '../types/types'; -import { createInfiniteQueryHook, createQueryHook } from './common'; +import { createInfiniteQueryHook, createQueryHook, StaleTime } from './common'; export function useAllMeasuresHistoryQuery( component: string | undefined, @@ -268,3 +268,56 @@ export const useMeasureQuery = createQueryHook( }); }, ); + +const PORTFOLIO_OVERVIEW_METRIC_KEYS = [ + MetricKey.software_quality_releasability_rating, + MetricKey.software_quality_releasability_rating_distribution, + MetricKey.software_quality_security_rating_distribution, + MetricKey.software_quality_security_review_rating_distribution, + MetricKey.software_quality_maintainability_rating_distribution, + MetricKey.software_quality_reliability_rating_distribution, + MetricKey.new_software_quality_security_rating_distribution, + MetricKey.new_software_quality_security_review_rating_distribution, + MetricKey.new_software_quality_maintainability_rating_distribution, + MetricKey.new_software_quality_reliability_rating_distribution, +]; + +export const useMeasuresQuery = createQueryHook( + ({ + componentKey, + metricKeys, + branchLike, + }: { + branchLike?: BranchLike; + componentKey: string; + metricKeys: string; + }) => { + const queryClient = useQueryClient(); + const branchLikeQuery = getBranchLikeQuery(branchLike); + + return queryOptions({ + queryKey: ['measures', 'list', componentKey, 'branchLike', branchLikeQuery, metricKeys], + queryFn: async () => { + const measures = await getMeasures({ + component: componentKey, + // TODO Remove once BE is ready + metricKeys: metricKeys + .split(',') + .filter((key) => !PORTFOLIO_OVERVIEW_METRIC_KEYS.includes(key as MetricKey)) + .join(), + }); + + const measuresMapByMetricKey = groupBy(measures, 'metric'); + metricKeys.split(',').forEach((metricKey) => { + const measure = measuresMapByMetricKey[metricKey]?.[0] ?? null; + queryClient.setQueryData<Measure>( + ['measures', 'details', componentKey, 'branchLike', branchLike, metricKey], + measure, + ); + }); + return measures; + }, + staleTime: StaleTime.LONG, + }); + }, +); |