Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion superset-frontend/src/components/Chart/ChartErrorMessage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
*/

import { ClientErrorObject, SupersetError } from '@superset-ui/core';
import { t } from '@apache-superset/core/translation';
import { FC } from 'react';
import { useChartOwnerNames } from 'src/hooks/apiResources';
import { ErrorMessageWithStackTrace } from 'src/components';
Expand All @@ -32,7 +33,7 @@ export type Props = {
stackTrace?: string;
} & Omit<ClientErrorObject, 'error'>;

const DEFAULT_CHART_ERROR = 'Data error';
const DEFAULT_CHART_ERROR = t('Error: Data error');

export const ChartErrorMessage: FC<Props> = ({ chartId, error, ...props }) => {
// fetches the chart owners and adds them to the extra data of the error message
Expand Down
43 changes: 43 additions & 0 deletions superset-frontend/src/components/ErrorMessage/ErrorAlert.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -88,3 +88,46 @@ test('ErrorAlert renders compact mode with a tooltip and modal', () => {
fireEvent.click(iconTrigger);
expect(screen.getByText('Compact mode example')).toBeInTheDocument();
});

test('ErrorAlert renders an icon alongside the error text (non-color cue)', () => {
const { container } = render(
<ErrorAlert
errorType="Error"
message="Something went wrong"
type="error"
/>,
);
// The Alert component with showIcon renders an antd icon element
const icon = container.querySelector('.ant-alert-icon');
expect(icon).toBeInTheDocument();
});

test('ErrorAlert renders a warning icon for warning type (non-color cue)', () => {
const { container } = render(
<ErrorAlert
errorType="Warning"
message="Be careful"
type="warning"
compact
/>,
);
// In compact mode, the renderTrigger function shows WarningOutlined for warnings
expect(
container.querySelector('[aria-label="warning"]'),
).toBeInTheDocument();
});

test('ErrorAlert renders an exclamation-circle icon for error type in compact mode (non-color cue)', () => {
const { container } = render(
<ErrorAlert
errorType="Error"
message="Something failed"
type="error"
compact
/>,
);
// In compact mode, the renderTrigger function shows ExclamationCircleOutlined for errors
expect(
container.querySelector('[aria-label="exclamation-circle"]'),
).toBeInTheDocument();
});
6 changes: 5 additions & 1 deletion superset-frontend/src/components/ImportModal/ErrorAlert.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,11 @@ export const ErrorAlert: FunctionComponent<IProps> = ({
css={(theme: SupersetTheme) => antdWarningAlertStyles(theme)}
type="error"
showIcon
message={errorMessage}
message={
<>
<strong>{t('Error:')}</strong> {errorMessage}
</>
}
description={
showDbInstallInstructions ? (
<>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,3 +56,17 @@ test('should render the colors', () => {
const allColors = screen.getAllByTestId('color');
expect(allColors).toHaveLength(12);
});

test('should render aria-label with scheme name on the swatch container', () => {
setup();
const labelled = screen.getByLabelText('Color scheme: Superset Colors');
expect(labelled).toBeInTheDocument();
});

test('color swatches should be aria-hidden', () => {
setup();
const allColors = screen.getAllByTestId('color');
allColors.forEach(color => {
expect(color).toHaveAttribute('aria-hidden', 'true');
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
*/

import { css, SupersetTheme } from '@apache-superset/core/theme';
import { t } from '@apache-superset/core/translation';
import { useRef, useState } from 'react';
import { Tooltip } from '@superset-ui/core/components';

Expand Down Expand Up @@ -55,6 +56,7 @@ export default function ColorSchemeLabel(props: ColorSchemeLabelProps) {
<span
data-test="color"
key={`${id}-${i}`}
aria-hidden="true"
css={(theme: { sizeUnit: number }) => css`
padding-left: ${theme.sizeUnit / 2}px;
:before {
Expand Down Expand Up @@ -94,6 +96,7 @@ export default function ColorSchemeLabel(props: ColorSchemeLabelProps) {
justify-content: flex-start;
`}
data-test={id}
aria-label={t('Color scheme: %s', label)}
>
<span
className="color-scheme-label"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,62 +52,57 @@ export default function AlertStatusIcon({
}) {
const theme = useTheme();
const lastStateConfig = {
icon: Icons.CheckOutlined,
icon: Icons.CheckCircleOutlined,
label: '',
status: '',
};
switch (state) {
case AlertState.Success:
lastStateConfig.icon = Icons.CheckOutlined;
lastStateConfig.icon = Icons.CheckCircleOutlined;
lastStateConfig.label = isReportEnabled
? t('Report sent')
: t('Alert triggered, notification sent');
lastStateConfig.status = AlertState.Success;
break;
case AlertState.Working:
lastStateConfig.icon = Icons.Running;
lastStateConfig.icon = Icons.LoadingOutlined;
lastStateConfig.label = isReportEnabled
? t('Report sending')
: t('Alert running');
lastStateConfig.status = AlertState.Working;
break;
case AlertState.Error:
lastStateConfig.icon = Icons.CloseOutlined;
lastStateConfig.icon = Icons.CloseCircleOutlined;
lastStateConfig.label = isReportEnabled
? t('Report failed')
: t('Alert failed');
lastStateConfig.status = AlertState.Error;
break;
case AlertState.Noop:
lastStateConfig.icon = Icons.CheckOutlined;
lastStateConfig.icon = Icons.ClockCircleOutlined;
lastStateConfig.label = t('Nothing triggered');
lastStateConfig.status = AlertState.Noop;
break;
case AlertState.Grace:
lastStateConfig.icon = Icons.WarningOutlined;
lastStateConfig.icon = Icons.ExclamationCircleOutlined;
lastStateConfig.label = t('Alert Triggered, In Grace Period');
lastStateConfig.status = AlertState.Grace;
break;
default:
lastStateConfig.icon = Icons.CheckOutlined;
lastStateConfig.icon = Icons.ClockCircleOutlined;
lastStateConfig.label = t('Nothing triggered');
lastStateConfig.status = AlertState.Noop;
}
const Icon = lastStateConfig.icon;
const isRunningIcon = state === AlertState.Working;
const isWorkingState = state === AlertState.Working;
return (
<Tooltip title={lastStateConfig.label} placement="bottomLeft">
<span
css={
isRunningIcon
? css`
display: inline-flex;
align-items: center;
justify-content: center;
transform: scale(1.8);
`
: undefined
}
css={css`
display: inline-flex;
align-items: center;
justify-content: center;
`}
>
<Icon
iconSize="m"
Expand All @@ -116,6 +111,7 @@ export default function AlertStatusIcon({
isReportEnabled,
theme,
)}
spin={isWorkingState}
/>
Comment on lines 107 to 115
Copy link

Copilot AI Apr 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The icon’s accessible name currently comes from the icon filename (e.g. “check-circle”, “clock-circle”), which doesn’t convey the actual alert/report status to screen reader users. Since this component already has a localized lastStateConfig.label, consider wiring that into the rendered icon (e.g. via aria-label / title) so the status is announced meaningfully (and not just via a hover tooltip).

Copilot uses AI. Check for mistakes.
</span>
</Tooltip>
Expand Down
Loading