chore(core): add more telemetry (#6402)

This commit is contained in:
Brooooooklyn 2024-03-30 07:46:23 +00:00
parent 1c648c2425
commit 822bbb54a4
No known key found for this signature in database
GPG Key ID: 30B1140CE1C07C99
15 changed files with 124 additions and 4 deletions

View File

@ -8,6 +8,7 @@ import { GithubIcon, GoogleDuotoneIcon } from '@blocksuite/icons';
import type { ReactElement } from 'react';
import { useCallback, useState } from 'react';
import { mixpanel } from '../../../utils';
import { useAuth } from './use-auth';
const OAuthProviderMap: Record<
@ -51,6 +52,7 @@ function OAuthProvider({ provider }: { provider: OAuthProviderType }) {
const onClick = useCallback(() => {
setIsConnecting(true);
oauthSignIn(provider);
mixpanel.track('OAuth', { provider });
}, [provider, oauthSignIn]);
return (

View File

@ -91,6 +91,9 @@ export const SignIn: FC<AuthPanelProps> = ({
if (user.hasPassword && !subscriptionData) {
setAuthState('signInWithPassword');
} else {
mixpanel.track_forms('SignIn', 'Email', {
email,
});
const res = await signIn(email, verifyToken, challenge);
if (res?.status === 403 && res?.url === INTERNAL_BETA_URL) {
return setAuthState('noAccess');
@ -103,6 +106,9 @@ export const SignIn: FC<AuthPanelProps> = ({
}
} else {
const res = await signUp(email, verifyToken, challenge);
mixpanel.track_forms('SignUp', 'Email', {
email,
});
if (res?.status === 403 && res?.url === INTERNAL_BETA_URL) {
return setAuthState('noAccess');
} else if (!res || res.status >= 400) {

View File

@ -19,6 +19,7 @@ import { useSetAtom } from 'jotai';
import type { KeyboardEvent } from 'react';
import { useCallback, useLayoutEffect, useState } from 'react';
import { mixpanel } from '../../../utils';
import { CloudSvg } from '../share-page-modal/cloud-svg';
import * as styles from './index.css';
@ -226,6 +227,9 @@ export const CreateWorkspaceModal = ({
const onConfirmName = useAsyncCallback(
async (name: string, workspaceFlavour: WorkspaceFlavour) => {
mixpanel.track_forms('CreateWorkspaceModel', 'CreateWorkspace', {
workspaceFlavour,
});
if (loading) return;
setLoading(true);

View File

@ -27,7 +27,7 @@ import {
import { encodeStateAsUpdate } from 'yjs';
import { pageHistoryModalAtom } from '../../../atoms/page-history';
import { timestampToLocalTime } from '../../../utils';
import { mixpanel, timestampToLocalTime } from '../../../utils';
import { BlockSuiteEditor } from '../../blocksuite/block-suite-editor';
import { StyledEditorModeSwitch } from '../../blocksuite/block-suite-mode-switch/style';
import {
@ -104,9 +104,15 @@ const HistoryEditorPreview = ({
title,
}: HistoryEditorPreviewProps) => {
const onSwitchToPageMode = useCallback(() => {
mixpanel.track('Button', {
resolve: 'HistorySwitchToPageMode',
});
onModeChange('page');
}, [onModeChange]);
const onSwitchToEdgelessMode = useCallback(() => {
mixpanel.track('Button', {
resolve: 'HistorySwitchToEdgelessMode',
});
onModeChange('edgeless');
}, [onModeChange]);
@ -528,6 +534,9 @@ export const GlobalPageHistoryModal = () => {
const workspace = useService(Workspace);
const handleOpenChange = useCallback(
(open: boolean) => {
mixpanel.track('Button', {
resolve: open ? 'OpenPageHistoryModal' : 'ClosePageHistoryModal',
});
setState(prev => ({
...prev,
open,

View File

@ -33,6 +33,7 @@ import { useServerFeatures } from '../../../../hooks/affine/use-server-config';
import { useMutation } from '../../../../hooks/use-mutation';
import { useQuery } from '../../../../hooks/use-query';
import { useUserSubscription } from '../../../../hooks/use-subscription';
import { mixpanel } from '../../../../utils';
import { validateAndReduceImage } from '../../../../utils/reduce-image';
import { Upload } from '../../../pure/file-upload';
import * as styles from './style.css';
@ -52,6 +53,9 @@ export const UserAvatar = () => {
const handleUpdateUserAvatar = useAsyncCallback(
async (file: File) => {
try {
mixpanel.track_forms('UpdateProfile', 'UploadAvatar', {
userId: user.id,
});
const reducedFile = await validateAndReduceImage(file);
const data = await avatarTrigger({
avatar: reducedFile, // Pass the reducedFile directly to the avatarTrigger
@ -74,6 +78,9 @@ export const UserAvatar = () => {
const handleRemoveUserAvatar = useCallback(
async (e: MouseEvent<HTMLButtonElement>) => {
mixpanel.track('RemoveAvatar', {
userId: user.id,
});
e.stopPropagation();
await removeAvatarTrigger();
user.update({ avatarUrl: null });
@ -120,6 +127,9 @@ export const AvatarAndName = () => {
}
try {
mixpanel.track_forms('UpdateProfile', 'UpdateUsername', {
userId: user.id,
});
const data = await updateProfile({
input: { name: input },
});
@ -197,6 +207,9 @@ const StoragePanel = () => {
const setSettingModalAtom = useSetAtom(openSettingModalAtom);
const onUpgrade = useCallback(() => {
mixpanel.track('Button', {
resolve: 'UpgradeStorage',
});
setSettingModalAtom({
open: true,
activeTab: 'plans',

View File

@ -31,6 +31,7 @@ import { useMutation } from '../../../../../hooks/use-mutation';
import { useQuery } from '../../../../../hooks/use-query';
import type { SubscriptionMutator } from '../../../../../hooks/use-subscription';
import { useUserSubscription } from '../../../../../hooks/use-subscription';
import { mixpanel } from '../../../../../utils';
import { SWRErrorBoundary } from '../../../../pure/swr-error-bundary';
import { CancelAction, ResumeAction } from '../plans/actions';
import * as styles from './style.css';
@ -115,11 +116,15 @@ const SubscriptionSettings = () => {
const setOpenSettingModalAtom = useSetAtom(openSettingModalAtom);
const gotoPlansSetting = useCallback(() => {
mixpanel.track('Button', {
resolve: 'ChangePlan',
currentPlan: plan,
});
setOpenSettingModalAtom({
open: true,
activeTab: 'plans',
});
}, [setOpenSettingModalAtom]);
}, [setOpenSettingModalAtom, plan]);
const currentPlanDesc = useMemo(() => {
const messageKey = getMessageKey(plan, recurring);

View File

@ -24,6 +24,7 @@ import { openPaymentDisableAtom } from '../../../../../atoms';
import { authAtom } from '../../../../../atoms/index';
import { useCurrentLoginStatus } from '../../../../../hooks/affine/use-current-login-status';
import { useMutation } from '../../../../../hooks/use-mutation';
import { mixpanel } from '../../../../../utils';
import { CancelAction, ResumeAction } from './actions';
import { BulledListIcon } from './icons/bulled-list';
import { ConfirmLoadingModal } from './modals';
@ -206,6 +207,7 @@ const ActionButton = ({
const mutateAndNotify = useCallback(
(sub: Parameters<SubscriptionMutator>[0]) => {
mixpanel.track_forms('Subscription', detail.plan, sub);
onSubscriptionUpdate?.(sub);
onNotify?.({ detail, recurring });
},
@ -346,6 +348,12 @@ const BookDemo = ({ plan }: { plan: SubscriptionPlan }) => {
href={url}
target="_blank"
rel="noreferrer"
onClick={() => {
mixpanel.track('Button', {
resolve: 'BookDemo',
url,
});
}}
>
<Button className={styles.planAction} type="primary">
{t['com.affine.payment.book-a-demo']()}

View File

@ -26,6 +26,7 @@ import { Suspense, useCallback, useMemo } from 'react';
import { authAtom } from '../../../../atoms';
import { useCurrentLoginStatus } from '../../../../hooks/affine/use-current-login-status';
import { useCurrentUser } from '../../../../hooks/affine/use-current-user';
import { mixpanel } from '../../../../utils';
import { UserPlanButton } from '../../auth/user-plan-button';
import { useGeneralSettingList } from '../general-setting';
import type { ActiveTab, WorkspaceSubTab } from '../types';
@ -115,10 +116,17 @@ export const SettingSidebar = ({
const loginStatus = useCurrentLoginStatus();
const generalList = useGeneralSettingList();
const onAccountSettingClick = useCallback(() => {
mixpanel.track('Button', {
resolve: 'AccountSetting',
});
onTabChange('account', null);
}, [onTabChange]);
const onWorkspaceSettingClick = useCallback(
(subTab: WorkspaceSubTab, workspaceMetadata: WorkspaceMetadata) => {
mixpanel.track('Button', {
resolve: 'WorkspaceSetting',
workspaceId: workspaceMetadata.id,
});
onTabChange(`workspace:${subTab}`, workspaceMetadata);
},
[onTabChange]
@ -141,6 +149,9 @@ export const SettingSidebar = ({
key={key}
title={title}
onClick={() => {
mixpanel.track('Button', {
resolve: key,
});
onTabChange(key, null);
}}
data-testid={testId}

View File

@ -2,6 +2,7 @@ import { CloseIcon, DownloadIcon } from '@blocksuite/icons';
import clsx from 'clsx';
import { useCallback, useState } from 'react';
import { mixpanel } from '../../../utils';
import * as styles from './index.css';
// Although it is called an input, it is actually a button.
@ -20,6 +21,9 @@ export function AppDownloadButton({
// TODO: unify this type of literal value.
const handleClick = useCallback(() => {
mixpanel.track('Button', {
resolve: 'GoToDownloadAppPage',
});
const url = `https://affine.pro/download?channel=stable`;
open(url, '_blank');
}, []);

View File

@ -7,7 +7,7 @@ import type { CSSProperties } from 'react';
import { useCallback, useEffect } from 'react';
import type { DocCollection } from '../../../shared';
import { toast } from '../../../utils';
import { mixpanel, toast } from '../../../utils';
import { StyledEditorModeSwitch, StyledKeyboardItem } from './style';
import { EdgelessSwitchItem, PageSwitchItem } from './switch-items';
@ -67,6 +67,9 @@ export const EditorModeSwitch = ({
}, [currentMode, isPublic, page, pageId, t, trash]);
const onSwitchToPageMode = useCallback(() => {
mixpanel.track('Button', {
resolve: 'SwitchToPageMode',
});
if (currentMode === 'page' || isPublic) {
return;
}
@ -75,6 +78,9 @@ export const EditorModeSwitch = ({
}, [currentMode, isPublic, page, t]);
const onSwitchToEdgelessMode = useCallback(() => {
mixpanel.track('Button', {
resolve: 'SwitchToEdgelessMode',
});
if (currentMode === 'edgeless' || isPublic) {
return;
}

View File

@ -14,6 +14,7 @@ import {
openCreateWorkspaceModalAtom,
openDisableCloudAlertModalAtom,
} from '../../../../atoms';
import { mixpanel } from '../../../../utils';
import { AddWorkspace } from './add-workspace';
import * as styles from './index.css';
import { UserAccountItem } from './user-account';
@ -27,6 +28,9 @@ export const SignInItem = () => {
const t = useAFFiNEI18N();
const onClickSignIn = useCallback(() => {
mixpanel.track('Button', {
resolve: 'SignIn',
});
if (!runtimeConfig.enableCloud) {
setDisableCloudOpen(true);
} else {
@ -104,6 +108,9 @@ const UserWithWorkspaceListInner = ({
) {
return openSignInModal();
}
mixpanel.track('Button', {
resolve: 'NewWorkspace',
});
setOpenCreateWorkspaceModal('new');
onEventEnd?.();
}, [
@ -114,6 +121,9 @@ const UserWithWorkspaceListInner = ({
]);
const onAddWorkspace = useCallback(() => {
mixpanel.track('Button', {
resolve: 'AddWorkspace',
});
setOpenCreateWorkspaceModal('add');
onEventEnd?.();
}, [onEventEnd, setOpenCreateWorkspaceModal]);

View File

@ -3,6 +3,7 @@ import { useAtom } from 'jotai';
import { Suspense, useCallback } from 'react';
import { openWorkspaceListModalAtom } from '../../atoms';
import { mixpanel } from '../../utils';
import { UserWithWorkspaceList } from '../pure/workspace-slider-bar/user-with-workspace-list';
import { WorkspaceCard } from '../pure/workspace-slider-bar/workspace-card';
@ -14,6 +15,9 @@ export const WorkspaceSelector = () => {
setOpenUserWorkspaceList(false);
}, [setOpenUserWorkspaceList]);
const openUserWorkspaceList = useCallback(() => {
mixpanel.track('Button', {
resolve: 'OpenWorkspaceList',
});
setOpenUserWorkspaceList(true);
}, [setOpenUserWorkspaceList]);

View File

@ -8,6 +8,7 @@ import { useService, Workspace, WorkspaceManager } from '@toeverything/infra';
import { useState } from 'react';
import { WorkspaceSubPath } from '../../shared';
import { mixpanel } from '../../utils';
import * as styles from './upgrade.css';
import { ArrowCircleIcon, HeartBreakIcon } from './upgrade-icon';
@ -27,6 +28,10 @@ export const WorkspaceUpgrade = function WorkspaceUpgrade() {
return;
}
mixpanel.track('Button', {
resolve: 'UpgradeWorkspace',
});
try {
const newWorkspace =
await currentWorkspace.upgrade.upgrade(workspaceManager);

View File

@ -7,6 +7,7 @@ import { atomWithObservable, atomWithStorage } from 'jotai/utils';
import { useCallback, useState } from 'react';
import { Observable } from 'rxjs';
import { mixpanel } from '../utils';
import { useAsyncCallback } from './affine-async-hooks';
function rpcToObservable<
@ -120,6 +121,9 @@ export const useAppUpdater = () => {
);
const quitAndInstall = useCallback(() => {
mixpanel.track('Button', {
resolve: 'QuitAndInstall',
});
if (updateReady) {
setAppQuitting(true);
apis?.updater.quitAndInstall().catch(err => {
@ -130,6 +134,9 @@ export const useAppUpdater = () => {
}, [updateReady]);
const checkForUpdates = useCallback(async () => {
mixpanel.track('Button', {
resolve: 'CheckForUpdates',
});
if (checkingForUpdates) {
return;
}
@ -146,6 +153,9 @@ export const useAppUpdater = () => {
}, [checkingForUpdates, setCheckingForUpdates]);
const downloadUpdate = useCallback(() => {
mixpanel.track('Button', {
resolve: 'DownloadUpdate',
});
apis?.updater.downloadUpdate().catch(err => {
console.error('Error downloading update:', err);
});
@ -153,6 +163,10 @@ export const useAppUpdater = () => {
const toggleAutoDownload = useCallback(
(enable: boolean) => {
mixpanel.track('Button', {
resolve: 'ToggleAutoDownload',
value: enable,
});
setSetting({
autoDownloadUpdate: enable,
});
@ -162,6 +176,10 @@ export const useAppUpdater = () => {
const toggleAutoCheck = useCallback(
(enable: boolean) => {
mixpanel.track('Button', {
resolve: 'ToggleAutoCheck',
value: enable,
});
setSetting({
autoCheckUpdate: enable,
});
@ -170,11 +188,17 @@ export const useAppUpdater = () => {
);
const openChangelog = useAsyncCallback(async () => {
mixpanel.track('Button', {
resolve: 'OpenChangelog',
});
window.open(runtimeConfig.changelogUrl, '_blank');
await setChangelogUnread(true);
}, [setChangelogUnread]);
const dismissChangelog = useAsyncCallback(async () => {
mixpanel.track('Button', {
resolve: 'DismissChangelog',
});
await setChangelogUnread(true);
}, [setChangelogUnread]);

View File

@ -47,6 +47,7 @@ import {
} from '../providers/modal-provider';
import { SWRConfigProvider } from '../providers/swr-config-provider';
import { pathGenerator } from '../shared';
import { mixpanel } from '../utils';
import * as styles from './styles.css';
const CMDKQuickSearchModal = lazy(() =>
@ -60,6 +61,14 @@ export const QuickSearch = () => {
openQuickSearchModalAtom
);
const onToggleQuickSearch = useCallback(
(open: boolean) => {
mixpanel.track('QuickSearch', { open });
setOpenQuickSearchModalAtom(open);
},
[setOpenQuickSearchModalAtom]
);
const workbench = useService(Workbench);
const currentPath = useLiveData(workbench.location$.map(l => l.pathname));
const pageRecordList = useService(PageRecordList);
@ -73,7 +82,7 @@ export const QuickSearch = () => {
return (
<CMDKQuickSearchModal
open={openQuickSearchModal}
onOpenChange={setOpenQuickSearchModalAtom}
onOpenChange={onToggleQuickSearch}
pageMeta={pageMeta}
/>
);