diff options
author | David Cho-Lerat <david.cho-lerat@sonarsource.com> | 2024-09-18 14:52:23 +0200 |
---|---|---|
committer | sonartech <sonartech@sonarsource.com> | 2024-09-24 20:03:04 +0000 |
commit | 9f80a169ea2c85db1cd8479c42ce609b80aeafaf (patch) | |
tree | 26dcfcc6d66a2e08e81b470fc69325d19b9e07a1 /server/sonar-web/src/main/js/apps/quality-profiles | |
parent | 7869ce9d4981e5ce428aef07bed9e99ca7506f47 (diff) | |
download | sonarqube-9f80a169ea2c85db1cd8479c42ce609b80aeafaf.tar.gz sonarqube-9f80a169ea2c85db1cd8479c42ce609b80aeafaf.zip |
SONAR-23030 Use Heading component
Diffstat (limited to 'server/sonar-web/src/main/js/apps/quality-profiles')
4 files changed, 66 insertions, 34 deletions
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/home/EvolutionDeprecated.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/home/EvolutionDeprecated.tsx index 735bf38a28d..4b3080b4499 100644 --- a/server/sonar-web/src/main/js/apps/quality-profiles/home/EvolutionDeprecated.tsx +++ b/server/sonar-web/src/main/js/apps/quality-profiles/home/EvolutionDeprecated.tsx @@ -17,10 +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 { Heading } from '@sonarsource/echoes-react'; import { DiscreetLink, FlagMessage, Note } from 'design-system'; import { sortBy } from 'lodash'; import * as React from 'react'; import { useIntl } from 'react-intl'; +import { isDefined } from '../../../helpers/types'; import { getDeprecatedActiveRulesUrl } from '../../../helpers/urls'; import { Profile } from '../types'; import { getProfilePath } from '../utils'; @@ -49,9 +52,10 @@ export default function EvolutionDeprecated({ profiles }: Readonly<Props>) { return ( <section aria-label={intl.formatMessage({ id: 'quality_profiles.deprecated_rules' })}> - <h2 className="sw-heading-md sw-mb-6"> + <Heading as="h2" hasMarginBottom> {intl.formatMessage({ id: 'quality_profiles.deprecated_rules' })} - </h2> + </Heading> + <FlagMessage variant="error" className="sw-mb-3"> {intl.formatMessage( { id: 'quality_profiles.deprecated_rules_are_still_activated' }, @@ -70,7 +74,9 @@ export default function EvolutionDeprecated({ profiles }: Readonly<Props>) { <Note> {profile.languageName} + {', '} + <DiscreetLink className="link-no-underline" to={getDeprecatedActiveRulesUrl({ qprofile: profile.key })} @@ -85,6 +91,7 @@ export default function EvolutionDeprecated({ profiles }: Readonly<Props>) { )} </DiscreetLink> </Note> + <EvolutionDeprecatedInherited profile={profile} profilesWithDeprecations={profilesWithDeprecations} @@ -104,31 +111,34 @@ function EvolutionDeprecatedInherited( ) { const { profile, profilesWithDeprecations } = props; const intl = useIntl(); + const rules = React.useMemo( () => getDeprecatedRulesInheritanceChain(profile, profilesWithDeprecations), [profile, profilesWithDeprecations], ); - if (rules.length) { - return ( - <> - {rules.map((rule) => { - if (rule.from.key === profile.key) { - return null; - } - - return ( - <Note key={rule.from.key}> - {intl.formatMessage( - { id: 'coding_rules.filters.inheritance.x_inherited_from_y' }, - { count: rule.count, name: rule.from.name }, - )} - </Note> - ); - })} - </> - ); + + if (rules.length === 0) { + return null; } - return null; + + return ( + <> + {rules.map((rule) => { + if (rule.from.key === profile.key) { + return null; + } + + return ( + <Note key={rule.from.key}> + {intl.formatMessage( + { id: 'coding_rules.filters.inheritance.x_inherited_from_y' }, + { count: rule.count, name: rule.from.name }, + )} + </Note> + ); + })} + </> + ); } function getDeprecatedRulesInheritanceChain(profile: Profile, profilesWithDeprecations: Profile[]) { @@ -139,14 +149,16 @@ function getDeprecatedRulesInheritanceChain(profile: Profile, profilesWithDeprec return rules; } - if (profile.parentKey) { + if (isDefined(profile.parentKey) && profile.parentKey !== '') { const parentProfile = profilesWithDeprecations.find((p) => p.key === profile.parentKey); + if (parentProfile) { const parentRules = getDeprecatedRulesInheritanceChain( parentProfile, profilesWithDeprecations, ); - if (parentRules.length) { + + if (parentRules.length !== 0) { count -= parentRules.reduce((n, rule) => n + rule.count, 0); rules = rules.concat(parentRules); } diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/home/EvolutionRules.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/home/EvolutionRules.tsx index 125155c9f42..0e680661200 100644 --- a/server/sonar-web/src/main/js/apps/quality-profiles/home/EvolutionRules.tsx +++ b/server/sonar-web/src/main/js/apps/quality-profiles/home/EvolutionRules.tsx @@ -17,6 +17,8 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +import { Heading } from '@sonarsource/echoes-react'; import { DiscreetLink, Link, Note } from 'design-system'; import { noop, sortBy } from 'lodash'; import * as React from 'react'; @@ -26,6 +28,7 @@ import { MetricType } from '~sonar-aligned/types/metrics'; import { listRules } from '../../../api/rules'; import { toShortISO8601String } from '../../../helpers/dates'; import { translateWithParameters } from '../../../helpers/l10n'; +import { isDefined } from '../../../helpers/types'; import { getRulesUrl } from '../../../helpers/urls'; import { Rule, RuleActivation } from '../../../types/types'; @@ -39,6 +42,7 @@ export default function EvolutionRules() { const intl = useIntl(); const [latestRules, setLatestRules] = React.useState<ExtendedRule[]>(); const [latestRulesTotal, setLatestRulesTotal] = React.useState<number>(); + const periodStartDate = React.useMemo(() => { const startDate = new Date(); startDate.setFullYear(startDate.getFullYear() - 1); @@ -60,21 +64,23 @@ export default function EvolutionRules() { }, noop); }, [periodStartDate]); - if (!latestRulesTotal || !latestRules) { + if (!(isDefined(latestRulesTotal) && latestRulesTotal !== 0) || !latestRules) { return null; } return ( <section aria-label={intl.formatMessage({ id: 'quality_profiles.latest_new_rules' })}> - <h2 className="sw-heading-md sw-mb-6"> + <Heading as="h2" hasMarginBottom> {intl.formatMessage({ id: 'quality_profiles.latest_new_rules' })} - </h2> + </Heading> + <ul className="sw-flex sw-flex-col sw-gap-4 sw-body-sm"> {latestRules.map((rule) => ( <li className="sw-flex sw-flex-col sw-gap-1" key={rule.key}> <div className="sw-truncate"> <DiscreetLink to={getRulesUrl({ rule_key: rule.key })}>{rule.name}</DiscreetLink> </div> + <Note className="sw-truncate"> {rule.activations ? translateWithParameters( @@ -90,6 +96,7 @@ export default function EvolutionRules() { </li> ))} </ul> + {latestRulesTotal > RULES_LIMIT && ( <div className="sw-mt-6 sw-body-sm-highlight"> <Link to={getRulesUrl({ available_since: periodStartDate })}> @@ -107,6 +114,7 @@ export default function EvolutionRules() { function parseRules(rules: Rule[], actives?: Record<string, RuleActivation[]>): ExtendedRule[] { return rules.map((rule) => { const activations = actives?.[rule.key]?.length ?? 0; + return { ...rule, activations }; }); } diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/home/EvolutionStagnant.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/home/EvolutionStagnant.tsx index e41b60b349d..d44fe4cab52 100644 --- a/server/sonar-web/src/main/js/apps/quality-profiles/home/EvolutionStagnant.tsx +++ b/server/sonar-web/src/main/js/apps/quality-profiles/home/EvolutionStagnant.tsx @@ -17,10 +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 { Heading } from '@sonarsource/echoes-react'; import { DiscreetLink, FlagMessage, Note } from 'design-system'; import * as React from 'react'; import { useIntl } from 'react-intl'; import DateFormatter from '../../../components/intl/DateFormatter'; +import { isDefined } from '../../../helpers/types'; import { Profile } from '../types'; import { getProfilePath, isStagnant } from '../utils'; @@ -28,7 +31,7 @@ interface Props { profiles: Profile[]; } -export default function EvolutionStagnant(props: Props) { +export default function EvolutionStagnant(props: Readonly<Props>) { const intl = useIntl(); const outdated = props.profiles.filter((profile) => !profile.isBuiltIn && isStagnant(profile)); @@ -38,13 +41,14 @@ export default function EvolutionStagnant(props: Props) { return ( <section aria-label={intl.formatMessage({ id: 'quality_profiles.stagnant_profiles' })}> - <h2 className="sw-heading-md sw-mb-6"> + <Heading as="h2" hasMarginBottom> {intl.formatMessage({ id: 'quality_profiles.stagnant_profiles' })} - </h2> + </Heading> <FlagMessage variant="warning" className="sw-mb-3"> {intl.formatMessage({ id: 'quality_profiles.not_updated_more_than_year' })} </FlagMessage> + <ul className="sw-flex sw-flex-col sw-gap-4 sw-body-sm"> {outdated.map((profile) => ( <li className="sw-flex sw-flex-col sw-gap-1" key={profile.key}> @@ -53,7 +57,8 @@ export default function EvolutionStagnant(props: Props) { {profile.name} </DiscreetLink> </div> - {profile.rulesUpdatedAt && ( + + {isDefined(profile.rulesUpdatedAt) && profile.rulesUpdatedAt !== '' && ( <Note> <DateFormatter date={profile.rulesUpdatedAt} long> {(formattedDate) => diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/home/PageHeader.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/home/PageHeader.tsx index 55043a09630..1fd5d6c299a 100644 --- a/server/sonar-web/src/main/js/apps/quality-profiles/home/PageHeader.tsx +++ b/server/sonar-web/src/main/js/apps/quality-profiles/home/PageHeader.tsx @@ -17,8 +17,9 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -import { Button, ButtonGroup, ButtonVariety } from '@sonarsource/echoes-react'; -import { FlagMessage, Link } from 'design-system'; + +import { Button, ButtonGroup, ButtonVariety, Heading, Link } from '@sonarsource/echoes-react'; +import { FlagMessage } from 'design-system'; import * as React from 'react'; import { useIntl } from 'react-intl'; import { useLocation, useRouter } from '~sonar-aligned/components/hoc/withRouter'; @@ -61,7 +62,10 @@ export default function PageHeader(props: Readonly<Props>) { return ( <header className="sw-grid sw-grid-cols-3 sw-gap-12"> <div className="sw-col-span-2"> - <h1 className="sw-heading-lg sw-mb-4">{translate('quality_profiles.page')}</h1> + <Heading as="h1" hasMarginBottom> + {translate('quality_profiles.page')} + </Heading> + <div className="sw-body-sm"> {intl.formatMessage({ id: 'quality_profiles.intro' })} @@ -70,6 +74,7 @@ export default function PageHeader(props: Readonly<Props>) { </Link> </div> </div> + {actions.create && ( <div className="sw-flex sw-flex-col sw-items-end"> <ButtonGroup> @@ -81,10 +86,12 @@ export default function PageHeader(props: Readonly<Props>) { > {intl.formatMessage({ id: 'create' })} </Button> + <Button id="quality-profiles-restore" onClick={() => setModal('restoreProfile')}> {intl.formatMessage({ id: 'restore' })} </Button> </ButtonGroup> + {languages.length === 0 && ( <FlagMessage className="sw-mt-2" variant="warning"> {intl.formatMessage({ id: 'quality_profiles.no_languages_available' })} |