@@ -28,13 +28,17 @@ import { FormattedMessage } from 'react-intl'; | |||
import DocumentationLink from '../../../components/common/DocumentationLink'; | |||
import { translate } from '../../../helpers/l10n'; | |||
import { OPTIMIZED_CAYC_CONDITIONS } from '../utils'; | |||
import QGRecommendedIcon from './QGRecommendedIcon'; | |||
export default function CaycCompliantBanner() { | |||
return ( | |||
<CardWithPrimaryBackground className="sw-mb-9 sw-p-8"> | |||
<SubHeadingHighlight className="sw-mb-2"> | |||
{translate('quality_gates.cayc.banner.title')} | |||
</SubHeadingHighlight> | |||
<div className="sw-flex sw-items-center sw-mb-2"> | |||
<QGRecommendedIcon className="sw-mr-2" /> | |||
<SubHeadingHighlight className="sw-m-0"> | |||
{translate('quality_gates.cayc.banner.title')} | |||
</SubHeadingHighlight> | |||
</div> | |||
<div> | |||
<FormattedMessage |
@@ -23,6 +23,7 @@ import { | |||
HeadingDark, | |||
HelperHintIcon, | |||
HighlightedSection, | |||
LightLabel, | |||
LightPrimary, | |||
Link, | |||
Note, | |||
@@ -34,6 +35,7 @@ import * as React from 'react'; | |||
import { FormattedMessage } from 'react-intl'; | |||
import { useAvailableFeatures } from '../../../app/components/available-features/withAvailableFeatures'; | |||
import { useMetrics } from '../../../app/components/metrics/withMetricsContext'; | |||
import DocumentationLink from '../../../components/common/DocumentationLink'; | |||
import DocumentationTooltip from '../../../components/common/DocumentationTooltip'; | |||
import ModalButton, { ModalProps } from '../../../components/controls/ModalButton'; | |||
import { useDocUrl } from '../../../helpers/docs'; | |||
@@ -49,6 +51,7 @@ import CaycCondition from './CaycCondition'; | |||
import CaycFixOptimizeBanner from './CaycFixOptimizeBanner'; | |||
import CaycReviewUpdateConditionsModal from './ConditionReviewAndUpdateModal'; | |||
import ConditionsTable from './ConditionsTable'; | |||
import QGRecommendedIcon from './QGRecommendedIcon'; | |||
interface Props { | |||
qualityGate: QualityGate; | |||
@@ -145,6 +148,25 @@ export default function Conditions({ qualityGate, isFetching }: Readonly<Props>) | |||
<div> | |||
<CaYCConditionsSimplificationGuide qualityGate={qualityGate} /> | |||
{qualityGate.isBuiltIn && ( | |||
<div className="sw-flex sw-items-center sw-mt-2 sw-mb-9"> | |||
<QGRecommendedIcon className="sw-mr-1" /> | |||
<LightLabel> | |||
<FormattedMessage | |||
defaultMessage="quality_gates.is_built_in.cayc.description" | |||
id="quality_gates.is_built_in.cayc.description" | |||
values={{ | |||
link: ( | |||
<DocumentationLink to="/user-guide/clean-as-you-code/"> | |||
{translate('clean_as_you_code')} | |||
</DocumentationLink> | |||
), | |||
}} | |||
/> | |||
</LightLabel> | |||
</div> | |||
)} | |||
{isCompliantCustomQualityGate && !isOptimizing && <CaycCompliantBanner />} | |||
{isCompliantCustomQualityGate && isOptimizing && canEdit && ( | |||
<CaycFixOptimizeBanner renderCaycModal={renderCaycModal} isOptimizing /> |
@@ -22,23 +22,18 @@ import { | |||
Badge, | |||
ButtonSecondary, | |||
DangerButtonPrimary, | |||
FlagWarningIcon, | |||
ItemButton, | |||
ItemDangerButton, | |||
ItemDivider, | |||
LightLabel, | |||
SubTitle, | |||
} from 'design-system'; | |||
import { countBy } from 'lodash'; | |||
import * as React from 'react'; | |||
import { FormattedMessage } from 'react-intl'; | |||
import DocumentationLink from '../../../components/common/DocumentationLink'; | |||
import Tooltip from '../../../components/controls/Tooltip'; | |||
import { translate } from '../../../helpers/l10n'; | |||
import { useSetQualityGateAsDefaultMutation } from '../../../queries/quality-gates'; | |||
import { CaycStatus, QualityGate } from '../../../types/types'; | |||
import BuiltInQualityGateBadge from './BuiltInQualityGateBadge'; | |||
import CaycBadgeTooltip from './CaycBadgeTooltip'; | |||
import CopyQualityGateForm from './CopyQualityGateForm'; | |||
import DeleteQualityGateForm from './DeleteQualityGateForm'; | |||
import RenameQualityGateForm from './RenameQualityGateForm'; | |||
@@ -47,8 +42,6 @@ interface Props { | |||
qualityGate: QualityGate; | |||
} | |||
const TOOLTIP_MOUSE_LEAVE_DELAY = 0.3; | |||
export default function DetailsHeader({ qualityGate }: Readonly<Props>) { | |||
const [isRenameFormOpen, setIsRenameFormOpen] = React.useState(false); | |||
const [isCopyFormOpen, setIsCopyFormOpen] = React.useState(false); | |||
@@ -60,7 +53,6 @@ export default function DetailsHeader({ qualityGate }: Readonly<Props>) { | |||
actions.delete, | |||
actions.setAsDefault, | |||
])['true']; | |||
const canEdit = Boolean(actions?.manageConditions); | |||
const { mutateAsync: setQualityGateAsDefault } = useSetQualityGateAsDefaultMutation(); | |||
const handleSetAsDefaultClick = () => { | |||
@@ -75,46 +67,11 @@ export default function DetailsHeader({ qualityGate }: Readonly<Props>) { | |||
<div className="sw-flex sw-flex-col"> | |||
<div className="sw-flex sw-items-baseline"> | |||
<SubTitle className="sw-m-0">{qualityGate.name}</SubTitle> | |||
{qualityGate.caycStatus === CaycStatus.NonCompliant && canEdit && ( | |||
<Tooltip overlay={<CaycBadgeTooltip />} mouseLeaveDelay={TOOLTIP_MOUSE_LEAVE_DELAY}> | |||
<FlagWarningIcon className="sw-ml-2" description={<CaycBadgeTooltip />} /> | |||
</Tooltip> | |||
)} | |||
<div className="sw-flex sw-gap-2 sw-ml-4"> | |||
{qualityGate.isDefault && <Badge>{translate('default')}</Badge>} | |||
{qualityGate.isBuiltIn && <BuiltInQualityGateBadge />} | |||
</div> | |||
</div> | |||
{qualityGate.isBuiltIn && ( | |||
<> | |||
<LightLabel className="sw-mt-2"> | |||
<FormattedMessage | |||
defaultMessage="quality_gates.is_built_in.cayc.description" | |||
id="quality_gates.is_built_in.cayc.description" | |||
values={{ | |||
link: ( | |||
<DocumentationLink to="/user-guide/clean-as-you-code/"> | |||
{translate('clean_as_you_code')} | |||
</DocumentationLink> | |||
), | |||
}} | |||
/> | |||
</LightLabel> | |||
<span className="sw-mt-9"> | |||
<FormattedMessage | |||
defaultMessage="quality_gates.is_built_in.description" | |||
id="quality_gates.is_built_in.description" | |||
values={{ | |||
link: ( | |||
<DocumentationLink to="/user-guide/quality-gates/#using-sonar-way-the-recommended-quality-gate"> | |||
{translate('learn_more')} | |||
</DocumentationLink> | |||
), | |||
}} | |||
/> | |||
</span> | |||
</> | |||
)} | |||
</div> | |||
{actionsCount === 1 && ( | |||
<> |
@@ -17,13 +17,7 @@ | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
import { | |||
Badge, | |||
BareButton, | |||
FlagWarningIcon, | |||
SubnavigationGroup, | |||
SubnavigationItem, | |||
} from 'design-system'; | |||
import { Badge, BareButton, SubnavigationGroup, SubnavigationItem } from 'design-system'; | |||
import * as React from 'react'; | |||
import { useNavigate } from 'react-router-dom'; | |||
import Tooltip from '../../../components/controls/Tooltip'; | |||
@@ -32,6 +26,7 @@ import { translate } from '../../../helpers/l10n'; | |||
import { getQualityGateUrl } from '../../../helpers/urls'; | |||
import { CaycStatus, QualityGate } from '../../../types/types'; | |||
import BuiltInQualityGateBadge from './BuiltInQualityGateBadge'; | |||
import QGRecommendedIcon from './QGRecommendedIcon'; | |||
interface Props { | |||
qualityGates: QualityGate[]; | |||
@@ -80,12 +75,13 @@ export default function List({ qualityGates, currentQualityGate }: Props) { | |||
</div> | |||
)} | |||
</div> | |||
{qualityGate.caycStatus === CaycStatus.NonCompliant && | |||
qualityGate.actions?.manageConditions && ( | |||
<Tooltip overlay={translate('quality_gates.cayc.tooltip.message')}> | |||
<FlagWarningIcon description={translate('quality_gates.cayc.tooltip.message')} /> | |||
</Tooltip> | |||
)} | |||
{qualityGate.caycStatus !== CaycStatus.NonCompliant && ( | |||
<Tooltip overlay={translate('quality_gates.cayc.tooltip.message')}> | |||
<span> | |||
<QGRecommendedIcon /> | |||
</span> | |||
</Tooltip> | |||
)} | |||
</SubnavigationItem> | |||
); | |||
})} |
@@ -17,19 +17,13 @@ | |||
* 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 DocumentationLink from '../../../components/common/DocumentationLink'; | |||
import { translate } from '../../../helpers/l10n'; | |||
export default function CaycBadgeTooltip() { | |||
return ( | |||
<div> | |||
<p className="sw-mb-2 sw-pb-2 bordered-bottom-cayc"> | |||
{translate('quality_gates.cayc.tooltip.message')} | |||
</p> | |||
<DocumentationLink to="/user-guide/clean-as-you-code/"> | |||
{translate('quality_gates.cayc.badge.tooltip.learn_more')} | |||
</DocumentationLink> | |||
</div> | |||
); | |||
} | |||
import styled from '@emotion/styled'; | |||
import { IconRecommended } from '@sonarsource/echoes-react'; | |||
import { themeColor } from 'design-system'; | |||
const QGRecommendedIcon = styled(IconRecommended)` | |||
color: ${themeColor('primary')}; | |||
`; | |||
export default QGRecommendedIcon; |
@@ -82,7 +82,6 @@ it('should render the built-in quality gate properly', async () => { | |||
await user.click(builtInQualityGate); | |||
expect(await screen.findByText(/quality_gates.is_built_in.cayc.description/)).toBeInTheDocument(); | |||
expect(await screen.findByText(/quality_gates.is_built_in.description/)).toBeInTheDocument(); | |||
}); | |||
it('should be able to create a quality gate then delete it', async () => { | |||
@@ -424,7 +423,6 @@ it('should not warn user when quality gate is not CaYC compliant and user has no | |||
await user.click(nonCompliantQualityGate); | |||
expect(screen.queryByRole('alert')).not.toBeInTheDocument(); | |||
expect(screen.queryByText('quality_gates.cayc.tooltip.message')).not.toBeInTheDocument(); | |||
}); | |||
it('should not show optimize banner when quality gate is compliant but non-CaYC and user has no permission to edit it', async () => { | |||
@@ -438,7 +436,6 @@ it('should not show optimize banner when quality gate is compliant but non-CaYC | |||
await user.click(nonCompliantQualityGate); | |||
expect(screen.queryByRole('alert')).not.toBeInTheDocument(); | |||
expect(screen.queryByText('quality_gates.cayc.tooltip.message')).not.toBeInTheDocument(); | |||
}); | |||
it('should warn user when quality gate is not CaYC compliant and user has permission to edit it', async () => { | |||
@@ -449,7 +446,6 @@ it('should warn user when quality gate is not CaYC compliant and user has permis | |||
const nonCompliantQualityGate = await screen.findByRole('button', { name: /Non Cayc QG/ }); | |||
await user.click(nonCompliantQualityGate); | |||
// expect(screen.getByTestId('conditions')).toMatchSnapshot(); | |||
expect(await screen.findByText(/quality_gates.cayc_missing.banner.title/)).toBeInTheDocument(); | |||
expect(screen.getAllByText('quality_gates.cayc.tooltip.message').length).toBeGreaterThan(0); |
@@ -2317,7 +2317,7 @@ quality_gates.cayc.new_maintainability_rating=Technical debt ratio is greater th | |||
quality_gates.cayc.new_reliability_rating.A=No bugs | |||
quality_gates.cayc.new_security_rating.A=No vulnerabilities | |||
quality_gates.cayc.unlock_edit=Unlock editing | |||
quality_gates.cayc.tooltip.message=This quality gate does not comply with Clean as You Code. | |||
quality_gates.cayc.tooltip.message=This quality gate is configured for Clean as You Code. | |||
quality_gates.cayc.badge.tooltip.learn_more=Learn more: Clean as You Code | |||
quality_gates.cayc.banner.title=This quality gate complies with Clean as You Code | |||
quality_gates.cayc.banner.description1=This quality gate complies with the {cayc_link} methodology, so that you benefit from the most efficient approach to delivering Clean Code. |