From 293a435f4100a59d3d764c619b24548c2a9c4cd5 Mon Sep 17 00:00:00 2001 From: Christinarlong <60594860+Christinarlong@users.noreply.github.com> Date: Tue, 3 Dec 2024 10:11:51 -0800 Subject: [PATCH] chore(sentry apps): Add backwards compatbility for SentryAppCompenent errors (#81480) In (#81167 ), we want to change the SentryAppComponent endpoint to return a string of the error to improve end user clarity when debugging. In the frontend, we currently expect the error response to be a boolean though, so we need to make the frontend backwards compatible (i.e handle both boolean and string) --- .../feedback/list/useHasLinkedIssues.tsx | 4 +++- .../useExternalIssueData.tsx | 4 +++- .../sentryAppComponentIcon.spec.tsx | 24 +++++++++++++++++++ .../app/components/sentryAppComponentIcon.tsx | 8 ++++++- static/app/types/integrations.tsx | 2 +- 5 files changed, 38 insertions(+), 4 deletions(-) create mode 100644 static/app/components/sentryAppComponentIcon.spec.tsx diff --git a/static/app/components/feedback/list/useHasLinkedIssues.tsx b/static/app/components/feedback/list/useHasLinkedIssues.tsx index b829cdca9848dc..aab310f37c71af 100644 --- a/static/app/components/feedback/list/useHasLinkedIssues.tsx +++ b/static/app/components/feedback/list/useHasLinkedIssues.tsx @@ -1,5 +1,6 @@ import type {ExternalIssueComponent} from 'sentry/components/group/externalIssuesList/types'; import useIssueTrackingFilter from 'sentry/components/group/externalIssuesList/useIssueTrackingFilter'; +import {sentryAppComponentIsDisabled} from 'sentry/components/sentryAppComponentIcon'; import SentryAppInstallationStore from 'sentry/stores/sentryAppInstallationsStore'; import {useLegacyStore} from 'sentry/stores/useLegacyStore'; import type {Event} from 'sentry/types/event'; @@ -23,7 +24,8 @@ export default function useExternalIssueData({group, event, project}: Props) { const renderSentryAppIssues = (): ExternalIssueComponent[] => { return components .map(component => { - const {sentryApp, error: disabled} = component; + const {sentryApp} = component; + const disabled = sentryAppComponentIsDisabled(component); const installation = sentryAppInstallations.find( i => i.app.uuid === sentryApp.uuid ); diff --git a/static/app/components/group/externalIssuesList/useExternalIssueData.tsx b/static/app/components/group/externalIssuesList/useExternalIssueData.tsx index 47104210634fec..767c96371e5cab 100644 --- a/static/app/components/group/externalIssuesList/useExternalIssueData.tsx +++ b/static/app/components/group/externalIssuesList/useExternalIssueData.tsx @@ -2,6 +2,7 @@ import type {ExternalIssueComponent} from 'sentry/components/group/externalIssue import {useExternalIssues} from 'sentry/components/group/externalIssuesList/useExternalIssues'; import useFetchIntegrations from 'sentry/components/group/externalIssuesList/useFetchIntegrations'; import useIssueTrackingFilter from 'sentry/components/group/externalIssuesList/useIssueTrackingFilter'; +import {sentryAppComponentIsDisabled} from 'sentry/components/sentryAppComponentIcon'; import SentryAppInstallationStore from 'sentry/stores/sentryAppInstallationsStore'; import {useLegacyStore} from 'sentry/stores/useLegacyStore'; import type {Event} from 'sentry/types/event'; @@ -71,7 +72,8 @@ export default function useExternalIssueData({group, event, project}: Props) { const renderSentryAppIssues = (): ExternalIssueComponent[] => { return components .map(component => { - const {sentryApp, error: disabled} = component; + const {sentryApp} = component; + const disabled = sentryAppComponentIsDisabled(component); const installation = sentryAppInstallations.find( i => i.app.uuid === sentryApp.uuid ); diff --git a/static/app/components/sentryAppComponentIcon.spec.tsx b/static/app/components/sentryAppComponentIcon.spec.tsx new file mode 100644 index 00000000000000..824353b806cc07 --- /dev/null +++ b/static/app/components/sentryAppComponentIcon.spec.tsx @@ -0,0 +1,24 @@ +import {SentryAppComponentFixture} from 'sentry-fixture/sentryAppComponent'; + +import {sentryAppComponentIsDisabled} from 'sentry/components/sentryAppComponentIcon'; + +describe('SentryAppComponentIcon', function () { + it('sentryAppComponentIsDisabled returns false if the error is a non empty string', () => { + const component = SentryAppComponentFixture(); + component.error = 'RIP couldnt connect to sentry :C'; + expect(sentryAppComponentIsDisabled(component)).toBe(false); + }); + + it('sentryAppComponentIsDisabled returns true if the error is an empty string', () => { + const component = SentryAppComponentFixture(); + component.error = ''; + expect(sentryAppComponentIsDisabled(component)).toBe(true); + }); + + // TODO: Delete after new errors are deployed + it('sentryAppComponentIsDisabled returns itself if the error is a boolean', () => { + const component = SentryAppComponentFixture(); + component.error = true; + expect(sentryAppComponentIsDisabled(component)).toBe(true); + }); +}); diff --git a/static/app/components/sentryAppComponentIcon.tsx b/static/app/components/sentryAppComponentIcon.tsx index afda2cfa354ef8..b1e44f250a9dea 100644 --- a/static/app/components/sentryAppComponentIcon.tsx +++ b/static/app/components/sentryAppComponentIcon.tsx @@ -18,7 +18,8 @@ function SentryAppComponentIcon({sentryAppComponent, size = 20}: Props) { ({color}) => color === false ); const isDefault = selectedAvatar?.avatarType !== 'upload'; - const isDisabled = sentryAppComponent.error; + const isDisabled = sentryAppComponentIsDisabled(sentryAppComponent); + return ( { + return typeof component.error === 'boolean' ? component.error : !component.error; +}; + export default SentryAppComponentIcon; const SentryAppAvatarWrapper = styled('span')<{ diff --git a/static/app/types/integrations.tsx b/static/app/types/integrations.tsx index b6359122e9940f..7966525949b72e 100644 --- a/static/app/types/integrations.tsx +++ b/static/app/types/integrations.tsx @@ -263,7 +263,7 @@ export type SentryAppComponent< }; type: 'issue-link' | 'alert-rule-action' | 'issue-media' | 'stacktrace-link'; uuid: string; - error?: boolean; + error?: string | boolean; }; export type SentryAppWebhookRequest = {