/*
* 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 {
BasicSeparator,
LargeCenteredLayout,
LightGreyCard,
LightGreyCardTitle,
PageContentFontWrapper,
} from 'design-system';
import * as React from 'react';
import A11ySkipTarget from '../../../components/a11y/A11ySkipTarget';
import { useLocation, useRouter } from '../../../components/hoc/withRouter';
import AnalysisMissingInfoMessage from '../../../components/shared/AnalysisMissingInfoMessage';
import { parseDate } from '../../../helpers/dates';
import { areCCTMeasuresComputed, isDiffMetric } from '../../../helpers/measures';
import { CodeScope } from '../../../helpers/urls';
import { ApplicationPeriod } from '../../../types/application';
import { Branch } from '../../../types/branch-like';
import { ComponentQualifier, isPortfolioLike } from '../../../types/component';
import { Analysis, GraphType, MeasureHistory } from '../../../types/project-activity';
import { QualityGateStatus } from '../../../types/quality-gates';
import { Component, MeasureEnhanced, Metric, Period, QualityGate } from '../../../types/types';
import { AnalysisStatus } from '../components/AnalysisStatus';
import LastAnalysisLabel from '../components/LastAnalysisLabel';
import ActivityPanel from './ActivityPanel';
import BranchMetaTopBar from './BranchMetaTopBar';
import FirstAnalysisNextStepsNotif from './FirstAnalysisNextStepsNotif';
import MeasuresPanelNoNewCode from './MeasuresPanelNoNewCode';
import NewCodeMeasuresPanel from './NewCodeMeasuresPanel';
import NoCodeWarning from './NoCodeWarning';
import OverallCodeMeasuresPanel from './OverallCodeMeasuresPanel';
import QualityGatePanel from './QualityGatePanel';
import { QualityGateStatusTitle } from './QualityGateStatusTitle';
import SonarLintPromotion from './SonarLintPromotion';
import { TabsPanel } from './TabsPanel';
export interface BranchOverviewRendererProps {
analyses?: Analysis[];
appLeak?: ApplicationPeriod;
branch?: Branch;
branchesEnabled?: boolean;
component: Component;
detectedCIOnLastAnalysis?: boolean;
graph?: GraphType;
loadingHistory?: boolean;
loadingStatus?: boolean;
measures?: MeasureEnhanced[];
measuresHistory?: MeasureHistory[];
metrics?: Metric[];
onGraphChange: (graph: GraphType) => void;
period?: Period;
projectIsEmpty?: boolean;
qgStatuses?: QualityGateStatus[];
qualityGate?: QualityGate;
}
export default function BranchOverviewRenderer(props: BranchOverviewRendererProps) {
const {
analyses,
appLeak,
branch,
branchesEnabled,
component,
detectedCIOnLastAnalysis,
graph,
loadingHistory,
loadingStatus,
measures = [],
measuresHistory = [],
metrics = [],
onGraphChange,
period,
projectIsEmpty,
qgStatuses,
qualityGate,
} = props;
const { query } = useLocation();
const router = useRouter();
const tab = query.codeScope === CodeScope.Overall ? CodeScope.Overall : CodeScope.New;
const leakPeriod = component.qualifier === ComponentQualifier.Application ? appLeak : period;
const isNewCodeTab = tab === CodeScope.New;
const hasNewCodeMeasures = measures.some((m) => isDiffMetric(m.metric.key));
// Check if any potentially missing uncomputed measure is not present
const isMissingMeasures = !areCCTMeasuresComputed(measures);
const selectTab = (tab: CodeScope) => {
router.replace({ query: { ...query, codeScope: tab } });
};
React.useEffect(() => {
// Open Overall tab by default if there are no new measures.
if (loadingStatus === false && !hasNewCodeMeasures && isNewCodeTab) {
selectTab(CodeScope.Overall);
}
// In this case, we explicitly do NOT want to mark tab as a dependency, as
// it would prevent the user from selecting it, even if it's empty.
/* eslint-disable-next-line react-hooks/exhaustive-deps */
}, [loadingStatus, hasNewCodeMeasures]);
const analysisMissingInfo = isMissingMeasures && (
);
return (
<>
{projectIsEmpty ? (
) : (
{branch && (
<>
>
)}
qg.failedConditions)}
/>
{isNewCodeTab && (
<>
{hasNewCodeMeasures ? (
) : (
)}
>
)}
{!isNewCodeTab && (
<>
{analysisMissingInfo}
>
)}
)}
>
);
}