Show error if resolve AG request fails (#4199)

# What this PR does

Fix for https://github.com/grafana/oncall-private/issues/2587

- Modified the http-client to throw both the response and the error data
such that the decorator can read the actual error data passed from
backend

## Which issue(s) this PR closes

Closes https://github.com/grafana/oncall-private/issues/2587
This commit is contained in:
Rares Mardare 2024-04-11 11:40:33 +03:00 committed by GitHub
parent 04ca174445
commit 64bca2a2c0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 48 additions and 6 deletions

View file

@ -8,11 +8,17 @@ import { onCallApi } from 'network/oncall-api/http-client';
import { RootStore } from 'state/rootStore';
import { SelectOption } from 'state/types';
import { LocationHelper } from 'utils/LocationHelper';
import { GENERIC_ERROR } from 'utils/consts';
import { AutoLoadingState, WithGlobalNotification } from 'utils/decorators';
import { AlertGroupHelper } from './alertgroup.helpers';
import { AlertGroupColumn, AlertAction, IncidentStatus } from './alertgroup.types';
const composeFailureMessageFn = async (error: Response) => {
let errorData = await error.json();
return errorData?.detail || GENERIC_ERROR;
};
export class AlertGroupStore {
rootStore: RootStore;
alerts = new Map<string, ApiSchemas['AlertGroup']>();
@ -204,9 +210,13 @@ export class AlertGroupStore {
});
}
@WithGlobalNotification({
failure: 'Failure',
composeFailureMessageFn,
})
async resolve(id: ApiSchemas['AlertGroup']['pk']) {
this.setLiveUpdatesPaused(true);
const { data } = await onCallApi().POST('/alertgroups/{id}/resolve/', {
const { data } = await onCallApi({ skipErrorHandling: true }).POST('/alertgroups/{id}/resolve/', {
params: { path: { id } },
});
this.updateAlert(id, {
@ -215,6 +225,10 @@ export class AlertGroupStore {
});
}
@WithGlobalNotification({
failure: 'Failure',
composeFailureMessageFn,
})
async unresolve(id: ApiSchemas['AlertGroup']['pk']) {
this.setLiveUpdatesPaused(true);
const { data } = await onCallApi().POST('/alertgroups/{id}/unresolve/', { params: { path: { id } } });
@ -224,6 +238,10 @@ export class AlertGroupStore {
});
}
@WithGlobalNotification({
failure: 'Failure',
composeFailureMessageFn,
})
async acknowledge(id: ApiSchemas['AlertGroup']['pk']) {
this.setLiveUpdatesPaused(true);
const { data } = await onCallApi().POST('/alertgroups/{id}/acknowledge/', { params: { path: { id } } });
@ -233,6 +251,10 @@ export class AlertGroupStore {
});
}
@WithGlobalNotification({
failure: 'Failure',
composeFailureMessageFn,
})
async unacknowledge(id: ApiSchemas['AlertGroup']['pk']) {
this.setLiveUpdatesPaused(true);
const { data } = await onCallApi().POST('/alertgroups/{id}/unacknowledge/', { params: { path: { id } } });
@ -242,6 +264,10 @@ export class AlertGroupStore {
});
}
@WithGlobalNotification({
failure: 'Failure',
composeFailureMessageFn,
})
async silence(id: ApiSchemas['AlertGroup']['pk'], delay: number) {
this.setLiveUpdatesPaused(true);
const { data } = await onCallApi().POST('/alertgroups/{id}/silence/', {
@ -254,6 +280,10 @@ export class AlertGroupStore {
});
}
@WithGlobalNotification({
failure: 'Failure',
composeFailureMessageFn,
})
async unsilence(id: ApiSchemas['AlertGroup']['pk']) {
this.setLiveUpdatesPaused(true);
const { data } = await onCallApi().POST('/alertgroups/{id}/unsilence/', { params: { path: { id } } });

View file

@ -28,7 +28,16 @@ const REQUEST_CONFIG = {
};
const URL = 'https://someurl.com';
const SUCCESSFUL_RESPONSE_MOCK = { ok: true };
const FAILING_RESPONSE_MOCK = { ok: false, json: () => 'ERROR' };
const FAILING_RESPONSE_MOCK = {
ok: false,
json: () => 'ERROR',
// we need to have clone available to actually clone the response
clone: () => ({
ok: false,
json: () => 'ERROR',
}),
};
const customFetch = getCustomFetchFn({ withGlobalErrorHandler: true });
describe('customFetch', () => {

View file

@ -72,12 +72,13 @@ export const getCustomFetchFn =
faro?.api.pushEvent('Request completed', { url });
return res;
} else {
const errorData = await res.json();
const errorData = await res.clone().json();
faro?.api.pushEvent('Request failed', { url });
faro?.api.pushError(errorData);
if (withGlobalErrorHandler) {
showApiError(res);
}
throw res;
}
}

View file

@ -83,3 +83,5 @@ export enum OnCallAGStatus {
Silenced = 'silenced',
Acknowledged = 'acknowledged',
}
export const GENERIC_ERROR = 'An error has occurred. Please try again';

View file

@ -36,7 +36,7 @@ export function WrapAutoLoadingState(callback: Function, actionKey: string): (..
type GlobalNotificationConfig = {
success?: string;
failure?: string;
composeFailureMessageFn?: (error: unknown) => string;
composeFailureMessageFn?: (error: Response) => Promise<string>;
failureType?: 'error' | 'warning';
};
@ -50,7 +50,7 @@ export function WrapWithGlobalNotification(
success && openNotification(success);
} catch (err) {
const open = failureType === 'error' ? openErrorNotification : openWarningNotification;
const message = composeFailureMessageFn ? composeFailureMessageFn(err) : failure;
const message = composeFailureMessageFn ? await composeFailureMessageFn(err) : failure;
open(message);
throw err;
}
@ -73,7 +73,7 @@ export function WithGlobalNotification({
return response;
} catch (err) {
const open = failureType === 'error' ? openErrorNotification : openWarningNotification;
const message = composeFailureMessageFn ? composeFailureMessageFn(err) : failure;
const message = composeFailureMessageFn ? await composeFailureMessageFn(err) : failure;
open(message);
throw err;
}