Compare commits

..

1 Commits

Author SHA1 Message Date
Cyril d8d655cc3d ️(frontend) structure 5xx error alerts
Use h1/p for 500/502/503; pass status from doc and version views.
2026-03-25 11:59:19 +01:00
9 changed files with 67 additions and 4 deletions
+1 -2
View File
@@ -13,8 +13,7 @@ and this project adheres to
### Changed
- 💄(frontend) improve comments highlights #1961
- ♿(frontend) use aria-haspopup menu on DropButton triggers
#2126
-(frontend) structure correctly 5xx error alerts #2128
## [v4.8.3] - 2026-03-23
@@ -93,7 +93,7 @@ export const DropButton = ({
onOpenChangeHandler(true);
}}
aria-label={label}
aria-haspopup="menu"
aria-haspopup="true"
aria-expanded={isLocalOpen}
data-testid={testId}
$css={css`
@@ -4,6 +4,7 @@ import { useTranslation } from 'react-i18next';
import styled from 'styled-components';
import { Box, Text, TextType } from '@/components';
import { useHttpErrorMessages } from '@/hooks';
const AlertStyled = styled(Alert)`
& .c__button--tertiary:hover {
@@ -16,6 +17,7 @@ interface TextErrorsProps extends TextType {
defaultMessage?: string;
icon?: ReactNode;
canClose?: boolean;
status?: number;
}
export const TextErrors = ({
@@ -23,6 +25,7 @@ export const TextErrors = ({
defaultMessage,
icon,
canClose = false,
status,
...textProps
}: TextErrorsProps) => {
return (
@@ -35,6 +38,7 @@ export const TextErrors = ({
<TextOnlyErrors
causes={causes}
defaultMessage={defaultMessage}
status={status}
{...textProps}
/>
</AlertStyled>
@@ -44,9 +48,39 @@ export const TextErrors = ({
export const TextOnlyErrors = ({
causes,
defaultMessage,
status,
...textProps
}: TextErrorsProps) => {
const { t } = useTranslation();
const httpError = useHttpErrorMessages(status);
if (httpError) {
return (
<Box $direction="column" $gap="0.2rem">
<Text
as="h1"
$theme="error"
$textAlign="center"
$margin="0"
$size="1rem"
$weight="unset"
{...textProps}
>
{httpError.title}
</Text>
<Text
as="p"
$theme="error"
$textAlign="center"
$margin="0"
$size="0.875rem"
{...textProps}
>
{httpError.detail}
</Text>
</Box>
);
}
return (
<Box $direction="column" $gap="0.2rem">
@@ -94,7 +94,7 @@ describe('<DropdownMenu />', () => {
);
const trigger = screen.getByRole('button', { name: 'Select language' });
expect(trigger).toHaveAttribute('aria-haspopup', 'menu');
expect(trigger).toHaveAttribute('aria-haspopup', 'true');
expect(trigger).toHaveAttribute('aria-expanded', 'false');
await userEvent.click(trigger);
@@ -58,6 +58,7 @@ export const DocVersionEditor = ({
<Box $margin="large" className="--docs--doc-version-editor-error">
<TextErrors
causes={error.cause}
status={error.status}
icon={
error.status === 502 ? (
<Text
@@ -62,6 +62,7 @@ const VersionListState = ({
>
<TextErrors
causes={error.cause}
status={error.status}
icon={
error.status === 502 ? (
<Icon iconName="wifi_off" $theme="danger" />
@@ -1,4 +1,5 @@
export * from './useClipboard';
export * from './useCmdK';
export * from './useDate';
export * from './useHttpErrorMessages';
export * from './useKeyboardAction';
@@ -0,0 +1,26 @@
import { useTranslation } from 'react-i18next';
export const useHttpErrorMessages = (status?: number) => {
const { t } = useTranslation();
const messages: Record<number, { title: string; detail: string }> = {
500: {
title: t('500 - Internal Server Error'),
detail: t('The server met an unexpected condition.'),
},
502: {
title: t('502 - Bad Gateway'),
detail: t(
'The server received an invalid response. Please check your connection and try again.',
),
},
503: {
title: t('503 - Service Unavailable'),
detail: t(
'The service is temporarily unavailable. Please try again later.',
),
},
};
return status ? messages[status] : undefined;
};
@@ -216,6 +216,7 @@ const DocPage = ({ id }: DocProps) => {
<Box $margin="large">
<TextErrors
causes={error.cause}
status={error.status}
icon={
error.status === 502 ? (
<Icon iconName="wifi_off" $theme="danger" $withThemeInherited />