Skip to content
Merged
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
29 changes: 20 additions & 9 deletions static/app/components/charts/eventsRequest.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ type LoadingStatus = {
* Whether there was an error retrieving data
*/
errored: boolean;
errorMessage?: string;
};

export type RenderProps = LoadingStatus &
Expand Down Expand Up @@ -186,6 +187,7 @@ export type EventsRequestProps = DefaultProps &
type EventsRequestState = {
reloading: boolean;
errored: boolean;
errorMessage?: string;
timeseriesData: null | EventsStats | MultiSeriesEventsStats;
fetchedWithPrevious: boolean;
};
Expand Down Expand Up @@ -242,31 +244,37 @@ class EventsRequest extends React.PureComponent<EventsRequestProps, EventsReques
this.setState(state => ({
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,
});
}
}
Expand Down Expand Up @@ -448,7 +456,7 @@ class EventsRequest extends React.PureComponent<EventsRequestProps, EventsReques

render() {
const {children, showLoading, ...props} = this.props;
const {timeseriesData, reloading, errored} = this.state;
const {timeseriesData, reloading, errored, errorMessage} = this.state;
// Is "loading" if data is null
const loading = this.props.loading || timeseriesData === null;

Expand Down Expand Up @@ -495,6 +503,7 @@ class EventsRequest extends React.PureComponent<EventsRequestProps, EventsReques
loading,
reloading,
errored,
errorMessage,
results,
timeframe,
previousTimeseriesData,
Expand All @@ -519,6 +528,7 @@ class EventsRequest extends React.PureComponent<EventsRequestProps, EventsReques
loading,
reloading,
errored,
errorMessage,
// timeseries data
timeseriesData: transformedTimeseriesData,
comparisonTimeseriesData: transformedComparisonTimeseriesData,
Expand All @@ -539,6 +549,7 @@ class EventsRequest extends React.PureComponent<EventsRequestProps, EventsReques
loading,
reloading,
errored,
errorMessage,
...props,
});
}
Expand Down
9 changes: 8 additions & 1 deletion static/app/views/eventsV2/miniGraph.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -204,13 +204,15 @@ class MiniGraph extends React.Component<Props> {
expired={expired}
name={name}
referrer={referrer}
hideError
partial
>
{({loading, timeseriesData, results, errored}) => {
{({loading, timeseriesData, results, errored, errorMessage}) => {
if (errored) {
return (
<StyledGraphContainer>
<IconWarning color="gray300" size="md" />
<StyledErrorMessage>{errorMessage}</StyledErrorMessage>
</StyledGraphContainer>
);
}
Expand Down Expand Up @@ -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));
41 changes: 41 additions & 0 deletions tests/js/spec/views/eventsV2/miniGraph.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 () {
Expand Down Expand Up @@ -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(
<MiniGraph
// @ts-expect-error
location={location}
eventView={eventView}
organization={organization}
api={api}
/>,
initialData.routerContext
);

// @ts-expect-error
await tick();
wrapper.update();

expect(wrapper.find('MiniGraph').text()).toBe(errorMessage);
});
});