diff --git a/static/app/components/charts/eventsRequest.tsx b/static/app/components/charts/eventsRequest.tsx index 42270cbaab1389..3941a2b4ac0a58 100644 --- a/static/app/components/charts/eventsRequest.tsx +++ b/static/app/components/charts/eventsRequest.tsx @@ -38,6 +38,7 @@ type LoadingStatus = { * Whether there was an error retrieving data */ errored: boolean; + errorMessage?: string; }; export type RenderProps = LoadingStatus & @@ -186,6 +187,7 @@ export type EventsRequestProps = DefaultProps & type EventsRequestState = { reloading: boolean; errored: boolean; + errorMessage?: string; timeseriesData: null | EventsStats | MultiSeriesEventsStats; fetchedWithPrevious: boolean; }; @@ -242,31 +244,37 @@ class EventsRequest extends React.PureComponent ({ reloading: state.timeseriesData !== null, errored: false, + errorMessage: undefined, })); + let errorMessage; if (expired) { - addErrorMessage( - t('%s has an invalid date range. Please try a more recent date range.', name), - {append: true} + errorMessage = t( + '%s has an invalid date range. Please try a more recent date range.', + name ); + addErrorMessage(errorMessage, {append: true}); this.setState({ errored: true, + errorMessage, }); } else { try { api.clear(); timeseriesData = await doEventsRequest(api, props); } catch (resp) { + if (resp && resp.responseJSON && resp.responseJSON.detail) { + errorMessage = resp.responseJSON.detail; + } else { + errorMessage = t('Error loading chart data'); + } if (!hideError) { - if (resp && resp.responseJSON && resp.responseJSON.detail) { - addErrorMessage(resp.responseJSON.detail); - } else { - addErrorMessage(t('Error loading chart data')); - } + addErrorMessage(errorMessage); } this.setState({ errored: true, + errorMessage, }); } } @@ -448,7 +456,7 @@ class EventsRequest extends React.PureComponent { expired={expired} name={name} referrer={referrer} + hideError partial > - {({loading, timeseriesData, results, errored}) => { + {({loading, timeseriesData, results, errored, errorMessage}) => { if (errored) { return ( + {errorMessage} ); } @@ -317,4 +319,9 @@ const StyledGraphContainer = styled(props => ( align-items: center; `; +const StyledErrorMessage = styled('div')` + color: ${p => p.theme.gray300}; + margin-left: 4px; +`; + export default withApi(withTheme(MiniGraph)); diff --git a/tests/js/spec/views/eventsV2/miniGraph.spec.tsx b/tests/js/spec/views/eventsV2/miniGraph.spec.tsx index 9c6de186fc6fc8..8d4db52d50b557 100644 --- a/tests/js/spec/views/eventsV2/miniGraph.spec.tsx +++ b/tests/js/spec/views/eventsV2/miniGraph.spec.tsx @@ -59,6 +59,14 @@ describe('EventsV2 > MiniGraph', function () { }); // @ts-expect-error eventView = EventView.fromSavedQueryOrLocation(undefined, location); + + // @ts-expect-error + MockApiClient.clearMockResponses(); + // @ts-expect-error + MockApiClient.addMockResponse({ + url: '/organizations/org-slug/events-stats/', + statusCode: 200, + }); }); it('makes an EventsRequest with all selected multi y axis', async function () { @@ -118,4 +126,37 @@ describe('EventsV2 > MiniGraph', function () { }, ]); }); + + it('renders error message', async function () { + const errorMessage = 'something went wrong'; + // @ts-expect-error + const api = new MockApiClient(); + // @ts-expect-error + MockApiClient.clearMockResponses(); + // @ts-expect-error + MockApiClient.addMockResponse({ + url: '/organizations/org-slug/events-stats/', + body: { + detail: errorMessage, + }, + statusCode: 400, + }); + + const wrapper = mountWithTheme( + , + initialData.routerContext + ); + + // @ts-expect-error + await tick(); + wrapper.update(); + + expect(wrapper.find('MiniGraph').text()).toBe(errorMessage); + }); });