This is an automated email from the ASF dual-hosted git repository.
enzomartellucci pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/superset.git
The following commit(s) were added to refs/heads/master by this push:
new c1c012fb529 fix(chart): make chart error banners non-dismissible
(#38014)
c1c012fb529 is described below
commit c1c012fb529421f021afa9f8975ec30c9ab07449
Author: Enzo Martellucci <[email protected]>
AuthorDate: Thu Feb 26 17:01:02 2026 +0100
fix(chart): make chart error banners non-dismissible (#38014)
---
.../components/Chart/ChartErrorMessage.test.tsx | 13 +++++++++++
.../src/components/Chart/ChartErrorMessage.tsx | 1 +
.../ErrorMessage/DatabaseErrorMessage.tsx | 2 ++
.../ErrorMessage/DatasetNotFoundErrorMessage.tsx | 2 ++
.../ErrorMessageWithStackTrace.test.tsx | 12 +++++++++++
.../ErrorMessage/ErrorMessageWithStackTrace.tsx | 4 ++++
.../ErrorMessage/FrontendNetworkErrorMessage.tsx | 2 ++
.../ErrorMessage/InvalidSQLErrorMessage.tsx | 2 ++
.../ErrorMessage/OAuth2RedirectMessage.tsx | 2 ++
.../ErrorMessage/ParameterErrorMessage.tsx | 2 ++
.../ErrorMessage/TimeoutErrorMessage.tsx | 2 ++
.../src/components/ErrorMessage/types.ts | 1 +
.../components/gridComponents/Chart/Chart.test.tsx | 25 ++++++++++++++++++++++
13 files changed, 70 insertions(+)
diff --git a/superset-frontend/src/components/Chart/ChartErrorMessage.test.tsx
b/superset-frontend/src/components/Chart/ChartErrorMessage.test.tsx
index 1680b0e7602..5a96d6c108c 100644
--- a/superset-frontend/src/components/Chart/ChartErrorMessage.test.tsx
+++ b/superset-frontend/src/components/Chart/ChartErrorMessage.test.tsx
@@ -82,4 +82,17 @@ describe('ChartErrorMessage', () => {
expect(screen.getByText('Test error')).toBeInTheDocument();
expect(screen.getByText('Test subtitle')).toBeInTheDocument();
});
+
+ test('chart error banner is not dismissible', () => {
+ mockUseChartOwnerNames.mockReturnValue({
+ result: null,
+ status: ResourceStatus.Loading,
+ error: null,
+ });
+ render(<ChartErrorMessage {...defaultProps} />);
+
+ expect(
+ screen.queryByRole('button', { name: /close/i }),
+ ).not.toBeInTheDocument();
+ });
});
diff --git a/superset-frontend/src/components/Chart/ChartErrorMessage.tsx
b/superset-frontend/src/components/Chart/ChartErrorMessage.tsx
index 4c3f79965b3..cd21275153f 100644
--- a/superset-frontend/src/components/Chart/ChartErrorMessage.tsx
+++ b/superset-frontend/src/components/Chart/ChartErrorMessage.tsx
@@ -49,6 +49,7 @@ export const ChartErrorMessage: FC<Props> = ({ chartId,
error, ...props }) => {
{...props}
error={ownedError}
title={DEFAULT_CHART_ERROR}
+ closable={false}
/>
);
};
diff --git
a/superset-frontend/src/components/ErrorMessage/DatabaseErrorMessage.tsx
b/superset-frontend/src/components/ErrorMessage/DatabaseErrorMessage.tsx
index 3125ca92162..fad71169c58 100644
--- a/superset-frontend/src/components/ErrorMessage/DatabaseErrorMessage.tsx
+++ b/superset-frontend/src/components/ErrorMessage/DatabaseErrorMessage.tsx
@@ -39,6 +39,7 @@ interface DatabaseErrorExtra {
export function DatabaseErrorMessage({
error,
source,
+ closable,
}: ErrorMessageComponentProps<DatabaseErrorExtra | null>) {
const { extra, level, message } = error;
@@ -101,6 +102,7 @@ export function DatabaseErrorMessage({
description={alertDescription}
type={level}
descriptionDetails={body}
+ closable={closable}
/>
);
}
diff --git
a/superset-frontend/src/components/ErrorMessage/DatasetNotFoundErrorMessage.tsx
b/superset-frontend/src/components/ErrorMessage/DatasetNotFoundErrorMessage.tsx
index f0f279e4a22..6623715ee0b 100644
---
a/superset-frontend/src/components/ErrorMessage/DatasetNotFoundErrorMessage.tsx
+++
b/superset-frontend/src/components/ErrorMessage/DatasetNotFoundErrorMessage.tsx
@@ -24,6 +24,7 @@ import { ErrorAlert } from './ErrorAlert';
export function DatasetNotFoundErrorMessage({
error,
subtitle,
+ closable,
}: ErrorMessageComponentProps) {
const { level, message } = error;
return (
@@ -32,6 +33,7 @@ export function DatasetNotFoundErrorMessage({
message={subtitle}
description={message}
type={level}
+ closable={closable}
/>
);
}
diff --git
a/superset-frontend/src/components/ErrorMessage/ErrorMessageWithStackTrace.test.tsx
b/superset-frontend/src/components/ErrorMessage/ErrorMessageWithStackTrace.test.tsx
index b27ff32d00a..4b9c5946e76 100644
---
a/superset-frontend/src/components/ErrorMessage/ErrorMessageWithStackTrace.test.tsx
+++
b/superset-frontend/src/components/ErrorMessage/ErrorMessageWithStackTrace.test.tsx
@@ -58,6 +58,18 @@ test('should render the link', () => {
expect(link).toHaveAttribute('href', mockedProps.link);
});
+test('should render a close button by default', () => {
+ render(<ErrorMessageWithStackTrace {...mockedProps} />);
+ expect(screen.getByRole('button', { name: /close/i })).toBeInTheDocument();
+});
+
+test('should not render a close button when closable is false', () => {
+ render(<ErrorMessageWithStackTrace {...mockedProps} closable={false} />);
+ expect(
+ screen.queryByRole('button', { name: /close/i }),
+ ).not.toBeInTheDocument();
+});
+
test('should render the fallback', () => {
const body = 'Blahblah';
render(
diff --git
a/superset-frontend/src/components/ErrorMessage/ErrorMessageWithStackTrace.tsx
b/superset-frontend/src/components/ErrorMessage/ErrorMessageWithStackTrace.tsx
index dc562e473ba..2dc7f793bbe 100644
---
a/superset-frontend/src/components/ErrorMessage/ErrorMessageWithStackTrace.tsx
+++
b/superset-frontend/src/components/ErrorMessage/ErrorMessageWithStackTrace.tsx
@@ -38,6 +38,7 @@ type Props = {
errorMitigationFunction?: () => void;
fallback?: ReactNode;
compact?: boolean;
+ closable?: boolean;
};
export function ErrorMessageWithStackTrace({
@@ -51,6 +52,7 @@ export function ErrorMessageWithStackTrace({
descriptionDetails,
fallback,
compact,
+ closable = true,
}: Props) {
// Check if a custom error message component was registered for this message
if (error) {
@@ -62,6 +64,7 @@ export function ErrorMessageWithStackTrace({
return (
<ErrorMessageComponent
compact={compact}
+ closable={closable}
error={error}
source={source}
subtitle={subtitle}
@@ -99,6 +102,7 @@ export function ErrorMessageWithStackTrace({
description={description}
descriptionDetails={computedDescriptionDetails}
compact={compact}
+ closable={closable}
/>
);
}
diff --git
a/superset-frontend/src/components/ErrorMessage/FrontendNetworkErrorMessage.tsx
b/superset-frontend/src/components/ErrorMessage/FrontendNetworkErrorMessage.tsx
index 98338af13c7..e52b96b8fee 100644
---
a/superset-frontend/src/components/ErrorMessage/FrontendNetworkErrorMessage.tsx
+++
b/superset-frontend/src/components/ErrorMessage/FrontendNetworkErrorMessage.tsx
@@ -25,11 +25,13 @@ export function FrontendNetworkErrorMessage({
error,
subtitle,
compact,
+ closable,
}: ErrorMessageComponentProps) {
const { level, message } = error;
return (
<ErrorAlert
compact={compact}
+ closable={closable}
errorType={t('Network Error')}
message={message}
type={level}
diff --git
a/superset-frontend/src/components/ErrorMessage/InvalidSQLErrorMessage.tsx
b/superset-frontend/src/components/ErrorMessage/InvalidSQLErrorMessage.tsx
index b7eb1135227..5792f2d4db3 100644
--- a/superset-frontend/src/components/ErrorMessage/InvalidSQLErrorMessage.tsx
+++ b/superset-frontend/src/components/ErrorMessage/InvalidSQLErrorMessage.tsx
@@ -34,6 +34,7 @@ interface SupersetParseErrorExtra {
export function InvalidSQLErrorMessage({
error,
subtitle,
+ closable,
}: ErrorMessageComponentProps<SupersetParseErrorExtra>) {
const { extra, level, message } = error;
@@ -58,6 +59,7 @@ export function InvalidSQLErrorMessage({
message={subtitle}
type={level}
description={body}
+ closable={closable}
/>
);
}
diff --git
a/superset-frontend/src/components/ErrorMessage/OAuth2RedirectMessage.tsx
b/superset-frontend/src/components/ErrorMessage/OAuth2RedirectMessage.tsx
index f62a5e076c6..1c6ede178b7 100644
--- a/superset-frontend/src/components/ErrorMessage/OAuth2RedirectMessage.tsx
+++ b/superset-frontend/src/components/ErrorMessage/OAuth2RedirectMessage.tsx
@@ -63,6 +63,7 @@ interface OAuth2RedirectExtra {
export function OAuth2RedirectMessage({
error,
source,
+ closable,
}: ErrorMessageComponentProps<OAuth2RedirectExtra>) {
const oAuthTab = useRef<Window | null>(null);
const { extra, level } = error;
@@ -172,6 +173,7 @@ export function OAuth2RedirectMessage({
message={subtitle}
type={level}
description={body}
+ closable={closable}
/>
);
}
diff --git
a/superset-frontend/src/components/ErrorMessage/ParameterErrorMessage.tsx
b/superset-frontend/src/components/ErrorMessage/ParameterErrorMessage.tsx
index 2e4dbf23d9e..73d8b264c7f 100644
--- a/superset-frontend/src/components/ErrorMessage/ParameterErrorMessage.tsx
+++ b/superset-frontend/src/components/ErrorMessage/ParameterErrorMessage.tsx
@@ -56,6 +56,7 @@ const findMatches = (undefinedParameters: string[],
templateKeys: string[]) => {
export function ParameterErrorMessage({
error,
subtitle,
+ closable,
}: ErrorMessageComponentProps<ParameterErrorExtra>) {
const { extra = { issue_codes: [] }, level, message } = error;
@@ -118,6 +119,7 @@ export function ParameterErrorMessage({
message={message}
description={subtitle}
descriptionDetails={body}
+ closable={closable}
/>
);
}
diff --git
a/superset-frontend/src/components/ErrorMessage/TimeoutErrorMessage.tsx
b/superset-frontend/src/components/ErrorMessage/TimeoutErrorMessage.tsx
index d9e5a26093d..298d1859832 100644
--- a/superset-frontend/src/components/ErrorMessage/TimeoutErrorMessage.tsx
+++ b/superset-frontend/src/components/ErrorMessage/TimeoutErrorMessage.tsx
@@ -36,6 +36,7 @@ interface TimeoutErrorExtra {
export function TimeoutErrorMessage({
error,
source,
+ closable,
}: ErrorMessageComponentProps<TimeoutErrorExtra>) {
const { extra, level } = error;
@@ -95,6 +96,7 @@ export function TimeoutErrorMessage({
message={subtitle}
type={level}
descriptionDetails={body}
+ closable={closable}
/>
);
}
diff --git a/superset-frontend/src/components/ErrorMessage/types.ts
b/superset-frontend/src/components/ErrorMessage/types.ts
index de38332fa6b..de597d19347 100644
--- a/superset-frontend/src/components/ErrorMessage/types.ts
+++ b/superset-frontend/src/components/ErrorMessage/types.ts
@@ -26,6 +26,7 @@ export type ErrorMessageComponentProps<ExtraType =
Record<string, any> | null> =
source?: ErrorSource;
subtitle?: ReactNode;
compact?: boolean;
+ closable?: boolean;
};
export type ErrorMessageComponent = ComponentType<ErrorMessageComponentProps>;
diff --git
a/superset-frontend/src/dashboard/components/gridComponents/Chart/Chart.test.tsx
b/superset-frontend/src/dashboard/components/gridComponents/Chart/Chart.test.tsx
index c4ba8646538..7ef19dce5fb 100644
---
a/superset-frontend/src/dashboard/components/gridComponents/Chart/Chart.test.tsx
+++
b/superset-frontend/src/dashboard/components/gridComponents/Chart/Chart.test.tsx
@@ -370,6 +370,31 @@ test('should fallback to formData state when runtime state
not available', () =>
expect(getByTestId('chart-container')).toBeInTheDocument();
});
+test('should not show a close button on chart error banners', () => {
+ const { queryByRole } = setup(
+ {},
+ {
+ ...defaultState,
+ charts: {
+ ...defaultState.charts,
+ [queryId]: {
+ ...defaultState.charts[queryId],
+ chartStatus: 'failed',
+ chartAlert: 'Something went wrong',
+ queriesResponse: [
+ {
+ message: 'Something went wrong',
+ errors: [],
+ },
+ ],
+ },
+ },
+ },
+ );
+
+ expect(queryByRole('button', { name: /close/i })).not.toBeInTheDocument();
+});
+
test('should handle chart state when no converter exists', () => {
jest
.spyOn(chartStateConverter, 'hasChartStateConverter')