mirror of https://github.com/apache/superset.git
chore(native-filters): Ensure consistent error handling (#24206)
Co-authored-by: Michael S. Molina <michael.s.molina@gmail.com>
This commit is contained in:
parent
6e7b93eb48
commit
674da1b209
|
@ -37,6 +37,7 @@ const StyledContent = styled.div`
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
margin-left: ${({ theme }) => theme.gridUnit * 2}px;
|
margin-left: ${({ theme }) => theme.gridUnit * 2}px;
|
||||||
|
overflow: hidden;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const StyledTitle = styled.span`
|
const StyledTitle = styled.span`
|
||||||
|
|
|
@ -21,7 +21,8 @@ import React from 'react';
|
||||||
import { render, screen } from 'spec/helpers/testing-library';
|
import { render, screen } from 'spec/helpers/testing-library';
|
||||||
import userEvent from '@testing-library/user-event';
|
import userEvent from '@testing-library/user-event';
|
||||||
import ErrorMessageWithStackTrace from './ErrorMessageWithStackTrace';
|
import ErrorMessageWithStackTrace from './ErrorMessageWithStackTrace';
|
||||||
import { ErrorLevel, ErrorSource } from './types';
|
import BasicErrorAlert from './BasicErrorAlert';
|
||||||
|
import { ErrorLevel, ErrorSource, ErrorTypeEnum } from './types';
|
||||||
|
|
||||||
jest.mock(
|
jest.mock(
|
||||||
'src/components/Icons/Icon',
|
'src/components/Icons/Icon',
|
||||||
|
@ -57,3 +58,21 @@ test('should render the link', () => {
|
||||||
expect(link).toHaveTextContent('(Request Access)');
|
expect(link).toHaveTextContent('(Request Access)');
|
||||||
expect(link).toHaveAttribute('href', mockedProps.link);
|
expect(link).toHaveAttribute('href', mockedProps.link);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('should render the fallback', () => {
|
||||||
|
const body = 'Blahblah';
|
||||||
|
render(
|
||||||
|
<ErrorMessageWithStackTrace
|
||||||
|
error={{
|
||||||
|
error_type: ErrorTypeEnum.FRONTEND_NETWORK_ERROR,
|
||||||
|
message: body,
|
||||||
|
extra: {},
|
||||||
|
level: 'error',
|
||||||
|
}}
|
||||||
|
fallback={<BasicErrorAlert title="Blah" body={body} level="error" />}
|
||||||
|
{...mockedProps}
|
||||||
|
/>,
|
||||||
|
{ useRedux: true },
|
||||||
|
);
|
||||||
|
expect(screen.getByText(body)).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
|
@ -34,6 +34,7 @@ type Props = {
|
||||||
source?: ErrorSource;
|
source?: ErrorSource;
|
||||||
description?: string;
|
description?: string;
|
||||||
errorMitigationFunction?: () => void;
|
errorMitigationFunction?: () => void;
|
||||||
|
fallback?: React.ReactNode;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function ErrorMessageWithStackTrace({
|
export default function ErrorMessageWithStackTrace({
|
||||||
|
@ -45,6 +46,7 @@ export default function ErrorMessageWithStackTrace({
|
||||||
stackTrace,
|
stackTrace,
|
||||||
source,
|
source,
|
||||||
description,
|
description,
|
||||||
|
fallback,
|
||||||
}: Props) {
|
}: Props) {
|
||||||
// Check if a custom error message component was registered for this message
|
// Check if a custom error message component was registered for this message
|
||||||
if (error) {
|
if (error) {
|
||||||
|
@ -62,6 +64,10 @@ export default function ErrorMessageWithStackTrace({
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (fallback) {
|
||||||
|
return <>{fallback}</>;
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ErrorAlert
|
<ErrorAlert
|
||||||
level="warning"
|
level="warning"
|
||||||
|
|
|
@ -40,9 +40,13 @@ import { isEqual, isEqualWith } from 'lodash';
|
||||||
import { getChartDataRequest } from 'src/components/Chart/chartAction';
|
import { getChartDataRequest } from 'src/components/Chart/chartAction';
|
||||||
import Loading from 'src/components/Loading';
|
import Loading from 'src/components/Loading';
|
||||||
import BasicErrorAlert from 'src/components/ErrorMessage/BasicErrorAlert';
|
import BasicErrorAlert from 'src/components/ErrorMessage/BasicErrorAlert';
|
||||||
|
import ErrorMessageWithStackTrace from 'src/components/ErrorMessage/ErrorMessageWithStackTrace';
|
||||||
import { isFeatureEnabled } from 'src/featureFlags';
|
import { isFeatureEnabled } from 'src/featureFlags';
|
||||||
import { waitForAsyncData } from 'src/middleware/asyncEvent';
|
import { waitForAsyncData } from 'src/middleware/asyncEvent';
|
||||||
import { ClientErrorObject } from 'src/utils/getClientErrorObject';
|
import {
|
||||||
|
ClientErrorObject,
|
||||||
|
getClientErrorObject,
|
||||||
|
} from 'src/utils/getClientErrorObject';
|
||||||
import { FilterBarOrientation, RootState } from 'src/dashboard/types';
|
import { FilterBarOrientation, RootState } from 'src/dashboard/types';
|
||||||
import {
|
import {
|
||||||
onFiltersRefreshSuccess,
|
onFiltersRefreshSuccess,
|
||||||
|
@ -97,7 +101,7 @@ const FilterValue: React.FC<FilterControlProps> = ({
|
||||||
const dependencies = useFilterDependencies(id, dataMaskSelected);
|
const dependencies = useFilterDependencies(id, dataMaskSelected);
|
||||||
const shouldRefresh = useShouldFilterRefresh();
|
const shouldRefresh = useShouldFilterRefresh();
|
||||||
const [state, setState] = useState<ChartDataResponseResult[]>([]);
|
const [state, setState] = useState<ChartDataResponseResult[]>([]);
|
||||||
const [error, setError] = useState<string>('');
|
const [error, setError] = useState<ClientErrorObject>();
|
||||||
const [formData, setFormData] = useState<Partial<QueryFormData>>({
|
const [formData, setFormData] = useState<Partial<QueryFormData>>({
|
||||||
inView: false,
|
inView: false,
|
||||||
});
|
});
|
||||||
|
@ -183,11 +187,11 @@ const FilterValue: React.FC<FilterControlProps> = ({
|
||||||
setState(asyncResult);
|
setState(asyncResult);
|
||||||
handleFilterLoadFinish();
|
handleFilterLoadFinish();
|
||||||
})
|
})
|
||||||
.catch((error: ClientErrorObject) => {
|
.catch((error: Response) => {
|
||||||
setError(
|
getClientErrorObject(error).then(clientErrorObject => {
|
||||||
error.message || error.error || t('Check configuration'),
|
setError(clientErrorObject);
|
||||||
);
|
handleFilterLoadFinish();
|
||||||
handleFilterLoadFinish();
|
});
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
|
@ -196,13 +200,15 @@ const FilterValue: React.FC<FilterControlProps> = ({
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
setState(json.result);
|
setState(json.result);
|
||||||
setError('');
|
setError(undefined);
|
||||||
handleFilterLoadFinish();
|
handleFilterLoadFinish();
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch((error: Response) => {
|
.catch((error: Response) => {
|
||||||
setError(error.statusText);
|
getClientErrorObject(error).then(clientErrorObject => {
|
||||||
handleFilterLoadFinish();
|
setError(clientErrorObject);
|
||||||
|
handleFilterLoadFinish();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, [
|
}, [
|
||||||
|
@ -298,10 +304,15 @@ const FilterValue: React.FC<FilterControlProps> = ({
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
return (
|
return (
|
||||||
<BasicErrorAlert
|
<ErrorMessageWithStackTrace
|
||||||
title={t('Cannot load filter')}
|
error={error.errors?.[0]}
|
||||||
body={error}
|
fallback={
|
||||||
level="error"
|
<BasicErrorAlert
|
||||||
|
title={t('Cannot load filter')}
|
||||||
|
body={error.error}
|
||||||
|
level="error"
|
||||||
|
/>
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,6 +54,7 @@ import { Input, TextArea } from 'src/components/Input';
|
||||||
import { Select, FormInstance } from 'src/components';
|
import { Select, FormInstance } from 'src/components';
|
||||||
import Collapse from 'src/components/Collapse';
|
import Collapse from 'src/components/Collapse';
|
||||||
import BasicErrorAlert from 'src/components/ErrorMessage/BasicErrorAlert';
|
import BasicErrorAlert from 'src/components/ErrorMessage/BasicErrorAlert';
|
||||||
|
import ErrorMessageWithStackTrace from 'src/components/ErrorMessage/ErrorMessageWithStackTrace';
|
||||||
import { FormItem } from 'src/components/Form';
|
import { FormItem } from 'src/components/Form';
|
||||||
import Icons from 'src/components/Icons';
|
import Icons from 'src/components/Icons';
|
||||||
import Loading from 'src/components/Loading';
|
import Loading from 'src/components/Loading';
|
||||||
|
@ -72,7 +73,10 @@ import DateFilterControl from 'src/explore/components/controls/DateFilterControl
|
||||||
import AdhocFilterControl from 'src/explore/components/controls/FilterControl/AdhocFilterControl';
|
import AdhocFilterControl from 'src/explore/components/controls/FilterControl/AdhocFilterControl';
|
||||||
import { isFeatureEnabled } from 'src/featureFlags';
|
import { isFeatureEnabled } from 'src/featureFlags';
|
||||||
import { waitForAsyncData } from 'src/middleware/asyncEvent';
|
import { waitForAsyncData } from 'src/middleware/asyncEvent';
|
||||||
import { ClientErrorObject } from 'src/utils/getClientErrorObject';
|
import {
|
||||||
|
ClientErrorObject,
|
||||||
|
getClientErrorObject,
|
||||||
|
} from 'src/utils/getClientErrorObject';
|
||||||
import { SingleValueType } from 'src/filters/components/Range/SingleValueType';
|
import { SingleValueType } from 'src/filters/components/Range/SingleValueType';
|
||||||
import {
|
import {
|
||||||
getFormData,
|
getFormData,
|
||||||
|
@ -345,7 +349,7 @@ const FiltersConfigForm = (
|
||||||
ref: React.RefObject<any>,
|
ref: React.RefObject<any>,
|
||||||
) => {
|
) => {
|
||||||
const isRemoved = !!removedFilters[filterId];
|
const isRemoved = !!removedFilters[filterId];
|
||||||
const [error, setError] = useState<string>('');
|
const [error, setError] = useState<ClientErrorObject>();
|
||||||
const [metrics, setMetrics] = useState<Metric[]>([]);
|
const [metrics, setMetrics] = useState<Metric[]>([]);
|
||||||
const [activeTabKey, setActiveTabKey] = useState<string>(
|
const [activeTabKey, setActiveTabKey] = useState<string>(
|
||||||
FilterTabs.configuration.key,
|
FilterTabs.configuration.key,
|
||||||
|
@ -440,11 +444,11 @@ const FiltersConfigForm = (
|
||||||
|
|
||||||
const setNativeFilterFieldValuesWrapper = (values: object) => {
|
const setNativeFilterFieldValuesWrapper = (values: object) => {
|
||||||
setNativeFilterFieldValues(form, filterId, values);
|
setNativeFilterFieldValues(form, filterId, values);
|
||||||
setError('');
|
setError(undefined);
|
||||||
forceUpdate();
|
forceUpdate();
|
||||||
};
|
};
|
||||||
|
|
||||||
const setErrorWrapper = (error: string) => {
|
const setErrorWrapper = (error: ClientErrorObject) => {
|
||||||
setNativeFilterFieldValues(form, filterId, {
|
setNativeFilterFieldValues(form, filterId, {
|
||||||
defaultValueQueriesData: null,
|
defaultValueQueriesData: null,
|
||||||
});
|
});
|
||||||
|
@ -506,10 +510,10 @@ const FiltersConfigForm = (
|
||||||
defaultValueQueriesData: asyncResult,
|
defaultValueQueriesData: asyncResult,
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.catch((error: ClientErrorObject) => {
|
.catch((error: Response) => {
|
||||||
setError(
|
getClientErrorObject(error).then(clientErrorObject => {
|
||||||
error.message || error.error || t('Check configuration'),
|
setErrorWrapper(clientErrorObject);
|
||||||
);
|
});
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
|
@ -523,10 +527,8 @@ const FiltersConfigForm = (
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch((error: Response) => {
|
.catch((error: Response) => {
|
||||||
error.json().then(body => {
|
getClientErrorObject(error).then(clientErrorObject => {
|
||||||
setErrorWrapper(
|
setError(clientErrorObject);
|
||||||
body.message || error.statusText || t('Check configuration'),
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
@ -1224,10 +1226,15 @@ const FiltersConfigForm = (
|
||||||
{error || showDefaultValue ? (
|
{error || showDefaultValue ? (
|
||||||
<DefaultValueContainer>
|
<DefaultValueContainer>
|
||||||
{error ? (
|
{error ? (
|
||||||
<BasicErrorAlert
|
<ErrorMessageWithStackTrace
|
||||||
title={t('Cannot load filter')}
|
error={error.errors?.[0]}
|
||||||
body={error}
|
fallback={
|
||||||
level="error"
|
<BasicErrorAlert
|
||||||
|
title={t('Cannot load filter')}
|
||||||
|
body={error.error}
|
||||||
|
level="error"
|
||||||
|
/>
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<DefaultValue
|
<DefaultValue
|
||||||
|
|
Loading…
Reference in New Issue