-
-
Notifications
You must be signed in to change notification settings - Fork 4.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(onboarding): add logging #75679
Conversation
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #75679 +/- ##
==========================================
- Coverage 78.25% 78.23% -0.02%
==========================================
Files 6826 6833 +7
Lines 303279 303541 +262
Branches 52188 52240 +52
==========================================
+ Hits 237323 237479 +156
- Misses 59579 59686 +107
+ Partials 6377 6376 -1
|
isLoading, | ||
isError, | ||
refetch, | ||
} = useApiQuery<{}>( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of {}
, pass the type you expect in response here. That will make project
that type and you won't need the as
below
{staleTime: Infinity} | ||
); | ||
|
||
const detailedProject = project as Project & { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can define this type outside the component as:
interface ProjectWithAlertIntegrationInfo extends Project {
hasAlertIntegrationInstalled: boolean;
}
Using interface
and extends
is better when adding properties to an existing type since it is more performant and it works more how you would expect it to (type intersection can result in some confusing types in some situations)
isError, | ||
refetch, | ||
} = useApiQuery<{}>( | ||
[`/projects/${organization.slug}/${projectSlug}/?expand=hasAlertIntegration`], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not that big of a deal, but you can format it like this instead:
[`/projects/${organization.slug}/${projectSlug}/`, {query: { expand: 'hasAlertIntegration' }}],
deps => ( | ||
<MessagingIntegrationModal | ||
{...deps} | ||
headerContent={<h1>Connect with a messaging tool</h1>} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Static strings should be wrapped in t('...')
so that they can be translated
hasAlertIntegrationInstalled: true, | ||
}, | ||
}); | ||
const {container} = render(getComponent()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of checking the container, I'd check that no button exists:
expect(screen.queryByRole('button')).not.toBeInTheDocument()
@@ -32,6 +33,13 @@ function MessagingIntegrationModal({ | |||
project, | |||
onAddIntegration, | |||
}: Props) { | |||
useEffect(() => { | |||
trackAnalytics('onboarding.messaging_integration_modal_rendered', { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Usually we don't track analytics when something is rendered - it can result in a lot of excess analytic events if done wrong. Generally it's better to record the analytic on an action instead. I'd recommend firing this event when the button is clicked to open this modal.
If you haven't seen it yet, you can add them on the button very easily: https://develop.sentry.dev/development/analytics/#button-click-analytics
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1 to the button clicks - just wanted to also thank you for that link! i've been hoping to find something like that! 🎉
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@malwilley @saponifi3d We need to track how many users are actually shown this setup button so that we can compare this number to how many people actually click the button and install an integration, I'm not sure if there's a better way than tracking when this button is rendered.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🤔 maybe trigger the onboarding.messaging_integration_modal_rendered
onClick of the modal?
That way you could visualize the usage through:
- Page view
- Modal Open
- Setup Integration
and we'd be able to understand where a user might get stuck trying to setup the integration.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah I think I misread this earlier-- I can definitely change when onboarding.messaging_integration_modal_rendered
is logged to be onClick! The issue is with tracking onboarding.setup_messaging_integration_button_rendered
, because I believe this can only be logged when the button is rendered.
}; | ||
|
||
function SetupMessagingIntegrationButton({ | ||
organization, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of passing in organization
, you can use useOrganization()
inside this component. Makes it so that you don't need to pass that prop around everywhere.
In your test, you can add your test org to the context by doing:
render(<Component />, { organization: mockOrganization })
{...(organization.features.includes( | ||
'messaging-integration-onboarding' | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i'd recommend pulling the organization.features.includes('messaging-integration-onboarding')
into a variable like: hasMessagingIntegration
or isMessagingIntegrationEnabled
and use that variable instead of checking for the features each time.
{...(organization.features.includes( | ||
'messaging-integration-onboarding' | ||
) | ||
? { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
rather than making this a ternary, could we just use &&
logic since there isn't an else case?
@@ -32,6 +33,13 @@ function MessagingIntegrationModal({ | |||
project, | |||
onAddIntegration, | |||
}: Props) { | |||
useEffect(() => { | |||
trackAnalytics('onboarding.messaging_integration_modal_rendered', { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1 to the button clicks - just wanted to also thank you for that link! i've been hoping to find something like that! 🎉
|
||
useEffect(() => { | ||
if (project && !project.hasAlertIntegrationInstalled) { | ||
trackAnalytics('onboarding.messaging_integration_button_rendered', { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@malwilley I saw your other comment about not having logs in modal render but this button we really want analytics for. The way I read this code is that because it's in useEffect and only depends on project and organization this useEffect will be only called once. What would make it be double logged?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since project
is an object, if it were to be refetched the reference would change (even if the actual values didn't) which would trigger this useEffect again. Just pointing out that useEffect
can easily result in more runs than you would expect.
Since there is no action the user takes to get to this state, another way you could log this data is by using useRouteAnalyticsParams
to append a new property to the page view analytic. This is a reliable way of tracking things that are shown to the user: https://develop.sentry.dev/development/analytics/#route-based-frontend-analytics
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you. Will look into it ❤️
@@ -13,11 +13,11 @@ import AddIntegrationRow from 'sentry/views/alerts/rules/issue/addIntegrationRow | |||
import {IntegrationContext} from 'sentry/views/settings/organizationIntegrations/integrationContext'; | |||
|
|||
type Props = ModalRenderProps & { | |||
headerContent: React.ReactElement<any, any>; | |||
headerContent: string; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit:
headerContent: string; | |
headerContent: React.ReactNode; |
which is: string | null | JSX.Element
(basically, it's a catch all for how you're using this variable and the bodyContent
variable. and is closer to the React.ReactElement
type from before)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM 🎉
return null; | ||
} | ||
|
||
// TODO(Mia): only render if organization has team plan and above |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
just want to make sure it's okay to merge w/ this todo.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yup! That will be in my next PR, it's fine for now since this button is hidden behind a feature flag :)
Suspect IssuesThis pull request was deployed and Sentry observed the following issues:
Did you find this useful? React with a 👍 or 👎 |
PR reverted: 064a0e0 |
This reverts commit 26cb3d1. Co-authored-by: ameliahsu <55610339+ameliahsu@users.noreply.github.com>
^ thanks for the quick action and investigation on that failure. is unrelated. 🎉 |
added logging to monitor the impact of new messaging integration onboarding button
also converted setup button from a class component to a functional component which can replace the existing "Set up Slack Now" button