Skip to content
This repository has been archived by the owner on Sep 27, 2024. It is now read-only.

fix(profile): click analytics [MOSOWEB-43] #67

Merged
merged 36 commits into from
Oct 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
bee2259
Merge pull request #65 from MozillaSocial/fix/discover-copy-dropdown
anthony-liddle Oct 17, 2023
c3ef109
fix(profile): make ui_identifiers more specific, add 2 more follow cases
jpezninjo Oct 17, 2023
e62a0b0
fix(profile): click events for more options
jpezninjo Oct 18, 2023
790456e
fix(profile): make dropdown options into buttons
jpezninjo Oct 18, 2023
71ec6cd
fix(profile): events for notify button, add comments to engagementDet…
jpezninjo Oct 18, 2023
98213c7
fix(profile): modify lists
jpezninjo Oct 18, 2023
fc0a7c6
fix(profile): separate profile events into own map
jpezninjo Oct 18, 2023
6e37ff9
fix(profile): events for details (N posts, N followers, N following)
jpezninjo Oct 18, 2023
960b1c3
fix(profile): tabs"
jpezninjo Oct 18, 2023
e1c750b
fix(profile): send glean events directly for follow button so that we…
jpezninjo Oct 18, 2023
7e06e91
fix(profile): fix withdraw follow sends double events, refactor the c…
jpezninjo Oct 18, 2023
ce5e34d
fix(profile): more follow button click function cleanup
jpezninjo Oct 18, 2023
50f23a2
fix(profile): var rename
jpezninjo Oct 18, 2023
c1aad78
fix(profile): move the analytics on mute/block accnt/block domain in …
jpezninjo Oct 18, 2023
97af09d
fix(profiles): add account identifiers to the notifiy button events
jpezninjo Oct 18, 2023
a680560
fix(profile): add account ids to all the other 'more options' menu items
jpezninjo Oct 18, 2023
1a86114
fix(profiles): consolidate a ton of redundantly copied-and-pasted rec…
jpezninjo Oct 18, 2023
b1d2788
fix(profile): make gleanContext optional
jpezninjo Oct 18, 2023
035000d
fix(profile): break out profile events into own file
jpezninjo Oct 18, 2023
41fb0e3
fix(profile): update comments on engagement events list
jpezninjo Oct 18, 2023
5d8cd51
Merge branch 'main' into fix/profile-analytics
jpezninjo Oct 18, 2023
c328875
fix(glean): update event names to use kebab-case
wtfluckey Oct 19, 2023
67e84ca
fix(recordEngagement): add type
wtfluckey Oct 19, 2023
2989ae2
fix(glean): rename profile.notify events
wtfluckey Oct 19, 2023
ad1d671
fix(profile): rename open report identifier
jpezninjo Oct 24, 2023
77851e1
fix(profile): make follow unclick less clever and fix unmute + unfoll…
jpezninjo Oct 24, 2023
386f564
fix(profile): rename follow to follow-btn
jpezninjo Oct 24, 2023
8e333fb
Merge branch 'main' into fix/profile-analytics
jpezninjo Oct 24, 2023
2f4a0b7
fix(profile): fixed the follow button unblock event not firing if you…
jpezninjo Oct 24, 2023
7e256c5
fix(profile): follow button engagement events are using outdated states
jpezninjo Oct 24, 2023
848bdcb
Merge branch 'main' into fix/profile-analytics
jpezninjo Oct 24, 2023
f964cbb
Merge pull request #68 from MozillaSocial/fix/kebab-events
wtfluckey Oct 25, 2023
1e28075
fix(profile): fix one event missed Aly's tab space
jpezninjo Oct 25, 2023
b65df8c
fix(profiles): update engagement types
jpezninjo Oct 25, 2023
68f952b
Merge branch 'main' into fix/profile-analytics
jpezninjo Oct 25, 2023
c535447
Merge branch 'main' into fix/profile-analytics
jpezninjo Oct 25, 2023
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
58 changes: 56 additions & 2 deletions components/account/AccountFollowButton.vue
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
<script setup lang="ts">
import type { mastodon } from 'masto'
import { engagement } from '~~/telemetry/generated/ui'
import { engagementDetails } from '~~/telemetry/engagementDetails'
import { toggleFollowAccount, useRelationship } from '~~/composables/masto/relationship'

const { account, command, context, ...props } = defineProps<{
const { account, command, context, gleanContext, ...props } = defineProps<{
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

gleanContext would be profile in profile.follow.unfollow

Several components use AccountFollowButton

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How do you feel about renaming these ones to include something specific to it being the follow button? For instance profile.follow-btn.unfollow - I feel like that might make it a little more clear but also may be overkill?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought "follow" would be sufficient to denote the button :( but your comment is proof that it isn't. I will change all these to follow-btn

account: mastodon.v1.Account
relationship?: mastodon.v1.Relationship
gleanContext?: string
context?: 'followedBy' | 'following'
command?: boolean
}>()
Expand Down Expand Up @@ -65,6 +68,57 @@ const buttonStyle = $computed(() => {
// If not following, use a button style
return 'text-inverted bg-primary border-primary'
})

const dataGlean = $computed(() => {
if (!gleanContext)
return undefined

let action
if (relationship?.blocking)
action = 'follow-btn.unblock'
else if (relationship?.muting)
action = 'follow-btn.unmute'
else if (relationship ? relationship.following : context === 'following')
action = 'follow-btn.unfollow'
else if (relationship?.requested)
action = 'follow-btn.withdraw-follow-request'
else if ((relationship ? relationship.followedBy : context === 'followedBy') && account.locked)
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this horrendous conditional comes from somewhere else in the <template> code below

action = 'follow-btn.follow-request'
else
action = 'follow-btn.follow'

return `${gleanContext}.${action}`
})

function handleClick() {
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did some clever ordering with the contents of this function. I'm open to some non-clever alternatives

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The reordering of contents in this function might be causing the bug where the unfollow modal shows up when trying to unmute someone

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ooh good catch. I was unaware of this "mixed" use case. That counts as a 7th state for this horrible button component :'(

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's make sure that whatever changes we make, the end result matches what is on production. We don't want to introduce any usability differences in this PR, only analytics events. We can follow up with improvements to this terrible button in a future PR.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pushed up fixing the bug by removing my cleverness and bringing back the original order of events

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verified that I'm no longer seeing that bug!

function recordEngagement() {
engagement.record({
ui_identifier: dataGlean,
mastodon_account_id: account.id,
mastodon_account_handle: account.acct,
...engagementDetails[dataGlean],
})
}

const unfollow = relationship?.following || relationship?.requested

// Make sure recordEngagement is called before making changes to account/relationship
if (relationship?.blocking) {
recordEngagement()
unblock()
}
else if (relationship?.muting) {
recordEngagement()
unmute()
}
else if (unfollow) {
toggleFollowAccount(relationship!, account, dataGlean)
}
else {
recordEngagement()
toggleFollowAccount(relationship!, account)
}
}
</script>

<template>
Expand All @@ -75,7 +129,7 @@ const buttonStyle = $computed(() => {
rounded-full flex="~ gap2 center" font-500 min-w-30 h-fit px3 py1
:class="buttonStyle"
:hover="!relationship?.blocking && !relationship?.muting && relationship?.following ? 'border-red text-red' : 'bg-base border-primary text-primary'"
@click="relationship?.blocking ? unblock() : relationship?.muting ? unmute() : toggleFollowAccount(relationship!, account)"
@click="handleClick"
>
<template v-if="relationship?.blocking">
<span elk-group-hover="hidden">{{ $t('account.blocking') }}</span>
Expand Down
13 changes: 12 additions & 1 deletion components/account/AccountHeader.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<script setup lang="ts">
import type { mastodon } from 'masto'
import { engagement } from '~~/telemetry/generated/ui'
import { engagementDetails } from '~~/telemetry/engagementDetails'

const { account } = defineProps<{
account: mastodon.v1.Account
Expand Down Expand Up @@ -50,6 +52,14 @@ function previewAvatar() {
}

async function toggleNotifications() {
const dataGlean = relationship?.notifying ? 'profile.notify.stop' : 'profile.notify.start'
engagement.record({
ui_identifier: dataGlean,
mastodon_account_id: account.id,
mastodon_account_handle: account.acct,
...engagementDetails[dataGlean],
})

relationship!.notifying = !relationship?.notifying
try {
const newRel = await client.v1.accounts.follow(account.id, { notify: relationship?.notifying })
Expand Down Expand Up @@ -128,7 +138,7 @@ const personalNoteMaxLength = 2000
>
{{ $t('settings.profile.appearance.title') }}
</NuxtLink>
<AccountFollowButton :account="account" :command="command" />
<AccountFollowButton :account="account" :command="command" glean-context="profile" />
<span inset-ie-0 flex gap-2 items-center>
<AccountMoreButton
:account="account" :command="command"
Expand All @@ -153,6 +163,7 @@ const personalNoteMaxLength = 2000
:aria-label="$t('list.modify_account')"
rounded-full text-sm p2 border-1 transition-colors
border-base hover:text-primary
data-glean="profile.modify-lists"
>
<span i-ri:play-list-add-fill block text-current />
</button>
Expand Down
84 changes: 63 additions & 21 deletions components/account/AccountMoreButton.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
<script setup lang="ts">
import type { mastodon } from 'masto'
import { toggleBlockAccount, toggleBlockDomain, toggleMuteAccount } from '~~/composables/masto/relationship'
import { engagement } from '~~/telemetry/generated/ui'
import { engagementDetails } from '~~/telemetry/engagementDetails'

const { account } = defineProps<{
account: mastodon.v1.Account
Expand All @@ -21,39 +23,63 @@ const { client } = $(useMasto())
const useStarFavoriteIcon = usePreferences('useStarFavoriteIcon')
const { share, isSupported: isShareSupported } = useShare()

function recordEngagement(dataGlean: string) {
engagement.record({
ui_identifier: dataGlean,
mastodon_account_id: account.id,
mastodon_account_handle: account.acct,
...engagementDetails[dataGlean],
})
}

function shareAccount() {
recordEngagement('profile.more.share-account')
share({ url: location.href })
}

async function toggleReblogs() {
if (!relationship!.showingReblogs && await openConfirmDialog({
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you're gonna see me separate out condition && openConfirmDialog alot (4 times) in this PR

title: t('confirm.show_reblogs.title', [account.acct]),
confirm: t('confirm.show_reblogs.confirm'),
cancel: t('confirm.show_reblogs.cancel'),
}) !== 'confirm')
return
if (!relationship!.showingReblogs) {
if (await openConfirmDialog({
title: t('confirm.show_reblogs.title', [account.acct]),
confirm: t('confirm.show_reblogs.confirm'),
cancel: t('confirm.show_reblogs.cancel'),
}) !== 'confirm')
return
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

perhaps we should add analytics to the cancel cases of these dialogues?

recordEngagement('profile.more.show-boosts')
}
else {
recordEngagement('profile.more.hide-boosts')
}

const showingReblogs = !relationship?.showingReblogs
relationship = await client.v1.accounts.follow(account.id, { reblogs: showingReblogs })
}

async function addUserNote() {
recordEngagement('profile.more.add-note')
emit('addNote')
}

async function removeUserNote() {
recordEngagement('profile.more.remove-note')

if (!relationship!.note || relationship!.note.length === 0)
return

const newNote = await client.v1.accounts.createNote(account.id, { comment: '' })
relationship!.note = newNote.note
emit('removeNote')
}

function report() {
recordEngagement('profile.more.report.open')
openReportDialog(account)
}
</script>

<template>
<CommonDropdown :eager-mount="command">
<button flex gap-1 items-center w-full rounded op75 hover="op100 text-purple" group aria-label="More actions">
<button flex gap-1 items-center w-full rounded op75 hover="op100 text-purple" group aria-label="More actions" data-glean="profile.more.open">
<div rounded-5 p2 elk-group-hover="bg-purple/10">
<div i-ri:more-2-fill />
</div>
Expand All @@ -62,12 +88,15 @@ async function removeUserNote() {
<template #popper>
<NuxtLink v-if="notLocal" :to="account.url" external target="_blank">
<CommonDropdownItem
is="button"
:text="$t('menu.open_in_original_site')"
icon="i-ri:arrow-right-up-line"
:command="command"
data-glean="profile.more.open-in-original-site"
/>
</NuxtLink>
<CommonDropdownItem
is="button"
v-if="isShareSupported"
:text="`Share @${account.acct}`"
icon="i-ri:share-line"
Expand All @@ -78,26 +107,30 @@ async function removeUserNote() {
<template v-if="currentUser">
<template v-if="!isSelf">
<CommonDropdownItem
is="button"
:text="$t('menu.mention_account', [`@${account.acct}`])"
icon="i-ri:at-line"
:command="command"
@click="mentionUser(account)"
@click="mentionUser(account, 'profile.more.mention')"
/>
<CommonDropdownItem
is="button"
:text="$t('menu.direct_message_account', [`@${account.acct}`])"
icon="i-ri:message-3-line"
:command="command"
@click="directMessageUser(account)"
@click="directMessageUser(account, 'profile.more.direct-message')"
/>

<CommonDropdownItem
is="button"
v-if="!relationship?.showingReblogs"
icon="i-ri:repeat-line"
:text="$t('menu.show_reblogs', [`@${account.acct}`])"
:command="command"
@click="toggleReblogs()"
/>
<CommonDropdownItem
is="button"
v-else
:text="$t('menu.hide_reblogs', [`@${account.acct}`])"
icon="i-ri:repeat-line"
Expand All @@ -106,13 +139,15 @@ async function removeUserNote() {
/>

<CommonDropdownItem
is="button"
v-if="!relationship?.note || relationship?.note?.length === 0"
:text="$t('menu.add_personal_note', [`@${account.acct}`])"
icon="i-ri-edit-2-line"
:command="command"
@click="addUserNote()"
/>
<CommonDropdownItem
is="button"
v-else
:text="$t('menu.remove_personal_note', [`@${account.acct}`])"
icon="i-ri-edit-2-line"
Expand All @@ -121,75 +156,82 @@ async function removeUserNote() {
/>

<CommonDropdownItem
is="button"
v-if="!relationship?.muting"
:text="$t('menu.mute_account', [`@${account.acct}`])"
icon="i-ri:volume-mute-line"
:command="command"
@click="toggleMuteAccount (relationship!, account)"
@click="toggleMuteAccount (relationship!, account, 'profile.more.mute')"
/>
<CommonDropdownItem
is="button"
v-else
:text="$t('menu.unmute_account', [`@${account.acct}`])"
icon="i-ri:volume-up-fill"
:command="command"
@click="toggleMuteAccount (relationship!, account)"
@click="toggleMuteAccount (relationship!, account, 'profile.more.unmute')"
/>

<CommonDropdownItem
is="button"
v-if="!relationship?.blocking"
:text="$t('menu.block_account', [`@${account.acct}`])"
icon="i-ri:forbid-2-line"
:command="command"
@click="toggleBlockAccount (relationship!, account)"
@click="toggleBlockAccount (relationship!, account, 'profile.more.block')"
/>
<CommonDropdownItem
is="button"
v-else
:text="$t('menu.unblock_account', [`@${account.acct}`])"
icon="i-ri:checkbox-circle-line"
:command="command"
@click="toggleBlockAccount (relationship!, account)"
@click="toggleBlockAccount (relationship!, account, 'profile.more.unblock')"
/>

<template v-if="getServerName(account) !== currentServer">
<CommonDropdownItem
is="button"
v-if="!relationship?.domainBlocking"
:text="$t('menu.block_domain', [getServerName(account)])"
icon="i-ri:shut-down-line"
:command="command"
@click="toggleBlockDomain(relationship!, account)"
@click="toggleBlockDomain(relationship!, account, 'profile.more.block-domain')"
/>
<CommonDropdownItem
is="button"
v-else
:text="$t('menu.unblock_domain', [getServerName(account)])"
icon="i-ri:restart-line"
:command="command"
@click="toggleBlockDomain(relationship!, account)"
@click="toggleBlockDomain(relationship!, account, 'profile.more.unblock-domain')"
/>
</template>

<CommonDropdownItem
is="button"
:text="$t('menu.report_account', [`@${account.acct}`])"
icon="i-ri:flag-2-line"
:command="command"
@click="openReportDialog(account)"
@click="report()"
/>
</template>

<template v-else>
<NuxtLink to="/pinned">
<CommonDropdownItem :text="$t('account.pinned')" icon="i-ri:pushpin-line" :command="command" />
<CommonDropdownItem is="button" :text="$t('account.pinned')" icon="i-ri:pushpin-line" :command="command" data-glean="profile.more.goto-pinned" />
</NuxtLink>
<NuxtLink to="/favourites">
<CommonDropdownItem :text="$t('account.favourites')" :icon="useStarFavoriteIcon ? 'i-ri:star-line' : 'i-ri:heart-3-line'" :command="command" />
<CommonDropdownItem is="button" :text="$t('account.favourites')" :icon="useStarFavoriteIcon ? 'i-ri:star-line' : 'i-ri:heart-3-line'" :command="command" data-glean="profile.more.goto-favorites" />
</NuxtLink>
<NuxtLink to="/mutes">
<CommonDropdownItem :text="$t('account.muted_users')" icon="i-ri:volume-mute-line" :command="command" />
<CommonDropdownItem is="button" :text="$t('account.muted_users')" icon="i-ri:volume-mute-line" :command="command" data-glean="profile.more.goto-mutes" />
</NuxtLink>
<NuxtLink to="/blocks">
<CommonDropdownItem :text="$t('account.blocked_users')" icon="i-ri:forbid-2-line" :command="command" />
<CommonDropdownItem is="button" :text="$t('account.blocked_users')" icon="i-ri:forbid-2-line" :command="command" data-glean="profile.more.goto-blocks" />
</NuxtLink>
<NuxtLink to="/domain_blocks">
<CommonDropdownItem :text="$t('account.blocked_domains')" icon="i-ri:shut-down-line" :command="command" />
<CommonDropdownItem is="button" :text="$t('account.blocked_domains')" icon="i-ri:shut-down-line" :command="command" data-glean="profile.more.goto-domain-blocks" />
</NuxtLink>
</template>
</template>
Expand Down
3 changes: 3 additions & 0 deletions components/account/AccountPostsFollowers.vue
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

all NuxtLink's here

Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ const userSettings = useUserSettings()
replace
text-secondary
exact-active-class="text-primary"
data-glean="profile.details.posts"
>
<template #default="{ isExactActive }">
<CommonLocalizedNumber
Expand All @@ -31,6 +32,7 @@ const userSettings = useUserSettings()
:to="getAccountFollowingRoute(account)"
replace
text-secondary exact-active-class="text-primary"
data-glean="profile.details.following"
>
<template #default="{ isExactActive }">
<template
Expand All @@ -56,6 +58,7 @@ const userSettings = useUserSettings()
:to="getAccountFollowersRoute(account)"
replace text-secondary
exact-active-class="text-primary"
data-glean="profile.details.followers"

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not able to get these profile.details.* events to fire in the console. I only see the link_click following by page_view event. Not seeing them log to the Glean ping debugger either.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

image
<a> current require you to click on them directly instead of any nested children

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Whoops this screenshot is for a different UI. But similar reason, the needs to be clicked directly instead of their children -
image

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay cool. I'm sure there are some optimizations we can make, but I don't wanna hold up this PR for that so I'm cool with this for now.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good to me. We can solve this with something applicable to all anchor tags

>
<template #default="{ isExactActive }">
<template v-if="!getPreferences(userSettings, 'hideFollowerCount')">
Expand Down
Loading
Loading