Fix alarming JS errors (#4494)

# What this PR does
Fix alarming errors reported to Faro

## Which issue(s) this PR closes

Closes https://github.com/grafana/oncall/issues/4492

<!--
*Note*: if you have more than one GitHub issue that this PR closes, be
sure to preface
each issue link with a [closing
keyword](https://docs.github.com/en/get-started/writing-on-github/working-with-advanced-formatting/using-keywords-in-issues-and-pull-requests#linking-a-pull-request-to-an-issue).
This ensures that the issue(s) are auto-closed once the PR has been
merged.
-->

## Checklist

- [ ] Unit, integration, and e2e (if applicable) tests updated
- [x] Documentation added (or `pr:no public docs` PR label added if not
required)
- [x] Added the relevant release notes label (see labels prefixed w/
`release:`). These labels dictate how your PR will
    show up in the autogenerated release notes.
This commit is contained in:
Dominik Broj 2024-06-11 11:31:24 +02:00 committed by GitHub
parent 518e22705a
commit 9a011ea745
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 54 additions and 40 deletions

View file

@ -3,7 +3,7 @@ import { AppFeature } from 'state/features';
import { TemplateForEdit, commonTemplateForEdit } from './CommonAlertTemplatesForm.config';
export const getTemplatesForEdit = (features: Record<string, boolean>) => {
if (features[AppFeature.MsTeams]) {
if (features?.[AppFeature.MsTeams]) {
return { ...commonTemplateForEdit, ...additionalTemplateForEdit };
}
return commonTemplateForEdit;

View file

@ -142,7 +142,7 @@ export const Alerts = function () {
);
function showBannerTeam(): boolean {
return currentOrganization?.banner.title != null && !getItem(currentOrganization?.banner.title);
return Boolean(currentOrganization?.banner?.title) && !getItem(currentOrganization?.banner?.title);
}
function showMismatchWarning(): boolean {

View file

@ -26,10 +26,9 @@ const additionalTemplatesToRender: TemplateBlock[] = [
},
];
export const getTemplatesToRender = (features: Record<string, boolean>) => {
if (features[AppFeature.MsTeams]) {
export const getTemplatesToRender = (features?: Record<string, boolean>) => {
if (features?.[AppFeature.MsTeams]) {
return commonTemplatesToRender.concat(additionalTemplatesToRender);
}
return commonTemplatesToRender;
};

View file

@ -179,7 +179,9 @@ export const ScheduleOverrideForm: FC<RotationFormProps> = (props) => {
};
const onError = useCallback((error) => {
setErrors(error.response.data);
if (error.response) {
setErrors(error.response.data);
}
}, []);
const handleChange = useDebouncedCallback(updatePreview, 200);

View file

@ -5,6 +5,7 @@ import cn from 'classnames/bind';
import { observer } from 'mobx-react';
import { PluginLink } from 'components/PluginLink/PluginLink';
import { RenderConditionally } from 'components/RenderConditionally/RenderConditionally';
import { Text } from 'components/Text/Text';
import { WithPermissionControlDisplay } from 'containers/WithPermissionControl/WithPermissionControlDisplay';
import { WithPermissionControlTooltip } from 'containers/WithPermissionControl/WithPermissionControlTooltip';
@ -168,7 +169,9 @@ export const PhoneVerification = observer((props: PhoneVerificationProps) => {
const isButtonDisabled =
phone === user.verified_phone_number ||
(!isCodeSent && !isPhoneValid && !isPhoneCallInitiated) ||
!isPhoneProviderConfigured;
!isPhoneProviderConfigured ||
!window.grecaptcha;
const disabledButtonTooltipText = window.grecaptcha ? undefined : 'reCAPTCHA has not been loaded';
const isPhoneDisabled = !!user.verified_phone_number;
const isCodeFieldDisabled = (!isCodeSent && !isPhoneCallInitiated) || !isUserActionAllowed(action);
@ -263,6 +266,7 @@ export const PhoneVerification = observer((props: PhoneVerificationProps) => {
isCodeSent={isCodeSent}
isPhoneCallInitiated={isPhoneCallInitiated}
isButtonDisabled={isButtonDisabled}
disabledButtonTooltipText={disabledButtonTooltipText}
providerConfiguration={providerConfiguration}
onSubmitCallback={onSubmitCallback}
onVerifyCallback={onVerifyCallback}
@ -306,6 +310,7 @@ interface PhoneVerificationButtonsGroupProps {
isCodeSent: boolean;
isPhoneCallInitiated: boolean;
isButtonDisabled: boolean;
disabledButtonTooltipText?: string;
providerConfiguration: {
configured: boolean;
test_call: boolean;
@ -328,6 +333,7 @@ const PhoneVerificationButtonsGroup = observer(
isCodeSent,
isPhoneCallInitiated,
isButtonDisabled,
disabledButtonTooltipText,
providerConfiguration,
onSubmitCallback,
onVerifyCallback,
@ -353,30 +359,37 @@ const PhoneVerificationButtonsGroup = observer(
</WithPermissionControlTooltip>
</>
) : (
<HorizontalGroup>
{providerConfiguration.verification_sms && (
<WithPermissionControlTooltip userAction={action}>
<Button
variant="primary"
onClick={() => onSubmitCallback('verification_sms')}
disabled={isButtonDisabled}
>
Send Code
</Button>
</WithPermissionControlTooltip>
<RenderConditionally
shouldRender={Boolean(providerConfiguration)}
render={() => (
<HorizontalGroup>
{providerConfiguration.verification_sms && (
<WithPermissionControlTooltip userAction={action}>
<Button
variant="primary"
onClick={() => onSubmitCallback('verification_sms')}
disabled={isButtonDisabled}
tooltip={disabledButtonTooltipText}
>
Send Code
</Button>
</WithPermissionControlTooltip>
)}
{providerConfiguration.verification_call && (
<WithPermissionControlTooltip userAction={action}>
<Button
variant="primary"
onClick={() => onSubmitCallback('verification_call')}
disabled={isButtonDisabled}
tooltip={disabledButtonTooltipText}
>
Call to get the code
</Button>
</WithPermissionControlTooltip>
)}
</HorizontalGroup>
)}
{providerConfiguration.verification_call && (
<WithPermissionControlTooltip userAction={action}>
<Button
variant="primary"
onClick={() => onSubmitCallback('verification_call')}
disabled={isButtonDisabled}
>
Call to get the code
</Button>
</WithPermissionControlTooltip>
)}
</HorizontalGroup>
></RenderConditionally>
)}
</HorizontalGroup>
)}

View file

@ -315,7 +315,7 @@ export class AlertGroupStore {
async fetchTableSettings(): Promise<void> {
const tableSettings = await makeRequest('/alertgroup_table_settings', {});
const { hidden, visible, default: isDefaultOrder } = tableSettings;
const { hidden = [], visible = [], default: isDefaultOrder } = tableSettings;
runInAction(() => {
this.isDefaultColumnOrder = isDefaultOrder;

View file

@ -695,7 +695,7 @@ class _IncidentsPage extends React.Component<IncidentsPageProps, IncidentsPageSt
};
renderLabels = (item: ApiSchemas['AlertGroup']) => {
if (!item.labels.length) {
if (!item.labels?.length) {
return null;
}

View file

@ -48,11 +48,7 @@ export const GrafanaPluginRootPage = (props: AppRootProps) => {
});
return (
<ErrorBoundary
onError={(error) => {
FaroHelper.faro.api.pushError(error, { context: { type: 'react' } });
}}
>
<ErrorBoundary onError={FaroHelper.pushReactError}>
{() => (
<Provider store={rootStore}>
<PluginSetup InitializedComponent={Root} {...props} />

View file

@ -70,6 +70,10 @@ class BaseFaroHelper {
return this.faro;
}
pushReactError = (error: Error) => {
this.faro?.api.pushError(error, { context: { type: 'react' } });
};
pushNetworkRequestEvent = (config: { method: string; url: string; body: string }) => {
this.faro?.api.pushEvent('Request sent', config);
};
@ -97,10 +101,10 @@ class BaseFaroHelper {
});
};
pushAxiosNetworkResponseEvent = ({ name, res }: { name: string; res: AxiosResponse }) => {
pushAxiosNetworkResponseEvent = ({ name, res }: { name: string; res?: AxiosResponse }) => {
this.faro?.api.pushEvent(name, {
url: res.config?.url,
status: `${res.status}`,
url: res?.config?.url,
status: `${res?.status}`,
statusText: `${res.statusText}`,
method: res.config?.method.toUpperCase(),
});