@@ -21,6 +21,7 @@ import styled from '@emotion/styled'; | |||
import * as React from 'react'; | |||
import tw from 'twin.macro'; | |||
import { themeBorder, themeColor } from '../helpers/theme'; | |||
import { BasicSeparator } from './Separator'; | |||
interface CardProps extends React.HTMLAttributes<HTMLDivElement> { | |||
children: React.ReactNode; | |||
@@ -44,6 +45,17 @@ export function LightGreyCard(props: Readonly<CardProps>) { | |||
return <LightGreyCardStyled {...rest}>{children}</LightGreyCardStyled>; | |||
} | |||
export function LightGreyCardTitle({ children }: Readonly<React.PropsWithChildren>) { | |||
return ( | |||
<> | |||
<div className="sw-flex sw-items-center sw-justify-between sw-w-full sw-mb-4 sw-min-h-6"> | |||
{children} | |||
</div> | |||
<BasicSeparator className="sw--mx-6 sw-my-0" /> | |||
</> | |||
); | |||
} | |||
export const CardWithPrimaryBackground = styled(Card)` | |||
background-color: ${themeColor('backgroundPrimary')}; | |||
`; |
@@ -21,6 +21,7 @@ import { | |||
BasicSeparator, | |||
LargeCenteredLayout, | |||
LightGreyCard, | |||
LightGreyCardTitle, | |||
PageContentFontWrapper, | |||
} from 'design-system'; | |||
import * as React from 'react'; | |||
@@ -37,6 +38,7 @@ import { Analysis, GraphType, MeasureHistory } from '../../../types/project-acti | |||
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'; | |||
@@ -45,6 +47,7 @@ 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'; | |||
@@ -141,9 +144,10 @@ export default function BranchOverviewRenderer(props: BranchOverviewRendererProp | |||
</> | |||
)} | |||
<AnalysisStatus className="sw-mt-6" component={component} /> | |||
<div className="sw-flex sw-mt-6"> | |||
<div className="sw-w-1/4 sw-mr-3"> | |||
<LightGreyCard className="sw-h-max"> | |||
<div className="sw-flex sw-gap-3 sw-mt-6"> | |||
<div className="sw-w-1/4"> | |||
<LightGreyCard> | |||
<QualityGateStatusTitle /> | |||
<QualityGatePanel | |||
component={component} | |||
loading={loadingStatus} | |||
@@ -156,15 +160,18 @@ export default function BranchOverviewRenderer(props: BranchOverviewRendererProp | |||
/> | |||
</div> | |||
<LightGreyCard className="sw-flex-1"> | |||
<div className="sw-flex sw-flex-col"> | |||
<div className="sw-flex-1"> | |||
<LightGreyCard className="sw-flex sw-flex-col"> | |||
<LightGreyCardTitle> | |||
<div> </div> | |||
<LastAnalysisLabel analysisDate={branch?.analysisDate} /> | |||
</LightGreyCardTitle> | |||
<TabsPanel | |||
analyses={analyses} | |||
appLeak={appLeak} | |||
component={component} | |||
loading={loadingStatus} | |||
period={period} | |||
branch={branch} | |||
qgStatuses={qgStatuses} | |||
isNewCode={isNewCodeTab} | |||
onTabSelect={selectTab} | |||
@@ -212,8 +219,8 @@ export default function BranchOverviewRenderer(props: BranchOverviewRendererProp | |||
metrics={metrics} | |||
onGraphChange={onGraphChange} | |||
/> | |||
</div> | |||
</LightGreyCard> | |||
</LightGreyCard> | |||
</div> | |||
</div> | |||
</div> | |||
)} |
@@ -28,7 +28,6 @@ import CleanAsYouCodeWarning from './CleanAsYouCodeWarning'; | |||
import QualityGatePanelSection from './QualityGatePanelSection'; | |||
import QualityGateStatusHeader from './QualityGateStatusHeader'; | |||
import QualityGateStatusPassedView from './QualityGateStatusPassedView'; | |||
import { QualityGateStatusTitle } from './QualityGateStatusTitle'; | |||
export interface QualityGatePanelProps { | |||
component: Pick<Component, 'key' | 'qualifier' | 'qualityGate'>; | |||
@@ -68,7 +67,6 @@ export function QualityGatePanel(props: QualityGatePanelProps) { | |||
return ( | |||
<div data-testid="overview__quality-gate-panel"> | |||
<QualityGateStatusTitle /> | |||
<div className="sw-pt-5"> | |||
<Spinner loading={loading}> | |||
<QualityGateStatusHeader |
@@ -17,26 +17,23 @@ | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
import { BasicSeparator, HelperHintIcon, PageTitle } from 'design-system'; | |||
import { HelperHintIcon, LightGreyCardTitle, PageTitle } from 'design-system'; | |||
import React from 'react'; | |||
import HelpTooltip from '../../../components/controls/HelpTooltip'; | |||
import { translate } from '../../../helpers/l10n'; | |||
export function QualityGateStatusTitle() { | |||
return ( | |||
<> | |||
<div className="sw-flex sw-items-center sw-mb-4 sw--mt-2"> | |||
<div className="sw-flex sw-items-center"> | |||
<PageTitle as="h2" text={translate('overview.quality_gate.status')} /> | |||
<HelpTooltip | |||
className="sw-ml-2" | |||
overlay={<div className="sw-my-4">{translate('overview.quality_gate.help')}</div>} | |||
> | |||
<HelperHintIcon aria-label="help-tooltip" /> | |||
</HelpTooltip> | |||
</div> | |||
<LightGreyCardTitle> | |||
<div className="sw-flex sw-items-center"> | |||
<PageTitle as="h2" text={translate('overview.quality_gate.status')} /> | |||
<HelpTooltip | |||
className="sw-ml-2" | |||
overlay={<div className="sw-my-4">{translate('overview.quality_gate.help')}</div>} | |||
> | |||
<HelperHintIcon aria-label="help-tooltip" /> | |||
</HelpTooltip> | |||
</div> | |||
<BasicSeparator className="sw--mx-6" /> | |||
</> | |||
</LightGreyCardTitle> | |||
); | |||
} |
@@ -20,7 +20,7 @@ | |||
import styled from '@emotion/styled'; | |||
import { LinkHighlight, LinkStandalone } from '@sonarsource/echoes-react'; | |||
import classNames from 'classnames'; | |||
import { Badge, BasicSeparator, LightGreyCard, TextBold, TextSubdued } from 'design-system'; | |||
import { Badge, LightGreyCard, LightGreyCardTitle, TextBold, TextSubdued } from 'design-system'; | |||
import * as React from 'react'; | |||
import { FormattedMessage, useIntl } from 'react-intl'; | |||
import Tooltip from '../../../components/controls/Tooltip'; | |||
@@ -101,17 +101,16 @@ export function SoftwareImpactMeasureCard(props: Readonly<SoftwareImpactBreakdow | |||
data-testid={`overview__software-impact-card-${softwareQuality}`} | |||
className="sw-w-1/3 sw-overflow-hidden sw-rounded-2 sw-p-4 sw-flex-col" | |||
> | |||
<div className="sw-flex sw-justify-between"> | |||
<LightGreyCardTitle> | |||
<TextBold name={intl.formatMessage({ id: `software_quality.${softwareQuality}` })} /> | |||
{failed && ( | |||
<Badge className="sw-h-fit" variant="deleted"> | |||
<FormattedMessage id="overview.measures.failed_badge" /> | |||
</Badge> | |||
)} | |||
</div> | |||
<BasicSeparator className="sw--mx-4" /> | |||
</LightGreyCardTitle> | |||
<div className="sw-flex sw-flex-col sw-gap-3"> | |||
<div className="sw-flex sw-mt-2"> | |||
<div className="sw-flex sw-mt-4"> | |||
<div | |||
className={classNames('sw-flex sw-gap-1 sw-items-center', { | |||
'sw-opacity-60': component.needIssueSync, |
@@ -19,7 +19,7 @@ | |||
*/ | |||
import { Spinner } from '@sonarsource/echoes-react'; | |||
import { isBefore, sub } from 'date-fns'; | |||
import { BasicSeparator, ButtonLink, FlagMessage, LightLabel, Tabs } from 'design-system'; | |||
import { ButtonLink, FlagMessage, LightLabel, Tabs } from 'design-system'; | |||
import * as React from 'react'; | |||
import { FormattedMessage } from 'react-intl'; | |||
import DocumentationLink from '../../../components/common/DocumentationLink'; | |||
@@ -27,12 +27,10 @@ import { translate } from '../../../helpers/l10n'; | |||
import { isDiffMetric } from '../../../helpers/measures'; | |||
import { CodeScope } from '../../../helpers/urls'; | |||
import { ApplicationPeriod } from '../../../types/application'; | |||
import { Branch } from '../../../types/branch-like'; | |||
import { ComponentQualifier } from '../../../types/component'; | |||
import { Analysis, ProjectAnalysisEventCategory } from '../../../types/project-activity'; | |||
import { QualityGateStatus } from '../../../types/quality-gates'; | |||
import { Component, Period } from '../../../types/types'; | |||
import LastAnalysisLabel from '../components/LastAnalysisLabel'; | |||
import { MAX_ANALYSES_NB } from './ActivityPanel'; | |||
import { LeakPeriodInfo } from './LeakPeriodInfo'; | |||
@@ -42,7 +40,6 @@ export interface MeasuresPanelProps { | |||
component: Component; | |||
loading?: boolean; | |||
period?: Period; | |||
branch?: Branch; | |||
qgStatuses?: QualityGateStatus[]; | |||
isNewCode: boolean; | |||
onTabSelect: (tab: CodeScope) => void; | |||
@@ -59,7 +56,6 @@ export function TabsPanel(props: React.PropsWithChildren<MeasuresPanelProps>) { | |||
period, | |||
qgStatuses = [], | |||
isNewCode, | |||
branch, | |||
children, | |||
} = props; | |||
const isApp = component.qualifier === ComponentQualifier.Application; | |||
@@ -123,12 +119,7 @@ export function TabsPanel(props: React.PropsWithChildren<MeasuresPanelProps>) { | |||
]; | |||
return ( | |||
<div data-testid="overview__measures-panel"> | |||
<div className="sw-flex sw-justify-end sw-items-center sw-mb-4"> | |||
<LastAnalysisLabel analysisDate={branch?.analysisDate} /> | |||
</div> | |||
<BasicSeparator className="sw--mx-6 sw-mb-3" /> | |||
<div className="sw-mt-3" data-testid="overview__measures-panel"> | |||
{loading ? ( | |||
<div> | |||
<Spinner isLoading={loading} /> |