const thickness = SIZE_TO_THICKNESS_MAPPING[size];
if (value === undefined) {
- return <NoDataIcon height={width} width={width} />;
+ return <NoDataIcon size={size} />;
}
const themeRed = themeColor('coverageRed')({ theme });
const sizePX = SIZE_TO_PX_MAPPING[size];
if (rating === undefined) {
- return <NoDataIcon height={sizePX} width={sizePX} />;
+ return <NoDataIcon size={size} />;
}
const primaryColor = themeColor(`duplicationsIndicator.${rating}`)({ theme });
*/
import { CustomIcon, IconProps } from './Icon';
-export function NoDataIcon({ fill = 'currentColor', ...iconProps }: IconProps) {
+export interface NoDataIconProps extends IconProps {
+ size?: 'xs' | 'sm' | 'md';
+}
+
+const SIZES: Record<NonNullable<NoDataIconProps['size']>, number> = {
+ xs: 16,
+ sm: 24,
+ md: 36,
+};
+
+export function NoDataIcon({
+ fill = 'currentColor',
+ size = 'md',
+ ...iconProps
+}: Readonly<NoDataIconProps>) {
+ const iconSize = SIZES[size];
+
return (
- <CustomIcon {...iconProps}>
+ <CustomIcon height={iconSize} width={iconSize} {...iconProps}>
<path
clipRule="evenodd"
d="M16 8C16 12.4183 12.4183 16 8 16C5.5106 16 3.28676 14.863 1.81951 13.0799L15.4913 5.1865C15.8201 6.06172 16 7.00986 16 8ZM14.5574 3.41624L0.750565 11.3876C0.269025 10.3589 0 9.21089 0 8C0 3.58172 3.58172 0 8 0C10.7132 0 13.1109 1.35064 14.5574 3.41624Z"
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2024 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 styled from '@emotion/styled';
-import classNames from 'classnames';
-import {
- Card,
- HighImpactCircleIcon,
- LightLabel,
- NoDataIcon,
- PageTitle,
- SnoozeCircleIcon,
- Spinner,
- themeColor,
-} from 'design-system';
-import * as React from 'react';
-import { useIntl } from 'react-intl';
-import { getLeakValue } from '../../../components/measure/utils';
-import { DEFAULT_ISSUES_QUERY } from '../../../components/shared/utils';
-import { getBranchLikeQuery } from '../../../helpers/branch-like';
-import { findMeasure, formatMeasure } from '../../../helpers/measures';
-import { getComponentIssuesUrl } from '../../../helpers/urls';
-import { Branch } from '../../../types/branch-like';
-import { SoftwareImpactSeverity } from '../../../types/clean-code-taxonomy';
-import { IssueStatus } from '../../../types/issues';
-import { MetricKey, MetricType } from '../../../types/metrics';
-import { Component, MeasureEnhanced } from '../../../types/types';
-import { IssueMeasuresCardInner } from '../components/IssueMeasuresCardInner';
-
-export interface AcceptedIssuesPanelProps {
- branch?: Branch;
- component: Component;
- measures?: MeasureEnhanced[];
- isNewCode: boolean;
- loading?: boolean;
-}
-
-function AcceptedIssuesPanel(props: Readonly<AcceptedIssuesPanelProps>) {
- const { branch, component, measures = [], isNewCode, loading } = props;
- const intl = useIntl();
-
- const acceptedIssuesUrl = getComponentIssuesUrl(component.key, {
- ...getBranchLikeQuery(branch),
- issueStatuses: IssueStatus.Accepted,
- ...(isNewCode ? { inNewCodePeriod: 'true' } : {}),
- });
-
- const acceptedIssuesWithHighImpactUrl = getComponentIssuesUrl(component.key, {
- ...getBranchLikeQuery(branch),
- ...DEFAULT_ISSUES_QUERY,
- issueStatuses: IssueStatus.Accepted,
- impactSeverities: SoftwareImpactSeverity.High,
- });
-
- const acceptedCount = isNewCode
- ? getLeakValue(findMeasure(measures, MetricKey.new_accepted_issues))
- : findMeasure(measures, MetricKey.accepted_issues)?.value;
-
- const acceptedWithHighImpactCount = isNewCode
- ? undefined
- : findMeasure(measures, MetricKey.high_impact_accepted_issues)?.value;
-
- return (
- <div className="sw-mt-8">
- <PageTitle as="h2" text={intl.formatMessage({ id: 'overview.accepted_issues' })} />
- <LightLabel as="div" className="sw-mt-1 sw-mb-4">
- {intl.formatMessage({ id: 'overview.accepted_issues.description' })}
- </LightLabel>
- <Spinner loading={loading}>
- <div
- className={classNames('sw-grid sw-gap-4', {
- 'sw-grid-cols-2': isNewCode,
- 'sw-grid-cols-1': !isNewCode,
- })}
- >
- <Card className="sw-flex sw-gap-4">
- <IssueMeasuresCardInner
- disabled={component.needIssueSync}
- className={classNames({ 'sw-w-1/2': !isNewCode, 'sw-w-full': isNewCode })}
- metric={MetricKey.accepted_issues}
- value={formatMeasure(acceptedCount, MetricType.ShortInteger)}
- header={intl.formatMessage({
- id: isNewCode ? 'overview.accepted_issues' : 'overview.accepted_issues.total',
- })}
- url={acceptedIssuesUrl}
- icon={
- <SnoozeCircleIcon
- color={
- acceptedCount === '0' ? 'overviewCardDefaultIcon' : 'overviewCardWarningIcon'
- }
- className="sw--translate-y-3"
- />
- }
- />
- {!isNewCode && (
- <>
- <StyledCardSeparator />
- <IssueMeasuresCardInner
- disabled={Boolean(component.needIssueSync) || !acceptedWithHighImpactCount}
- className="sw-w-1/2"
- metric={MetricKey.high_impact_accepted_issues}
- value={formatMeasure(acceptedWithHighImpactCount, MetricType.ShortInteger)}
- header={intl.formatMessage({
- id: 'overview.high_impact_accepted_issues',
- })}
- url={acceptedIssuesWithHighImpactUrl}
- icon={
- acceptedWithHighImpactCount ? (
- <HighImpactCircleIcon className="sw--translate-y-3" />
- ) : (
- <NoDataIcon className="sw--translate-y-3" width={36} height={36} />
- )
- }
- />
- </>
- )}
- </Card>
- </div>
- </Spinner>
- </div>
- );
-}
-
-const StyledCardSeparator = styled.div`
- width: 1px;
- background-color: ${themeColor('projectCardBorder')};
-`;
-
-export default React.memo(AcceptedIssuesPanel);
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2024 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 { SoftwareQuality } from '../../../types/clean-code-taxonomy';
-import { MetricKey } from '../../../types/metrics';
-import { Component, MeasureEnhanced } from '../../../types/types';
-import SoftwareImpactMeasureCard from './SoftwareImpactMeasureCard';
-
-export interface BranchOverallCodePanelProps {
- component: Component;
- measures: MeasureEnhanced[];
-}
-
-export default function BranchOverallCodePanel(props: Readonly<BranchOverallCodePanelProps>) {
- const { component, measures } = props;
-
- return (
- <div className="sw-flex sw-gap-4 sw-mt-4">
- <SoftwareImpactMeasureCard
- component={component}
- softwareQuality={SoftwareQuality.Security}
- ratingMetricKey={MetricKey.security_rating}
- measures={measures}
- />
- <SoftwareImpactMeasureCard
- component={component}
- softwareQuality={SoftwareQuality.Reliability}
- ratingMetricKey={MetricKey.reliability_rating}
- measures={measures}
- />
- <SoftwareImpactMeasureCard
- component={component}
- softwareQuality={SoftwareQuality.Maintainability}
- ratingMetricKey={MetricKey.sqale_rating}
- measures={measures}
- />
- </div>
- );
-}
import { QualityGateStatus, QualityGateStatusCondition } from '../../../types/quality-gates';
import { Component, MeasureEnhanced, Metric, Period, QualityGate } from '../../../types/types';
import '../styles.css';
-import { BRANCH_OVERVIEW_METRICS, HISTORY_METRICS_LIST } from '../utils';
+import { BRANCH_OVERVIEW_METRICS, HISTORY_METRICS_LIST, Status } from '../utils';
import BranchOverviewRenderer from './BranchOverviewRenderer';
interface Props {
(results) => {
if (this.mounted) {
const qgStatuses = results
- .map(({ measures = [], project, projectBranchLike }) => {
+ .map(({ measures = [], project, projectBranchLike }): QualityGateStatus => {
const { key, name, status, caycStatus } = project;
const conditions = extractStatusConditionsFromApplicationStatusChildProject(project);
- const failedConditions = this.getFailedConditions(conditions, measures);
+ const enhancedConditions = this.getEnhancedConditions(conditions, measures);
+ const failedConditions = enhancedConditions.filter((c) => c.level !== Status.OK);
return {
+ conditions: enhancedConditions,
failedConditions,
caycStatus,
key,
if (this.mounted && measures) {
const { ignoredConditions, caycStatus, status } = projectStatus;
const conditions = extractStatusConditionsFromProjectStatus(projectStatus);
- const failedConditions = this.getFailedConditions(conditions, measures);
+ const enhancedConditions = this.getEnhancedConditions(conditions, measures);
+ const failedConditions = enhancedConditions.filter((c) => c.level !== Status.OK);
- const qgStatus = {
+ const qgStatus: QualityGateStatus = {
ignoredConditions,
caycStatus,
+ conditions: enhancedConditions,
failedConditions,
key,
name,
);
};
- getFailedConditions = (conditions: QualityGateStatusCondition[], measures: MeasureEnhanced[]) => {
+ getEnhancedConditions = (
+ conditions: QualityGateStatusCondition[],
+ measures: MeasureEnhanced[],
+ ) => {
return (
conditions
- .filter((c) => c.level !== 'OK')
// Enhance them with Metric information, which will be needed
// to render the conditions properly.
.map((c) => enhanceConditionWithMeasure(c, measures))
import { AnalysisStatus } from '../components/AnalysisStatus';
import SonarLintPromotion from '../components/SonarLintPromotion';
import { MeasuresTabs } from '../utils';
-import AcceptedIssuesPanel from './AcceptedIssuesPanel';
import ActivityPanel from './ActivityPanel';
import BranchMetaTopBar from './BranchMetaTopBar';
-import BranchOverallCodePanel from './BranchOverallCodePanel';
import FirstAnalysisNextStepsNotif from './FirstAnalysisNextStepsNotif';
-import { MeasuresPanel } from './MeasuresPanel';
import MeasuresPanelNoNewCode from './MeasuresPanelNoNewCode';
import NewCodeMeasuresPanel from './NewCodeMeasuresPanel';
import NoCodeWarning from './NoCodeWarning';
+import OverallCodeMeasuresPanel from './OverallCodeMeasuresPanel';
import QualityGatePanel from './QualityGatePanel';
import { TabsPanel } from './TabsPanel';
isNewCode={isNewCodeTab}
onTabSelect={selectTab}
>
- {!hasNewCodeMeasures && isNewCodeTab && (
- <MeasuresPanelNoNewCode
- branch={branch}
- component={component}
- period={period}
- />
- )}
-
{hasNewCodeMeasures &&
isMissingMeasures &&
isApplication(component.qualifier) && (
</FlagMessage>
)}
- {!isNewCodeTab && (
- <BranchOverallCodePanel component={component} measures={measures} />
+ {isNewCodeTab && !hasNewCodeMeasures && (
+ <MeasuresPanelNoNewCode
+ branch={branch}
+ component={component}
+ period={period}
+ />
)}
- {hasNewCodeMeasures && isNewCodeTab && (
+ {isNewCodeTab && hasNewCodeMeasures && (
<NewCodeMeasuresPanel
qgStatuses={qgStatuses}
branch={branch}
/>
)}
- <MeasuresPanel
- branch={branch}
- component={component}
- measures={measures}
- isNewCode={isNewCodeTab}
- />
-
- <AcceptedIssuesPanel
- branch={branch}
- component={component}
- measures={measures}
- isNewCode={isNewCodeTab}
- loading={loadingStatus}
- />
+ {!isNewCodeTab && (
+ <OverallCodeMeasuresPanel
+ branch={branch}
+ qgStatuses={qgStatuses}
+ component={component}
+ measures={measures}
+ />
+ )}
</TabsPanel>
<ActivityPanel
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2024 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 { Card, CoverageIndicator, DuplicationsIndicator } from 'design-system';
-import * as React from 'react';
-import { getTabPanelId } from '../../../components/controls/BoxedTabs';
-import { duplicationRatingConverter } from '../../../components/measure/utils';
-import { findMeasure } from '../../../helpers/measures';
-import { Branch } from '../../../types/branch-like';
-import { IssueType } from '../../../types/issues';
-import { MetricKey } from '../../../types/metrics';
-import { Component, MeasureEnhanced } from '../../../types/types';
-import { MeasurementType, MeasuresTabs } from '../utils';
-import MeasuresPanelIssueMeasure from './MeasuresPanelIssueMeasure';
-import MeasuresPanelPercentMeasure from './MeasuresPanelPercentMeasure';
-
-export interface MeasuresPanelProps {
- branch?: Branch;
- component: Component;
- measures: MeasureEnhanced[];
- isNewCode: boolean;
-}
-
-export function MeasuresPanel(props: MeasuresPanelProps) {
- const { branch, component, measures, isNewCode } = props;
-
- return (
- <div
- className="sw-grid sw-grid-cols-2 sw-gap-4 sw-mt-6"
- id={getTabPanelId(MeasuresTabs.Overall)}
- >
- {[IssueType.Bug, IssueType.CodeSmell, IssueType.Vulnerability, IssueType.SecurityHotspot].map(
- (type: IssueType) => (
- <Card key={type} className="sw-p-8">
- <MeasuresPanelIssueMeasure
- branchLike={branch}
- component={component}
- isNewCodeTab={isNewCode}
- measures={measures}
- type={type}
- />
- </Card>
- ),
- )}
-
- {(findMeasure(measures, MetricKey.coverage) ||
- findMeasure(measures, MetricKey.new_coverage)) && (
- <Card className="sw-p-8" data-test="overview__measures-coverage">
- <MeasuresPanelPercentMeasure
- branchLike={branch}
- component={component}
- measures={measures}
- ratingIcon={renderCoverageIcon}
- secondaryMetricKey={MetricKey.tests}
- type={MeasurementType.Coverage}
- useDiffMetric={isNewCode}
- />
- </Card>
- )}
-
- <Card className="sw-p-8">
- <MeasuresPanelPercentMeasure
- branchLike={branch}
- component={component}
- measures={measures}
- ratingIcon={renderDuplicationIcon}
- secondaryMetricKey={MetricKey.duplicated_blocks}
- type={MeasurementType.Duplication}
- useDiffMetric={isNewCode}
- />
- </Card>
- </div>
- );
-}
-
-export default React.memo(MeasuresPanel);
-
-function renderCoverageIcon(value?: string) {
- return <CoverageIndicator value={value} size="md" />;
-}
-
-function renderDuplicationIcon(value?: string) {
- const rating = value !== undefined ? duplicationRatingConverter(Number(value)) : undefined;
-
- return <DuplicationsIndicator rating={rating} size="md" />;
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2024 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 { LightPrimary, ThemeColors } from 'design-system';
-import * as React from 'react';
-import { translate } from '../../../helpers/l10n';
-import { BranchLike } from '../../../types/branch-like';
-import { ComponentQualifier } from '../../../types/component';
-import { IssueType } from '../../../types/issues';
-import { Component, MeasureEnhanced } from '../../../types/types';
-import IssueLabel from '../components/IssueLabel';
-import IssueRating from '../components/IssueRating';
-import { getIssueIconClass, getIssueRatingName } from '../utils';
-import MeasuresPanelCard from './MeasuresPanelCard';
-
-interface Props {
- branchLike?: BranchLike;
- component: Component;
- isNewCodeTab: boolean;
- measures: MeasureEnhanced[];
- type: IssueType;
-}
-
-export default function MeasuresPanelIssueMeasure(props: Props) {
- const { branchLike, component, isNewCodeTab, measures, type } = props;
-
- const isApp = component.qualifier === ComponentQualifier.Application;
-
- const IconClass = getIssueIconClass(type) as (args: {
- className?: string;
- fill?: ThemeColors;
- }) => JSX.Element;
-
- return (
- <MeasuresPanelCard
- data-test={`overview__measures-${type.toString().toLowerCase()}`}
- category={
- <div className="sw-flex sw-items-center">
- <IconClass className="sw-mr-1" fill="discreetInteractiveIcon" />
- <LightPrimary>{getIssueRatingName(type)}</LightPrimary>
- </div>
- }
- rating={
- !isApp || !isNewCodeTab ? (
- <IssueRating
- branchLike={branchLike}
- component={component}
- measures={measures}
- type={type}
- useDiffMetric={isNewCodeTab}
- />
- ) : null
- }
- >
- <IssueLabel
- branchLike={branchLike}
- component={component}
- helpTooltip={
- type === IssueType.SecurityHotspot
- ? translate('metric.security_hotspots.full_description')
- : undefined
- }
- measures={measures}
- type={type}
- useDiffMetric={isNewCodeTab}
- />
- </MeasuresPanelCard>
- );
-}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2024 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 { getComponentDrilldownUrl } from '../../../helpers/urls';
+import { BranchLike } from '../../../types/branch-like';
+import { isApplication } from '../../../types/component';
+import { MetricKey } from '../../../types/metrics';
+import { QualityGateStatusConditionEnhanced } from '../../../types/quality-gates';
+import { Component, MeasureEnhanced } from '../../../types/types';
+import MeasuresCardPercent from '../components/MeasuresCardPercent';
+import { MeasurementType, getMeasurementMetricKey } from '../utils';
+
+interface Props {
+ useDiffMetric?: boolean;
+ branch?: BranchLike;
+ component: Component;
+ measures: MeasureEnhanced[];
+ failedConditions: QualityGateStatusConditionEnhanced[];
+}
+
+/**
+ * Renders Coverage and Duplication cards for the Overview page.
+ */
+export default function MeasuresPanelPercentCards(props: Readonly<Props>) {
+ const { useDiffMetric, branch, component, measures, failedConditions } = props;
+
+ const isApp = isApplication(component.qualifier);
+
+ return (
+ <div className="sw-grid sw-grid-cols-2 sw-gap-4 sw-mt-4">
+ <MeasuresCardPercent
+ branchLike={branch}
+ componentKey={component.key}
+ conditions={failedConditions}
+ measures={measures}
+ measurementType={MeasurementType.Coverage}
+ label="overview.quality_gate.coverage"
+ url={getComponentDrilldownUrl({
+ componentKey: component.key,
+ metric: getMeasurementMetricKey(MeasurementType.Coverage, Boolean(useDiffMetric)),
+ branchLike: branch,
+ listView: true,
+ })}
+ conditionMetric={useDiffMetric ? MetricKey.new_coverage : MetricKey.coverage}
+ linesMetric={useDiffMetric ? MetricKey.new_lines_to_cover : MetricKey.lines_to_cover}
+ useDiffMetric={useDiffMetric}
+ showRequired={!isApp}
+ />
+
+ <MeasuresCardPercent
+ branchLike={branch}
+ componentKey={component.key}
+ conditions={failedConditions}
+ measures={measures}
+ measurementType={MeasurementType.Duplication}
+ label="overview.quality_gate.duplications"
+ url={getComponentDrilldownUrl({
+ componentKey: component.key,
+ metric: getMeasurementMetricKey(MeasurementType.Duplication, Boolean(useDiffMetric)),
+ branchLike: branch,
+ listView: true,
+ })}
+ conditionMetric={
+ useDiffMetric
+ ? MetricKey.new_duplicated_lines_density
+ : MetricKey.duplicated_lines_density
+ }
+ linesMetric={useDiffMetric ? MetricKey.new_lines : MetricKey.lines}
+ useDiffMetric={useDiffMetric}
+ showRequired={!isApp}
+ />
+ </div>
+ );
+}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2024 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 { DrilldownLink, GreySeparator, LightLabel, LightPrimary } from 'design-system';
-import * as React from 'react';
-import { getLeakValue } from '../../../components/measure/utils';
-import { isPullRequest } from '../../../helpers/branch-like';
-import { getLocalizedMetricName, translate, translateWithParameters } from '../../../helpers/l10n';
-import { findMeasure, formatMeasure, localizeMetric } from '../../../helpers/measures';
-import { getComponentDrilldownUrl } from '../../../helpers/urls';
-import { BranchLike } from '../../../types/branch-like';
-import { MetricKey, MetricType } from '../../../types/metrics';
-import { Component, MeasureEnhanced } from '../../../types/types';
-import AfterMergeEstimate from '../pullRequests/AfterMergeEstimate';
-import { MeasurementType, getMeasurementMetricKey } from '../utils';
-import DrilldownMeasureValue from './DrilldownMeasureValue';
-import MeasuresPanelCard from './MeasuresPanelCard';
-import MeasuresPanelPercentMeasureLabel from './MeasuresPanelPercentMeasureLabel';
-
-interface Props {
- branchLike?: BranchLike;
- component: Component;
- useDiffMetric: boolean;
- measures: MeasureEnhanced[];
- ratingIcon: (value: string | undefined) => React.ReactElement;
- secondaryMetricKey?: MetricKey;
- type: MeasurementType;
-}
-
-export default function MeasuresPanelPercentMeasure(props: Props) {
- const {
- branchLike,
- component,
- measures,
- ratingIcon,
- secondaryMetricKey,
- type,
- useDiffMetric = false,
- } = props;
- const metricKey = getMeasurementMetricKey(type, useDiffMetric);
- const measure = findMeasure(measures, metricKey);
-
- let value;
- if (measure) {
- value = useDiffMetric ? getLeakValue(measure) : measure.value;
- }
-
- const url = getComponentDrilldownUrl({
- componentKey: component.key,
- metric: metricKey,
- branchLike,
- listView: true,
- });
-
- const formattedValue = formatMeasure(value, MetricType.Percent, {
- decimals: 2,
- omitExtraDecimalZeros: true,
- });
-
- return (
- <MeasuresPanelCard
- data-test={`overview__measures-${type.toString().toLowerCase()}`}
- category={<LightPrimary>{translate('overview.measurement_type', type)}</LightPrimary>}
- rating={ratingIcon(value)}
- >
- <>
- <div className="sw-body-md sw-flex sw-items-center sw-mb-3">
- {value === undefined ? (
- <LightLabel aria-label={translate('no_data')}> — </LightLabel>
- ) : (
- <DrilldownLink
- aria-label={translateWithParameters(
- 'overview.see_more_details_on_x_of_y',
- value,
- localizeMetric(metricKey),
- )}
- to={url}
- >
- {formattedValue}
- </DrilldownLink>
- )}
-
- <LightLabel className="sw-ml-2">
- {translate('overview.measurement_type', type)}
- </LightLabel>
- </div>
- <MeasuresPanelPercentMeasureLabel
- component={component}
- measures={measures}
- type={type}
- useDiffMetric={useDiffMetric}
- branchLike={branchLike}
- />
-
- {!useDiffMetric && secondaryMetricKey && (
- <>
- <GreySeparator className="sw-mt-4" />
- <div className="sw-body-md sw-flex sw-items-center sw-mt-4">
- <DrilldownMeasureValue
- branchLike={branchLike}
- component={component}
- measures={measures}
- metric={secondaryMetricKey}
- />
- <LightLabel className="sw-ml-2">
- {getLocalizedMetricName({ key: secondaryMetricKey })}
- </LightLabel>
- </div>
- </>
- )}
-
- {isPullRequest(branchLike) && (
- <div className="sw-body-sm sw-flex sw-items-center sw-mt-4">
- <AfterMergeEstimate measures={measures} type={type} />
-
- <LightLabel className="sw-ml-2">
- {translate('component_measures.facet_category.overall_category.estimated')}
- </LightLabel>
- </div>
- )}
- </>
- </MeasuresPanelCard>
- );
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2024 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 { DrilldownLink, LightLabel } from 'design-system';
-import * as React from 'react';
-import { FormattedMessage } from 'react-intl';
-import { getLeakValue } from '../../../components/measure/utils';
-import { translate } from '../../../helpers/l10n';
-import { findMeasure, formatMeasure } from '../../../helpers/measures';
-import { getComponentDrilldownUrl } from '../../../helpers/urls';
-import { BranchLike } from '../../../types/branch-like';
-import { MetricType } from '../../../types/metrics';
-import { Component, MeasureEnhanced } from '../../../types/types';
-import { MeasurementType, getMeasurementLabelKeys, getMeasurementLinesMetricKey } from '../utils';
-
-interface Props {
- branchLike?: BranchLike;
- component: Component;
- useDiffMetric: boolean;
- measures: MeasureEnhanced[];
- type: MeasurementType;
-}
-
-export default function MeasuresPanelPercentMeasureLabel(props: Props) {
- const { branchLike, component, measures, type, useDiffMetric = false } = props;
- const { expandedLabelKey, labelKey } = getMeasurementLabelKeys(type, useDiffMetric);
- const linesMetric = getMeasurementLinesMetricKey(type, useDiffMetric);
- const measure = findMeasure(measures, linesMetric);
-
- if (!measure) {
- return <LightLabel>{translate(labelKey)}</LightLabel>;
- }
-
- const value = useDiffMetric ? getLeakValue(measure) : measure.value;
-
- const url = getComponentDrilldownUrl({
- componentKey: component.key,
- metric: linesMetric,
- branchLike,
- listView: true,
- });
-
- return (
- <LightLabel>
- <FormattedMessage
- defaultMessage={translate(expandedLabelKey)}
- id={expandedLabelKey}
- values={{
- count: (
- <DrilldownLink className="sw-body-md-highlight" to={url}>
- {formatMeasure(value, MetricType.ShortInteger)}
- </DrilldownLink>
- ),
- }}
- />
- </LightLabel>
- );
-}
import { DEFAULT_ISSUES_QUERY } from '../../../components/shared/utils';
import { getBranchLikeQuery } from '../../../helpers/branch-like';
import { findMeasure, formatMeasure } from '../../../helpers/measures';
-import {
- getComponentDrilldownUrl,
- getComponentIssuesUrl,
- getComponentSecurityHotspotsUrl,
-} from '../../../helpers/urls';
+import { getComponentIssuesUrl, getComponentSecurityHotspotsUrl } from '../../../helpers/urls';
import { Branch } from '../../../types/branch-like';
import { isApplication } from '../../../types/component';
import { IssueStatus } from '../../../types/issues';
import { Component, MeasureEnhanced } from '../../../types/types';
import { IssueMeasuresCardInner } from '../components/IssueMeasuresCardInner';
import MeasuresCardNumber from '../components/MeasuresCardNumber';
-import MeasuresCardPercent from '../components/MeasuresCardPercent';
-import {
- MeasurementType,
- MeasuresTabs,
- Status,
- getConditionRequiredLabel,
- getMeasurementMetricKey,
-} from '../utils';
+import { MeasuresTabs, Status, getConditionRequiredLabel } from '../utils';
+import MeasuresPanelPercentCards from './MeasuresPanelPercentCards';
interface Props {
branch?: Branch;
const intl = useIntl();
const isApp = isApplication(component.qualifier);
+ const conditions = qgStatuses?.flatMap((qg) => qg.conditions) ?? [];
const failedConditions = qgStatuses?.flatMap((qg) => qg.failedConditions) ?? [];
const newIssues = getLeakValue(findMeasure(measures, MetricKey.new_violations));
}
/>
</LightGreyCard>
- <div className="sw-grid sw-grid-cols-2 sw-gap-4 sw-mt-4">
- <MeasuresCardPercent
- branchLike={branch}
- componentKey={component.key}
- conditions={failedConditions}
- measures={measures}
- measurementType={MeasurementType.Coverage}
- label="overview.quality_gate.coverage"
- url={getComponentDrilldownUrl({
- componentKey: component.key,
- metric: getMeasurementMetricKey(MeasurementType.Coverage, true),
- branchLike: branch,
- listView: true,
- })}
- conditionMetric={MetricKey.new_coverage}
- linesMetric={MetricKey.new_lines_to_cover}
- useDiffMetric
- showRequired={!isApp}
- />
- <MeasuresCardPercent
- branchLike={branch}
- componentKey={component.key}
- conditions={failedConditions}
- measures={measures}
- measurementType={MeasurementType.Duplication}
- label="overview.quality_gate.duplications"
- url={getComponentDrilldownUrl({
- componentKey: component.key,
- metric: getMeasurementMetricKey(MeasurementType.Duplication, true),
- branchLike: branch,
- listView: true,
- })}
- conditionMetric={MetricKey.new_duplicated_lines_density}
- linesMetric={MetricKey.new_lines}
- useDiffMetric
- showRequired={!isApp}
- />
+ <MeasuresPanelPercentCards
+ useDiffMetric
+ branch={branch}
+ component={component}
+ measures={measures}
+ failedConditions={failedConditions}
+ />
+ <div className="sw-grid sw-grid-cols-2 sw-gap-4 sw-mt-4">
<MeasuresCardNumber
label={
newSecurityHotspots === '1'
...getBranchLikeQuery(branch),
})}
value={newSecurityHotspots}
- conditions={failedConditions}
+ metric={MetricKey.new_security_hotspots}
+ conditions={conditions}
conditionMetric={MetricKey.new_security_hotspots_reviewed}
showRequired={!isApp}
/>
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2024 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 {
+ MetricsRatingBadge,
+ NoDataIcon,
+ SnoozeCircleIcon,
+ TextSubdued,
+ getTabPanelId,
+} from 'design-system';
+import * as React from 'react';
+import { useIntl } from 'react-intl';
+import { getBranchLikeQuery } from '../../../helpers/branch-like';
+import { findMeasure, formatMeasure, formatRating } from '../../../helpers/measures';
+import { getComponentIssuesUrl, getComponentSecurityHotspotsUrl } from '../../../helpers/urls';
+import { BranchLike } from '../../../types/branch-like';
+import { SoftwareQuality } from '../../../types/clean-code-taxonomy';
+import { isApplication } from '../../../types/component';
+import { IssueStatus } from '../../../types/issues';
+import { MetricKey, MetricType } from '../../../types/metrics';
+import { QualityGateStatus } from '../../../types/quality-gates';
+import { Component, MeasureEnhanced } from '../../../types/types';
+import MeasuresCard from '../components/MeasuresCard';
+import MeasuresCardNumber from '../components/MeasuresCardNumber';
+import { MeasuresTabs } from '../utils';
+import MeasuresPanelPercentCards from './MeasuresPanelPercentCards';
+import SoftwareImpactMeasureCard from './SoftwareImpactMeasureCard';
+
+export interface OverallCodeMeasuresPanelProps {
+ branch?: BranchLike;
+ component: Component;
+ measures: MeasureEnhanced[];
+ qgStatuses?: QualityGateStatus[];
+}
+
+export default function OverallCodeMeasuresPanel(props: Readonly<OverallCodeMeasuresPanelProps>) {
+ const { branch, qgStatuses, component, measures } = props;
+
+ const intl = useIntl();
+
+ const isApp = isApplication(component.qualifier);
+ const conditions = qgStatuses?.flatMap((qg) => qg.conditions) ?? [];
+ const failedConditions = qgStatuses?.flatMap((qg) => qg.failedConditions) ?? [];
+ const acceptedIssues = findMeasure(measures, MetricKey.accepted_issues)?.value;
+ const securityHotspots = findMeasure(measures, MetricKey.security_hotspots)?.value;
+ const securityRating = findMeasure(measures, MetricKey.security_rating)?.value;
+
+ return (
+ <div id={getTabPanelId(MeasuresTabs.Overall)} className="sw-mt-6">
+ <div className="sw-flex sw-gap-4">
+ <SoftwareImpactMeasureCard
+ component={component}
+ softwareQuality={SoftwareQuality.Security}
+ ratingMetricKey={MetricKey.security_rating}
+ measures={measures}
+ />
+ <SoftwareImpactMeasureCard
+ component={component}
+ softwareQuality={SoftwareQuality.Reliability}
+ ratingMetricKey={MetricKey.reliability_rating}
+ measures={measures}
+ />
+ <SoftwareImpactMeasureCard
+ component={component}
+ softwareQuality={SoftwareQuality.Maintainability}
+ ratingMetricKey={MetricKey.sqale_rating}
+ measures={measures}
+ />
+ </div>
+
+ <div className="sw-grid sw-grid-cols-2 sw-gap-4 sw-mt-4">
+ <MeasuresCard
+ url={getComponentIssuesUrl(component.key, {
+ ...getBranchLikeQuery(branch),
+ issueStatuses: IssueStatus.Accepted,
+ })}
+ value={formatMeasure(acceptedIssues, MetricType.ShortInteger)}
+ metric={MetricKey.accepted_issues}
+ label="overview.accepted_issues"
+ failed={false}
+ icon={
+ <SnoozeCircleIcon
+ color={acceptedIssues === '0' ? 'overviewCardDefaultIcon' : 'overviewCardWarningIcon'}
+ />
+ }
+ >
+ <TextSubdued className="sw-body-xs sw-mt-3">
+ {intl.formatMessage({
+ id: 'overview.accepted_issues.help_verbose',
+ })}
+ </TextSubdued>
+ </MeasuresCard>
+
+ <MeasuresCardNumber
+ label={
+ securityHotspots === '1'
+ ? 'issue.type.SECURITY_HOTSPOT'
+ : 'issue.type.SECURITY_HOTSPOT.plural'
+ }
+ url={getComponentSecurityHotspotsUrl(component.key, {
+ ...getBranchLikeQuery(branch),
+ })}
+ value={securityHotspots}
+ metric={MetricKey.security_hotspots}
+ conditions={conditions}
+ conditionMetric={MetricKey.security_hotspots_reviewed}
+ showRequired={!isApp}
+ icon={
+ securityRating ? (
+ <MetricsRatingBadge
+ label={securityRating}
+ rating={formatRating(securityRating)}
+ size="md"
+ />
+ ) : (
+ <NoDataIcon size="md" />
+ )
+ }
+ />
+ </div>
+
+ <MeasuresPanelPercentCards
+ branch={branch}
+ component={component}
+ measures={measures}
+ failedConditions={failedConditions}
+ />
+ </div>
+ );
+}
*/
import styled from '@emotion/styled';
import classNames from 'classnames';
-import { Badge, ContentLink, themeColor } from 'design-system';
+import { Badge, ContentLink, NoDataIcon, themeColor } from 'design-system';
import * as React from 'react';
import { Path } from 'react-router-dom';
import Tooltip from '../../../components/controls/Tooltip';
</ContentLink>
</Tooltip>
</div>
- {icon}
+ {value ? icon : <NoDataIcon size="md" />}
</div>
</div>
{footer}
import { localizeMetric } from '../../../helpers/measures';
import { MetricKey } from '../../../types/metrics';
-interface Props {
+export interface MeasuresCardProps {
url: To;
- value: string;
+ value?: string;
metric: MetricKey;
label: string;
failed?: boolean;
}
export default function MeasuresCard(
- props: React.PropsWithChildren<Props & React.HTMLAttributes<HTMLDivElement>>,
+ props: React.PropsWithChildren<MeasuresCardProps & React.HTMLAttributes<HTMLDivElement>>,
) {
const { failed, children, metric, icon, value, url, label, ...rest } = props;
import { MetricKey, MetricType } from '../../../types/metrics';
import { QualityGateStatusConditionEnhanced } from '../../../types/quality-gates';
import { Status, getConditionRequiredLabel } from '../utils';
-import MeasuresCard from './MeasuresCard';
+import MeasuresCard, { MeasuresCardProps } from './MeasuresCard';
-interface Props {
+interface Props extends MeasuresCardProps {
conditions: QualityGateStatusConditionEnhanced[];
label: string;
url: To;
- value: string;
+ value?: string;
conditionMetric: MetricKey;
showRequired?: boolean;
}
<MeasuresCard
url={url}
value={formatMeasure(value, MetricType.ShortInteger)}
- metric={conditionMetric}
label={label}
failed={conditionFailed}
{...rest}
const value = useDiffMetric
? getLeakValue(findMeasure(measures, metricKey))
: findMeasure(measures, metricKey)?.value;
-
- const linesValue = getLeakValue(findMeasure(measures, linesMetric));
+ const linesValue = useDiffMetric
+ ? getLeakValue(findMeasure(measures, linesMetric))
+ : findMeasure(measures, linesMetric)?.value;
const linesLabel =
measurementType === MeasurementType.Coverage
? 'overview.quality_gate.on_x_new_lines_to_cover'
failed={conditionFailed}
icon={renderIcon(measurementType, value)}
>
- <>
- <span className="sw-body-xs sw-mt-3">
- {showRequired &&
- condition &&
- (conditionFailed ? (
- <TextError
- className="sw-font-regular sw-inline"
- text={getConditionRequiredLabel(condition, intl, true)}
- />
- ) : (
- <LightLabel>{getConditionRequiredLabel(condition, intl)}</LightLabel>
- ))}
- </span>
-
- <div className="sw-flex sw-body-sm sw-justify-between sw-items-center sw-mt-1">
- <LightLabel className="sw-flex sw-items-center sw-gap-1 ">
- <FormattedMessage
- defaultMessage={translate(linesLabel)}
- id={linesLabel}
- values={{
- link: (
- <ContentLink
- aria-label={translateWithParameters(
- 'overview.see_more_details_on_x_y',
- linesValue ?? '0',
- localizeMetric(linesMetric),
- )}
- className="sw-body-md-highlight sw-text-lg"
- to={linesUrl}
- >
- {formatMeasure(linesValue ?? '0', MetricType.ShortInteger)}
- </ContentLink>
- ),
- }}
+ <span className="sw-body-xs sw-mt-3">
+ {showRequired &&
+ condition &&
+ (conditionFailed ? (
+ <TextError
+ className="sw-font-regular sw-inline"
+ text={getConditionRequiredLabel(condition, intl, true)}
/>
- </LightLabel>
- </div>
- </>
+ ) : (
+ <LightLabel>{getConditionRequiredLabel(condition, intl)}</LightLabel>
+ ))}
+ </span>
+
+ <div className="sw-flex sw-body-sm sw-justify-between sw-items-center sw-mt-1">
+ <LightLabel className="sw-flex sw-items-center sw-gap-1 ">
+ <FormattedMessage
+ defaultMessage={translate(linesLabel)}
+ id={linesLabel}
+ values={{
+ link: (
+ <ContentLink
+ aria-label={translateWithParameters(
+ 'overview.see_more_details_on_x_y',
+ linesValue ?? '0',
+ localizeMetric(linesMetric),
+ )}
+ className="sw-body-md-highlight sw-text-lg"
+ to={linesUrl}
+ >
+ {formatMeasure(linesValue ?? '0', MetricType.ShortInteger)}
+ </ContentLink>
+ ),
+ }}
+ />
+ </LightLabel>
+ </div>
</MeasuresCard>
);
}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2024 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 classNames from 'classnames';
-import { LightPrimary } from 'design-system';
-import * as React from 'react';
-import { findMeasure, formatMeasure } from '../../../helpers/measures';
-import { MetricType } from '../../../types/metrics';
-import { MeasureEnhanced } from '../../../types/types';
-import { MeasurementType, getMeasurementAfterMergeMetricKey } from '../utils';
-
-export interface AfterMergeEstimateProps {
- className?: string;
- measures: MeasureEnhanced[];
- type: MeasurementType;
-}
-
-export function AfterMergeEstimate({ className, measures, type }: AfterMergeEstimateProps) {
- const afterMergeMetric = getMeasurementAfterMergeMetricKey(type);
-
- const measure = findMeasure(measures, afterMergeMetric);
-
- if (!measure || measure.value === undefined) {
- return null;
- }
-
- return (
- <div className={classNames(className, 'sw-flex sw-items-center')}>
- <LightPrimary className="sw-body-sm-highlight">
- {formatMeasure(measure.value, MetricType.Percent)}
- </LightPrimary>
- </div>
- );
-}
-
-export default React.memo(AfterMergeEstimate);
...getBranchLikeQuery(pullRequest),
})}
value={newSecurityHotspots}
+ metric={MetricKey.new_security_hotspots}
conditions={conditions}
conditionMetric={MetricKey.new_security_hotspots_reviewed}
showRequired
import { memoize } from 'lodash';
import React from 'react';
import { IntlShape } from 'react-intl';
-import CoverageRating from '../../components/ui/CoverageRating';
-import DuplicationsRating from '../../components/ui/DuplicationsRating';
import { ISSUETYPE_METRIC_KEYS_MAP } from '../../helpers/issues';
import { translate } from '../../helpers/l10n';
import { formatMeasure } from '../../helpers/measures';
[MeasurementType.Coverage]: {
metric: MetricKey.coverage,
newMetric: MetricKey.new_coverage,
- linesMetric: MetricKey.lines_to_cover,
- newLinesMetric: MetricKey.new_lines_to_cover,
- afterMergeMetric: MetricKey.coverage,
- labelKey: 'metric.coverage.name',
- expandedLabelKey: 'overview.coverage_on_X_lines',
- newLinesExpandedLabelKey: 'overview.coverage_on_X_new_lines',
- iconClass: CoverageRating,
},
[MeasurementType.Duplication]: {
metric: MetricKey.duplicated_lines_density,
newMetric: MetricKey.new_duplicated_lines_density,
- linesMetric: MetricKey.ncloc,
- newLinesMetric: MetricKey.new_lines,
- afterMergeMetric: MetricKey.duplicated_lines_density,
- labelKey: 'metric.duplicated_lines_density.short_name',
- expandedLabelKey: 'overview.duplications_on_X_lines',
- newLinesExpandedLabelKey: 'overview.duplications_on_X_new_lines',
- iconClass: DuplicationsRating,
},
};
return translate('metric_domain', ISSUETYPE_METRIC_KEYS_MAP[type].ratingName);
}
-export function getIssueIconClass(type: IssueType) {
- return ISSUETYPE_METRIC_KEYS_MAP[type].iconClass;
-}
-
export function getIssueMetricKey(type: IssueType, useDiffMetric: boolean) {
return useDiffMetric
? ISSUETYPE_METRIC_KEYS_MAP[type].newMetric
: ISSUETYPE_METRIC_KEYS_MAP[type].rating;
}
-export function getMeasurementIconClass(type: MeasurementType) {
- return MEASUREMENTS_MAP[type].iconClass;
-}
-
export function getMeasurementMetricKey(type: MeasurementType, useDiffMetric: boolean) {
return useDiffMetric ? MEASUREMENTS_MAP[type].newMetric : MEASUREMENTS_MAP[type].metric;
}
-export function getMeasurementAfterMergeMetricKey(type: MeasurementType) {
- return MEASUREMENTS_MAP[type].afterMergeMetric;
-}
-
-export function getMeasurementLinesMetricKey(type: MeasurementType, useDiffMetric: boolean) {
- return useDiffMetric ? MEASUREMENTS_MAP[type].newLinesMetric : MEASUREMENTS_MAP[type].linesMetric;
-}
-
-export function getMeasurementLabelKeys(type: MeasurementType, useDiffMetric: boolean) {
- return {
- expandedLabelKey: useDiffMetric
- ? MEASUREMENTS_MAP[type].newLinesExpandedLabelKey
- : MEASUREMENTS_MAP[type].expandedLabelKey,
- labelKey: MEASUREMENTS_MAP[type].labelKey,
- };
-}
-
export const parseQuery = memoize((urlQuery: RawQuery): { codeScope: string } => {
return {
codeScope: parseAsString(urlQuery['code_scope']),
export function mockQualityGateStatus(
overrides: Partial<QualityGateStatus> = {},
): QualityGateStatus {
+ const condition = mockQualityGateStatusConditionEnhanced();
return {
ignoredConditions: false,
caycStatus: CaycStatus.Compliant,
- failedConditions: [mockQualityGateStatusConditionEnhanced()],
+ conditions: [condition],
+ failedConditions: [condition],
key: 'foo',
name: 'Foo',
status: 'ERROR',
}
export interface QualityGateStatus {
+ conditions: QualityGateStatusConditionEnhanced[];
failedConditions: QualityGateStatusConditionEnhanced[];
ignoredConditions?: boolean;
caycStatus: CaycStatus;
issue.type.BUG=Bug
issue.type.VULNERABILITY=Vulnerability
issue.type.SECURITY_HOTSPOT=Security Hotspot
+issue.type.SECURITY_HOTSPOT.plural=Security Hotspots
issue.type.CODE_SMELL.plural=Code Smells
issue.type.BUG.plural=Bugs
issue.type.VULNERABILITY.plural=Vulnerabilities
-issue.type.SECURITY_HOTSPOT.plural=Security Hotspots
issue.type.deprecation.title=Issue types are deprecated and can no longer be modified.
issue.type.deprecation.filter_by=You can now filter issues by:
overview.pull_request.fixed_issues.disclaimer.2=When the pull request and the target branch are not synchronized, issues introduced on the target branch may be incorrectly considered fixed by the pull request. Rebasing the pull request would give an updated value.
overview.accepted_issues=Accepted issues
overview.accepted_issues.help=Valid issues that were not fixed
+overview.accepted_issues.help_verbose=Valid issues, but not fixed. They represent accepted technical debt.
overview.quality_gate.status=Quality Gate Status
overview.quality_gate=Quality Gate
overview.quality_gate_x=Quality Gate: {0}