Przeglądaj źródła

SONAR-19526 Improve accessibility of FlagMessage

tags/10.1.0.73491
Mathieu Suen 11 miesięcy temu
rodzic
commit
2cdcd43dac
17 zmienionych plików z 57 dodań i 144 usunięć
  1. 31
    43
      server/sonar-web/design-system/src/components/FlagMessage.tsx
  2. 7
    7
      server/sonar-web/design-system/src/components/__tests__/FlagMessage-test.tsx
  3. 2
    2
      server/sonar-web/src/main/js/app/components/nav/component/AnalysisStatus.tsx
  4. 1
    5
      server/sonar-web/src/main/js/apps/code/components/CodeAppRenderer.tsx
  5. 1
    1
      server/sonar-web/src/main/js/apps/component-measures/__tests__/ComponentMeasures-it.tsx
  6. 1
    12
      server/sonar-web/src/main/js/apps/component-measures/drilldown/FilesView.tsx
  7. 1
    5
      server/sonar-web/src/main/js/apps/component-measures/sidebar/Sidebar.tsx
  8. 2
    8
      server/sonar-web/src/main/js/apps/issues/components/BulkChangeModal.tsx
  9. 2
    13
      server/sonar-web/src/main/js/apps/issues/components/IssuesApp.tsx
  10. 1
    5
      server/sonar-web/src/main/js/apps/issues/crossComponentSourceViewer/ComponentSourceSnippetGroupViewer.tsx
  11. 2
    10
      server/sonar-web/src/main/js/apps/issues/sidebar/ListStyleFacet.tsx
  12. 1
    7
      server/sonar-web/src/main/js/apps/overview/branches/ApplicationNonCaycProjectWarning.tsx
  13. 1
    4
      server/sonar-web/src/main/js/apps/overview/branches/CleanAsYouCodeWarning.tsx
  14. 1
    5
      server/sonar-web/src/main/js/apps/overview/branches/NoCodeWarning.tsx
  15. 1
    5
      server/sonar-web/src/main/js/apps/overview/components/IgnoredConditionWarning.tsx
  16. 1
    4
      server/sonar-web/src/main/js/components/SourceViewer/components/DuplicationPopup.tsx
  17. 1
    8
      server/sonar-web/src/main/js/components/rules/RuleDescription.tsx

+ 31
- 43
server/sonar-web/design-system/src/components/FlagMessage.tsx Wyświetl plik

@@ -28,64 +28,51 @@ import { FlagErrorIcon, FlagInfoIcon, FlagSuccessIcon, FlagWarningIcon } from '.
export type Variant = 'error' | 'warning' | 'success' | 'info';

interface Props {
ariaLabel: string;
variant: Variant;
}

interface VariantInformation {
backGroundColor: ThemeColors;
borderColor: ThemeColors;
icon: JSX.Element;
role: string;
}

function getVariantInfo(variant: Variant): VariantInformation {
const variantList: Record<Variant, VariantInformation> = {
function getVariantInfo(variant: Variant) {
const variantList = {
error: {
icon: <FlagErrorIcon />,
borderColor: 'errorBorder',
backGroundColor: 'errorBackground',
role: 'alert',
},
warning: {
icon: <FlagWarningIcon />,
borderColor: 'warningBorder',
backGroundColor: 'warningBackground',
role: 'alert',
},
success: {
icon: <FlagSuccessIcon />,
borderColor: 'successBorder',
backGroundColor: 'successBackground',
role: 'status',
},
info: {
icon: <FlagInfoIcon />,
borderColor: 'infoBorder',
backGroundColor: 'infoBackground',
role: 'status',
},
};
} as const;

return variantList[variant];
}

export function FlagMessage(props: Props & React.HTMLAttributes<HTMLDivElement>) {
const { ariaLabel, className, variant, ...domProps } = props;
const { className, variant, ...domProps } = props;
const variantInfo = getVariantInfo(variant);

return (
<StyledFlag
aria-label={ariaLabel}
backGroundColor={variantInfo.backGroundColor}
borderColor={variantInfo.borderColor}
className={classNames('alert', className)}
role={variantInfo.role}
variantInfo={variantInfo}
{...domProps}
>
<StyledFlagInner>
<StyledFlagIcon variantInfo={variantInfo}>{variantInfo.icon}</StyledFlagIcon>
<StyledFlagContent>{props.children}</StyledFlagContent>
</StyledFlagInner>
<div className="flag-inner">
<div className="flag-icon">{variantInfo.icon}</div>
<div className="flag-content">{props.children}</div>
</div>
</StyledFlag>
);
}
@@ -93,32 +80,33 @@ export function FlagMessage(props: Props & React.HTMLAttributes<HTMLDivElement>)
FlagMessage.displayName = 'FlagMessage'; // so that tests don't see the obfuscated production name

export const StyledFlag = styled.div<{
variantInfo: VariantInformation;
backGroundColor: ThemeColors;
borderColor: ThemeColors;
}>`
${tw`sw-inline-flex`}
${tw`sw-min-h-10`}
${tw`sw-rounded-1`}
border: ${({ variantInfo }) => themeBorder('default', variantInfo.borderColor)};
border: ${({ borderColor }) => themeBorder('default', borderColor)};
background-color: ${themeColor('flagMessageBackground')};
`;

const StyledFlagInner = styled.div`
${tw`sw-flex sw-items-stretch`}
${tw`sw-box-border`}
`;
& > .flag-inner {
${tw`sw-flex sw-items-stretch`}
${tw`sw-box-border`}
}

const StyledFlagIcon = styled.div<{ variantInfo: VariantInformation }>`
${tw`sw-flex sw-justify-center sw-items-center`}
${tw`sw-rounded-l-1`}
${tw`sw-px-3`}
background-color: ${({ variantInfo }) => themeColor(variantInfo.backGroundColor)};
`;
& .flag-icon {
${tw`sw-flex sw-justify-center sw-items-center`}
${tw`sw-rounded-l-1`}
${tw`sw-px-3`}
background-color: ${({ backGroundColor }) => themeColor(backGroundColor)};
}

const StyledFlagContent = styled.div`
${tw`sw-flex sw-flex-auto sw-items-center`}
${tw`sw-overflow-auto`}
${tw`sw-text-left`}
${tw`sw-mx-3 sw-my-2`}
${tw`sw-body-sm`}
color: ${themeContrast('flagMessageBackground')};
& .flag-content {
${tw`sw-flex sw-flex-auto sw-items-center`}
${tw`sw-overflow-auto`}
${tw`sw-text-left`}
${tw`sw-mx-3 sw-my-2`}
${tw`sw-body-sm`}
color: ${themeContrast('flagMessageBackground')};
}
`;

+ 7
- 7
server/sonar-web/design-system/src/components/__tests__/FlagMessage-test.tsx Wyświetl plik

@@ -23,21 +23,21 @@ import { FCProps } from '../../types/misc';
import { FlagMessage, Variant } from '../FlagMessage';

it.each([
['error', 'alert', '1px solid rgb(249,112,102)'],
['warning', 'alert', '1px solid rgb(248,205,92)'],
['success', 'status', '1px solid rgb(50,213,131)'],
['info', 'status', '1px solid rgb(110,185,228)'],
])('should render properly for "%s" variant', (variant: Variant, expectedRole, color) => {
['error', '1px solid rgb(249,112,102)'],
['warning', '1px solid rgb(248,205,92)'],
['success', '1px solid rgb(50,213,131)'],
['info', '1px solid rgb(110,185,228)'],
])('should render properly for "%s" variant', (variant: Variant, color) => {
renderFlagMessage({ variant });

const item = screen.getByRole(expectedRole);
const item = screen.getByRole('status');
expect(item).toBeInTheDocument();
expect(item).toHaveStyle({ border: color });
});

function renderFlagMessage(props: Partial<FCProps<typeof FlagMessage>> = {}) {
return render(
<FlagMessage ariaLabel="label" variant="error" {...props}>
<FlagMessage role="status" variant="error" {...props}>
This is an error!
</FlagMessage>
);

+ 2
- 2
server/sonar-web/src/main/js/app/components/nav/component/AnalysisStatus.tsx Wyświetl plik

@@ -63,7 +63,7 @@ export function AnalysisStatus(props: HeaderMetaProps) {
if (currentTask?.status === TaskStatuses.Failed) {
return (
<>
<FlagMessage ariaLabel={translate('alert.tooltip.error')} variant="error">
<FlagMessage variant="error">
<span>{translate('project_navigation.analysis_status.failed')}</span>
<Link className="sw-ml-1" blurAfterClick onClick={openModal} preventDefault to={{}}>
{translate('project_navigation.analysis_status.details_link')}
@@ -84,7 +84,7 @@ export function AnalysisStatus(props: HeaderMetaProps) {
if (warnings.length > 0) {
return (
<>
<FlagMessage ariaLabel={translate('alert.tooltip.warning')} variant="warning">
<FlagMessage variant="warning">
<span>{translate('project_navigation.analysis_status.warnings')}</span>
<Link className="sw-ml-1" blurAfterClick onClick={openModal} preventDefault to={{}}>
{translate('project_navigation.analysis_status.details_link')}

+ 1
- 5
server/sonar-web/src/main/js/apps/code/components/CodeAppRenderer.tsx Wyświetl plik

@@ -120,11 +120,7 @@ export default function CodeAppRenderer(props: Props) {
<A11ySkipTarget anchor="code_main" />

{!canBrowseAllChildProjects && isPortfolio && (
<FlagMessage
ariaLabel={translate('code_viewer.not_all_measures_are_shown')}
variant="warning"
className="it__portfolio_warning sw-mb-4"
>
<FlagMessage variant="warning" className="it__portfolio_warning sw-mb-4">
{translate('code_viewer.not_all_measures_are_shown')}
<HelpTooltip
className="sw-ml-2"

+ 1
- 1
server/sonar-web/src/main/js/apps/component-measures/__tests__/ComponentMeasures-it.tsx Wyświetl plik

@@ -475,7 +475,7 @@ function getPageObject() {
viewSelect: byLabelText('component_measures.view_as'),
emptyText: byText('component_measures.empty'),
detailsUnavailableText: byText('component_measures.details_are_not_available'),
noAccessWarning: byRole('alert'),
noAccessWarning: byText('component_measures.not_all_measures_are_shown'),
showingOutOfTxt: (x: string, y: string) => byText(`x_of_y_shown.${x}.${y}`),
showAllBtn: byRole('button', {
name: 'component_measures.hidden_best_score_metrics_show_label',

+ 1
- 12
server/sonar-web/src/main/js/apps/component-measures/drilldown/FilesView.tsx Wyświetl plik

@@ -181,18 +181,7 @@ export default class FilesView extends React.PureComponent<Props, State> {
view={this.props.view}
/>
{hidingBestMeasures && this.props.paging && (
<FlagMessage
ariaLabel={translateWithParameters(
'component_measures.hidden_best_score_metrics',
formatMeasure(
this.props.paging.total - filteredComponents.length,
MetricType.Integer
),
formatMeasure(this.props.metric.bestValue, this.props.metric.type)
)}
variant="info"
className="sw-mt-4"
>
<FlagMessage variant="info" className="sw-mt-4">
{translateWithParameters(
'component_measures.hidden_best_score_metrics',
formatMeasure(

+ 1
- 5
server/sonar-web/src/main/js/apps/component-measures/sidebar/Sidebar.tsx Wyświetl plik

@@ -90,11 +90,7 @@ export default function Sidebar(props: Props) {
}}
>
{!canBrowseAllChildProjects && isPortfolioLike(qualifier) && (
<FlagMessage
ariaLabel={translate('component_measures.not_all_measures_are_shown')}
className="sw-mt-4 it__portfolio_warning"
variant="warning"
>
<FlagMessage className="sw-mt-4 it__portfolio_warning" variant="warning">
{translate('component_measures.not_all_measures_are_shown')}
<HelpTooltip
className="spacer-left"

+ 2
- 8
server/sonar-web/src/main/js/apps/issues/components/BulkChangeModal.tsx Wyświetl plik

@@ -437,11 +437,7 @@ export default class BulkChangeModal extends React.PureComponent<Props, State> {
<DeferredSpinner loading={loading}>
<form id="bulk-change-form" onSubmit={this.handleSubmit}>
{limitReached && (
<FlagMessage
ariaLabel={translate('alert.tooltip.warning')}
className="sw-mb-4"
variant="warning"
>
<FlagMessage className="sw-mb-4" variant="warning">
<span>
<FormattedMessage
defaultMessage={translate('issue_bulk_change.max_issues_reached')}
@@ -461,9 +457,7 @@ export default class BulkChangeModal extends React.PureComponent<Props, State> {
{this.renderCommentField()}
{issues.length > 0 && this.renderNotificationsField()}
{issues.length === 0 && (
<FlagMessage ariaLabel={translate('alert.tooltip.warning')} variant="warning">
{translate('issue_bulk_change.no_match')}
</FlagMessage>
<FlagMessage variant="warning">{translate('issue_bulk_change.no_match')}</FlagMessage>
)}
</form>
</DeferredSpinner>

+ 2
- 13
server/sonar-web/src/main/js/apps/issues/components/IssuesApp.tsx Wyświetl plik

@@ -1031,7 +1031,6 @@ export class App extends React.PureComponent<Props, State> {

const warning = !canBrowseAllChildProjects && isPortfolioLike(qualifier) && (
<FlagMessage
ariaLabel={translate('issues.not_all_issue_show')}
className="it__portfolio_warning sw-flex"
title={translate('issues.not_all_issue_show_why')}
variant="warning"
@@ -1236,10 +1235,7 @@ export class App extends React.PureComponent<Props, State> {
) : (
<DeferredSpinner loading={loading} ariaLabel={translate('issues.loading_issues')}>
{checkAll && paging && paging.total > MAX_PAGE_SIZE && (
<FlagMessage
ariaLabel={translate('issue_bulk_change.max_issues_reached')}
variant="warning"
>
<FlagMessage variant="warning">
<span>
<FormattedMessage
defaultMessage={translate('issue_bulk_change.max_issues_reached')}
@@ -1251,14 +1247,7 @@ export class App extends React.PureComponent<Props, State> {
)}

{cannotShowOpenIssue && (!paging || paging.total > 0) && (
<FlagMessage
ariaLabel={translateWithParameters(
'issues.cannot_open_issue_max_initial_X_fetched',
MAX_INITAL_FETCH
)}
className="sw-mb-4"
variant="warning"
>
<FlagMessage className="sw-mb-4" variant="warning">
{translateWithParameters(
'issues.cannot_open_issue_max_initial_X_fetched',
MAX_INITAL_FETCH

+ 1
- 5
server/sonar-web/src/main/js/apps/issues/crossComponentSourceViewer/ComponentSourceSnippetGroupViewer.tsx Wyświetl plik

@@ -281,11 +281,7 @@ export default class ComponentSourceSnippetGroupViewer extends React.PureCompone
return (
<>
{issueIsClosed && (
<FlagMessage
className="sw-mb-2 sw-flex"
variant="success"
ariaLabel={translate(closedIssueMessageKey)}
>
<FlagMessage className="sw-mb-2 sw-flex" variant="success">
<div className="sw-block">
<FormattedMessage
id={closedIssueMessageKey}

+ 2
- 10
server/sonar-web/src/main/js/apps/issues/sidebar/ListStyleFacet.tsx Wyświetl plik

@@ -335,11 +335,7 @@ export class ListStyleFacet<S> extends React.Component<Props<S>, State<S>> {
/>

{mightHaveMoreResults && this.state.showFullList && (
<FlagMessage
ariaLabel={translate('facet_might_have_more_results')}
className="sw-flex sw-my-4"
variant="warning"
>
<FlagMessage className="sw-flex sw-my-4" variant="warning">
{translate('facet_might_have_more_results')}
</FlagMessage>
)}
@@ -382,11 +378,7 @@ export class ListStyleFacet<S> extends React.Component<Props<S>, State<S>> {
</FacetItemsList>

{searchMaxResults && (
<FlagMessage
ariaLabel={translate('facet_might_have_more_results')}
className="sw-flex sw-my-4"
variant="warning"
>
<FlagMessage className="sw-flex sw-my-4" variant="warning">
{translate('facet_might_have_more_results')}
</FlagMessage>
)}

+ 1
- 7
server/sonar-web/src/main/js/apps/overview/branches/ApplicationNonCaycProjectWarning.tsx Wyświetl plik

@@ -38,13 +38,7 @@ export default function ApplicationNonCaycProjectWarning({ projects, caycStatus
return (
<Card className="sw-mt-4 sw-body-sm">
{caycStatus === CaycStatus.NonCompliant ? (
<FlagMessage
ariaLabel={translateWithParameters(
'overview.quality_gate.application.non_cayc.projects_x',
projects.length
)}
variant="warning"
>
<FlagMessage variant="warning">
{translateWithParameters(
'overview.quality_gate.application.non_cayc.projects_x',
projects.length

+ 1
- 4
server/sonar-web/src/main/js/apps/overview/branches/CleanAsYouCodeWarning.tsx Wyświetl plik

@@ -34,10 +34,7 @@ export default function CleanAsYouCodeWarning({ component }: Props) {

return (
<>
<FlagMessage
ariaLabel={translate('overview.quality_gate.conditions.cayc.warning')}
variant="warning"
>
<FlagMessage variant="warning">
{translate('overview.quality_gate.conditions.cayc.warning')}
</FlagMessage>
{component.qualityGate ? (

+ 1
- 5
server/sonar-web/src/main/js/apps/overview/branches/NoCodeWarning.tsx Wyświetl plik

@@ -83,11 +83,7 @@ export function NoCodeWarning({ branchLike, component, measures }: Props) {
}
/* eslint-enable no-lonely-if */

return (
<FlagMessage ariaLabel={title} variant="warning">
{title}
</FlagMessage>
);
return <FlagMessage variant="warning">{title}</FlagMessage>;
}

export default React.memo(NoCodeWarning);

+ 1
- 5
server/sonar-web/src/main/js/apps/overview/components/IgnoredConditionWarning.tsx Wyświetl plik

@@ -25,11 +25,7 @@ import { translate } from '../../../helpers/l10n';

export default function IgnoredConditionWarning() {
return (
<FlagMessage
ariaLabel={translate('overview.quality_gate.ignored_conditions')}
className="sw-mb-4"
variant="info"
>
<FlagMessage className="sw-mb-4" variant="info">
<span>{translate('overview.quality_gate.ignored_conditions')}</span>
<HelpTooltip
className="sw-ml-2"

+ 1
- 4
server/sonar-web/src/main/js/components/SourceViewer/components/DuplicationPopup.tsx Wyświetl plik

@@ -112,10 +112,7 @@ export default class DuplicationPopup extends PureComponent<Props> {
return (
<div className="sw-w-abs-400">
{inRemovedComponent && (
<FlagMessage
ariaLabel={translate('duplications.dups_found_on_deleted_resource')}
variant="warning"
>
<FlagMessage variant="warning">
{translate('duplications.dups_found_on_deleted_resource')}
</FlagMessage>
)}

+ 1
- 8
server/sonar-web/src/main/js/components/rules/RuleDescription.tsx Wyświetl plik

@@ -128,14 +128,7 @@ export default class RuleDescription extends React.PureComponent<Props, State> {
{translate('coding_rules.description_context.title')}
</h2>
{defaultContext && (
<FlagMessage
variant="info"
className="sw-mb-4"
ariaLabel={translateWithParameters(
'coding_rules.description_context.default_information',
defaultContext.displayName
)}
>
<FlagMessage variant="info" className="sw-mb-4">
{translateWithParameters(
'coding_rules.description_context.default_information',
defaultContext.displayName

Ładowanie…
Anuluj
Zapisz