feat(core): improve mixpanel (#7652)

move @affine/core/utils/mixpanel -> @affine/core/mixpanel

now you can debug mixpanel on browser devtool

![CleanShot 2024-07-30 at 17.32.48@2x.png](https://graphite-user-uploaded-assets-prod.s3.amazonaws.com/g3jz87HxbjOJpXV3FPT7/083c1286-39fd-4569-b4d2-e6e84cf2e797.png)
This commit is contained in:
EYHN
2024-07-30 13:22:16 +00:00
parent ea7066d02c
commit ab92efcfc0
58 changed files with 221 additions and 149 deletions

View File

@@ -6,7 +6,7 @@ import type { createStore } from 'jotai';
import { openSettingModalAtom, openWorkspaceListModalAtom } from '../atoms'; import { openSettingModalAtom, openWorkspaceListModalAtom } from '../atoms';
import type { useNavigateHelper } from '../hooks/use-navigate-helper'; import type { useNavigateHelper } from '../hooks/use-navigate-helper';
import { mixpanel } from '../utils/mixpanel'; import { mixpanel } from '../mixpanel';
import { registerAffineCommand } from './registry'; import { registerAffineCommand } from './registry';
export function registerAffineNavigationCommands({ export function registerAffineNavigationCommands({

View File

@@ -1,7 +1,7 @@
import { Button, FlexWrapper, notify } from '@affine/component'; import { Button, FlexWrapper, notify } from '@affine/component';
import { openSettingModalAtom } from '@affine/core/atoms'; import { openSettingModalAtom } from '@affine/core/atoms';
import { mixpanel } from '@affine/core/mixpanel';
import { SubscriptionService } from '@affine/core/modules/cloud'; import { SubscriptionService } from '@affine/core/modules/cloud';
import { mixpanel } from '@affine/core/utils';
import { useI18n } from '@affine/i18n'; import { useI18n } from '@affine/i18n';
import { AiIcon } from '@blocksuite/icons/rc'; import { AiIcon } from '@blocksuite/icons/rc';
import { import {

View File

@@ -1,8 +1,8 @@
import { Button, IconButton, Modal } from '@affine/component'; import { Button, IconButton, Modal } from '@affine/component';
import { openSettingModalAtom } from '@affine/core/atoms'; import { openSettingModalAtom } from '@affine/core/atoms';
import { useBlurRoot } from '@affine/core/hooks/use-blur-root'; import { useBlurRoot } from '@affine/core/hooks/use-blur-root';
import { mixpanel } from '@affine/core/mixpanel';
import { AuthService, SubscriptionService } from '@affine/core/modules/cloud'; import { AuthService, SubscriptionService } from '@affine/core/modules/cloud';
import { mixpanel } from '@affine/core/utils';
import { Trans, useI18n } from '@affine/i18n'; import { Trans, useI18n } from '@affine/i18n';
import { ArrowLeftSmallIcon } from '@blocksuite/icons/rc'; import { ArrowLeftSmallIcon } from '@blocksuite/icons/rc';
import { useLiveData, useServices } from '@toeverything/infra'; import { useLiveData, useServices } from '@toeverything/infra';
@@ -117,7 +117,7 @@ export const AIOnboardingGeneral = () => {
scrollAnchor: 'aiPricingPlan', scrollAnchor: 'aiPricingPlan',
}); });
mixpanel.track('PlansViewed', { mixpanel.track('PlansViewed', {
page: 'whiteboard-editor', page: 'whiteboard editor',
segment: 'ai onboarding', segment: 'ai onboarding',
module: 'general', module: 'general',
}); });

View File

@@ -1,6 +1,7 @@
import { notify, Skeleton } from '@affine/component'; import { notify, Skeleton } from '@affine/component';
import { Button } from '@affine/component/ui/button'; import { Button } from '@affine/component/ui/button';
import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks'; import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks';
import { mixpanel } from '@affine/core/mixpanel';
import { OAuthProviderType } from '@affine/graphql'; import { OAuthProviderType } from '@affine/graphql';
import { GithubIcon, GoogleDuotoneIcon } from '@blocksuite/icons/rc'; import { GithubIcon, GoogleDuotoneIcon } from '@blocksuite/icons/rc';
import { useLiveData, useService } from '@toeverything/infra'; import { useLiveData, useService } from '@toeverything/infra';
@@ -8,7 +9,6 @@ import type { ReactElement } from 'react';
import { useState } from 'react'; import { useState } from 'react';
import { AuthService, ServerConfigService } from '../../../modules/cloud'; import { AuthService, ServerConfigService } from '../../../modules/cloud';
import { mixpanel } from '../../../utils';
const OAuthProviderMap: Record< const OAuthProviderMap: Record<
OAuthProviderType, OAuthProviderType,

View File

@@ -3,6 +3,7 @@ import { AuthInput, ModalHeader } from '@affine/component/auth-components';
import { Button } from '@affine/component/ui/button'; import { Button } from '@affine/component/ui/button';
import { authAtom } from '@affine/core/atoms'; import { authAtom } from '@affine/core/atoms';
import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks'; import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks';
import { mixpanel } from '@affine/core/mixpanel';
import { Trans, useI18n } from '@affine/i18n'; import { Trans, useI18n } from '@affine/i18n';
import { ArrowDownBigIcon } from '@blocksuite/icons/rc'; import { ArrowDownBigIcon } from '@blocksuite/icons/rc';
import { useLiveData, useService } from '@toeverything/infra'; import { useLiveData, useService } from '@toeverything/infra';
@@ -12,7 +13,6 @@ import { useCallback, useEffect, useState } from 'react';
import { useSearchParams } from 'react-router-dom'; import { useSearchParams } from 'react-router-dom';
import { AuthService } from '../../../modules/cloud'; import { AuthService } from '../../../modules/cloud';
import { mixpanel } from '../../../utils';
import { emailRegex } from '../../../utils/email-regex'; import { emailRegex } from '../../../utils/email-regex';
import type { AuthPanelProps } from './index'; import type { AuthPanelProps } from './index';
import { OAuth } from './oauth'; import { OAuth } from './oauth';
@@ -74,7 +74,7 @@ export const SignIn: FC<AuthPanelProps> = ({
if (hasPassword) { if (hasPassword) {
setAuthState('signInWithPassword'); setAuthState('signInWithPassword');
} else { } else {
mixpanel.track_forms('SignIn', 'Email', { mixpanel.track('SignIn', {
email, email,
}); });
await authService.sendEmailMagicLink( await authService.sendEmailMagicLink(
@@ -92,7 +92,7 @@ export const SignIn: FC<AuthPanelProps> = ({
challenge, challenge,
searchParams.get('redirect_uri') searchParams.get('redirect_uri')
); );
mixpanel.track_forms('SignUp', 'Email', { mixpanel.track('SignUp', {
email, email,
}); });
setAuthState('afterSignUpSendEmail'); setAuthState('afterSignUpSendEmail');

View File

@@ -1,5 +1,5 @@
import { Tooltip } from '@affine/component/ui/tooltip'; import { Tooltip } from '@affine/component/ui/tooltip';
import { mixpanel } from '@affine/core/utils'; import { mixpanel } from '@affine/core/mixpanel';
import { SubscriptionPlan } from '@affine/graphql'; import { SubscriptionPlan } from '@affine/graphql';
import { useI18n } from '@affine/i18n'; import { useI18n } from '@affine/i18n';
import { useLiveData, useServices } from '@toeverything/infra'; import { useLiveData, useServices } from '@toeverything/infra';

View File

@@ -3,6 +3,7 @@ import type { ConfirmModalProps } from '@affine/component/ui/modal';
import { ConfirmModal, Modal } from '@affine/component/ui/modal'; import { ConfirmModal, Modal } from '@affine/component/ui/modal';
import { authAtom } from '@affine/core/atoms'; import { authAtom } from '@affine/core/atoms';
import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks'; import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks';
import { mixpanel } from '@affine/core/mixpanel';
import { DebugLogger } from '@affine/debug'; import { DebugLogger } from '@affine/debug';
import { apis } from '@affine/electron-api'; import { apis } from '@affine/electron-api';
import { WorkspaceFlavour } from '@affine/env/workspace'; import { WorkspaceFlavour } from '@affine/env/workspace';
@@ -20,7 +21,6 @@ import { useCallback, useLayoutEffect, useState } from 'react';
import { buildShowcaseWorkspace } from '../../../bootstrap/first-app-data'; import { buildShowcaseWorkspace } from '../../../bootstrap/first-app-data';
import { AuthService } from '../../../modules/cloud'; import { AuthService } from '../../../modules/cloud';
import { _addLocalWorkspace } from '../../../modules/workspace-engine'; import { _addLocalWorkspace } from '../../../modules/workspace-engine';
import { mixpanel } from '../../../utils';
import { CloudSvg } from '../share-page-modal/cloud-svg'; import { CloudSvg } from '../share-page-modal/cloud-svg';
import * as styles from './index.css'; import * as styles from './index.css';
@@ -221,7 +221,7 @@ export const CreateWorkspaceModal = ({
const onConfirmName = useAsyncCallback( const onConfirmName = useAsyncCallback(
async (name: string, workspaceFlavour: WorkspaceFlavour) => { async (name: string, workspaceFlavour: WorkspaceFlavour) => {
mixpanel.track_forms('CreateWorkspaceModel', 'CreateWorkspace', { mixpanel.track('CreateWorkspace', {
workspaceFlavour, workspaceFlavour,
}); });
if (loading) return; if (loading) return;

View File

@@ -4,6 +4,7 @@ import { Button, IconButton } from '@affine/component/ui/button';
import { Modal, useConfirmModal } from '@affine/component/ui/modal'; import { Modal, useConfirmModal } from '@affine/component/ui/modal';
import { openSettingModalAtom } from '@affine/core/atoms'; import { openSettingModalAtom } from '@affine/core/atoms';
import { useDocCollectionPageTitle } from '@affine/core/hooks/use-block-suite-workspace-page-title'; import { useDocCollectionPageTitle } from '@affine/core/hooks/use-block-suite-workspace-page-title';
import { mixpanel } from '@affine/core/mixpanel';
import { WorkspacePermissionService } from '@affine/core/modules/permissions'; import { WorkspacePermissionService } from '@affine/core/modules/permissions';
import { WorkspaceQuotaService } from '@affine/core/modules/quota'; import { WorkspaceQuotaService } from '@affine/core/modules/quota';
import { i18nTime, Trans, useI18n } from '@affine/i18n'; import { i18nTime, Trans, useI18n } from '@affine/i18n';
@@ -32,7 +33,6 @@ import {
import { encodeStateAsUpdate } from 'yjs'; import { encodeStateAsUpdate } from 'yjs';
import { pageHistoryModalAtom } from '../../../atoms/page-history'; import { pageHistoryModalAtom } from '../../../atoms/page-history';
import { mixpanel } from '../../../utils';
import { BlockSuiteEditor } from '../../blocksuite/block-suite-editor'; import { BlockSuiteEditor } from '../../blocksuite/block-suite-editor';
import { StyledEditorModeSwitch } from '../../blocksuite/block-suite-mode-switch/style'; import { StyledEditorModeSwitch } from '../../blocksuite/block-suite-mode-switch/style';
import { import {

View File

@@ -1,9 +1,9 @@
import { ConfirmModal } from '@affine/component/ui/modal'; import { ConfirmModal } from '@affine/component/ui/modal';
import { openQuotaModalAtom, openSettingModalAtom } from '@affine/core/atoms'; import { openQuotaModalAtom, openSettingModalAtom } from '@affine/core/atoms';
import { mixpanel } from '@affine/core/mixpanel';
import { UserQuotaService } from '@affine/core/modules/cloud'; import { UserQuotaService } from '@affine/core/modules/cloud';
import { WorkspacePermissionService } from '@affine/core/modules/permissions'; import { WorkspacePermissionService } from '@affine/core/modules/permissions';
import { WorkspaceQuotaService } from '@affine/core/modules/quota'; import { WorkspaceQuotaService } from '@affine/core/modules/quota';
import { mixpanel } from '@affine/core/utils';
import { useI18n } from '@affine/i18n'; import { useI18n } from '@affine/i18n';
import { useLiveData, useService, WorkspaceService } from '@toeverything/infra'; import { useLiveData, useService, WorkspaceService } from '@toeverything/infra';
import bytes from 'bytes'; import bytes from 'bytes';

View File

@@ -1,12 +1,12 @@
import { Button, ErrorMessage, Skeleton } from '@affine/component'; import { Button, ErrorMessage, Skeleton } from '@affine/component';
import { SettingRow } from '@affine/component/setting-components'; import { SettingRow } from '@affine/component/setting-components';
import { openSettingModalAtom } from '@affine/core/atoms'; import { openSettingModalAtom } from '@affine/core/atoms';
import { mixpanel } from '@affine/core/mixpanel';
import { import {
ServerConfigService, ServerConfigService,
SubscriptionService, SubscriptionService,
UserCopilotQuotaService, UserCopilotQuotaService,
} from '@affine/core/modules/cloud'; } from '@affine/core/modules/cloud';
import { mixpanel } from '@affine/core/utils';
import { useI18n } from '@affine/i18n'; import { useI18n } from '@affine/i18n';
import { useLiveData, useService } from '@toeverything/infra'; import { useLiveData, useService } from '@toeverything/infra';
import { cssVar } from '@toeverything/theme'; import { cssVar } from '@toeverything/theme';

View File

@@ -6,6 +6,7 @@ import {
import { Avatar } from '@affine/component/ui/avatar'; import { Avatar } from '@affine/component/ui/avatar';
import { Button } from '@affine/component/ui/button'; import { Button } from '@affine/component/ui/button';
import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks'; import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks';
import { mixpanel } from '@affine/core/mixpanel';
import { useI18n } from '@affine/i18n'; import { useI18n } from '@affine/i18n';
import { ArrowRightSmallIcon, CameraIcon } from '@blocksuite/icons/rc'; import { ArrowRightSmallIcon, CameraIcon } from '@blocksuite/icons/rc';
import { import {
@@ -24,7 +25,6 @@ import {
openSignOutModalAtom, openSignOutModalAtom,
} from '../../../../atoms'; } from '../../../../atoms';
import { AuthService, ServerConfigService } from '../../../../modules/cloud'; import { AuthService, ServerConfigService } from '../../../../modules/cloud';
import { mixpanel } from '../../../../utils';
import { Upload } from '../../../pure/file-upload'; import { Upload } from '../../../pure/file-upload';
import { AIUsagePanel } from './ai-usage-panel'; import { AIUsagePanel } from './ai-usage-panel';
import { StorageProgress } from './storage-progress'; import { StorageProgress } from './storage-progress';
@@ -38,7 +38,7 @@ export const UserAvatar = () => {
const handleUpdateUserAvatar = useAsyncCallback( const handleUpdateUserAvatar = useAsyncCallback(
async (file: File) => { async (file: File) => {
try { try {
mixpanel.track_forms('UpdateProfile', 'UploadAvatar', { mixpanel.track('UploadAvatar', {
userId: account.id, userId: account.id,
}); });
await session.uploadAvatar(file); await session.uploadAvatar(file);
@@ -104,7 +104,7 @@ export const AvatarAndName = () => {
} }
try { try {
mixpanel.track_forms('UpdateProfile', 'UpdateUsername', { mixpanel.track('UpdateUsername', {
userId: account.id, userId: account.id,
}); });
await session.updateLabel(input); await session.updateLabel(input);

View File

@@ -5,13 +5,14 @@ import {
SettingWrapper, SettingWrapper,
} from '@affine/component/setting-components'; } from '@affine/component/setting-components';
import { useAppUpdater } from '@affine/core/hooks/use-app-updater'; import { useAppUpdater } from '@affine/core/hooks/use-app-updater';
import { mixpanel } from '@affine/core/mixpanel';
import { useI18n } from '@affine/i18n'; import { useI18n } from '@affine/i18n';
import { ArrowRightSmallIcon, OpenInNewIcon } from '@blocksuite/icons/rc'; import { ArrowRightSmallIcon, OpenInNewIcon } from '@blocksuite/icons/rc';
import { useCallback } from 'react'; import { useCallback } from 'react';
import { useAppSettingHelper } from '../../../../../hooks/affine/use-app-setting-helper'; import { useAppSettingHelper } from '../../../../../hooks/affine/use-app-setting-helper';
import { appIconMap, appNames } from '../../../../../pages/open-app'; import { appIconMap, appNames } from '../../../../../pages/open-app';
import { mixpanel, popupWindow } from '../../../../../utils'; import { popupWindow } from '../../../../../utils';
import { relatedLinks } from './config'; import { relatedLinks } from './config';
import * as styles from './style.css'; import * as styles from './style.css';
import { UpdateCheckSection } from './update-check-section'; import { UpdateCheckSection } from './update-check-section';

View File

@@ -9,6 +9,7 @@ import { Button, IconButton } from '@affine/component/ui/button';
import { Loading } from '@affine/component/ui/loading'; import { Loading } from '@affine/component/ui/loading';
import { getUpgradeQuestionnaireLink } from '@affine/core/hooks/affine/use-subscription-notify'; import { getUpgradeQuestionnaireLink } from '@affine/core/hooks/affine/use-subscription-notify';
import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks'; import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks';
import { mixpanel } from '@affine/core/mixpanel';
import type { InvoicesQuery } from '@affine/graphql'; import type { InvoicesQuery } from '@affine/graphql';
import { import {
createCustomerPortalMutation, createCustomerPortalMutation,
@@ -32,7 +33,7 @@ import {
import { useMutation } from '../../../../../hooks/use-mutation'; import { useMutation } from '../../../../../hooks/use-mutation';
import { useQuery } from '../../../../../hooks/use-query'; import { useQuery } from '../../../../../hooks/use-query';
import { AuthService, SubscriptionService } from '../../../../../modules/cloud'; import { AuthService, SubscriptionService } from '../../../../../modules/cloud';
import { mixpanel, mixpanelTrack, popupWindow } from '../../../../../utils'; import { popupWindow } from '../../../../../utils';
import { SWRErrorBoundary } from '../../../../pure/swr-error-bundary'; import { SWRErrorBoundary } from '../../../../pure/swr-error-bundary';
import { CancelAction, ResumeAction } from '../plans/actions'; import { CancelAction, ResumeAction } from '../plans/actions';
import { AICancel, AIResume, AISubscribe } from '../plans/ai/actions'; import { AICancel, AIResume, AISubscribe } from '../plans/ai/actions';
@@ -479,7 +480,7 @@ const ResumeSubscription = () => {
const type = subscription.pro$.value?.plan; const type = subscription.pro$.value?.plan;
const category = subscription.pro$.value?.recurring; const category = subscription.pro$.value?.recurring;
if (type && category) { if (type && category) {
mixpanelTrack('PlanChangeStarted', { mixpanel.track('PlanChangeStarted', {
segment: 'settings panel', segment: 'settings panel',
module: 'pricing plan list', module: 'pricing plan list',
control: 'paying', control: 'paying',

View File

@@ -1,7 +1,7 @@
import { getDowngradeQuestionnaireLink } from '@affine/core/hooks/affine/use-subscription-notify'; import { getDowngradeQuestionnaireLink } from '@affine/core/hooks/affine/use-subscription-notify';
import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks'; import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks';
import type { MixpanelEvents } from '@affine/core/mixpanel'; import { mixpanel } from '@affine/core/mixpanel';
import { mixpanelTrack } from '@affine/core/utils'; import type { MixpanelEvents } from '@affine/core/mixpanel/events';
import { SubscriptionPlan } from '@affine/graphql'; import { SubscriptionPlan } from '@affine/graphql';
import { useLiveData, useService } from '@toeverything/infra'; import { useLiveData, useService } from '@toeverything/infra';
import { nanoid } from 'nanoid'; import { nanoid } from 'nanoid';
@@ -36,7 +36,7 @@ export const CancelAction = ({
useEffect(() => { useEffect(() => {
if (!open || !proSubscription) return; if (!open || !proSubscription) return;
mixpanelTrack('PlanChangeStarted', { mixpanel.track('PlanChangeStarted', {
segment: 'settings panel', segment: 'settings panel',
module, module,
control: 'cancel', control: 'cancel',
@@ -58,7 +58,7 @@ export const CancelAction = ({
onOpenChange(false); onOpenChange(false);
const proSubscription = subscription.pro$.value; const proSubscription = subscription.pro$.value;
if (proSubscription) { if (proSubscription) {
mixpanelTrack('PlanChangeSucceeded', { mixpanel.track('PlanChangeSucceeded', {
control: 'cancel', control: 'cancel',
type: proSubscription.plan, type: proSubscription.plan,
category: proSubscription.recurring, category: proSubscription.recurring,
@@ -128,7 +128,7 @@ export const ResumeAction = ({
onOpenChange(false); onOpenChange(false);
const proSubscription = subscription.pro$.value; const proSubscription = subscription.pro$.value;
if (proSubscription) { if (proSubscription) {
mixpanelTrack('PlanChangeSucceeded', { mixpanel.track('PlanChangeSucceeded', {
control: 'paying', control: 'paying',
type: proSubscription.plan, type: proSubscription.plan,
category: proSubscription.recurring, category: proSubscription.recurring,

View File

@@ -2,9 +2,9 @@ import { Button, type ButtonProps, useConfirmModal } from '@affine/component';
import { useDowngradeNotify } from '@affine/core/components/affine/subscription-landing/notify'; import { useDowngradeNotify } from '@affine/core/components/affine/subscription-landing/notify';
import { getDowngradeQuestionnaireLink } from '@affine/core/hooks/affine/use-subscription-notify'; import { getDowngradeQuestionnaireLink } from '@affine/core/hooks/affine/use-subscription-notify';
import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks'; import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks';
import type { MixpanelEvents } from '@affine/core/mixpanel'; import { mixpanel } from '@affine/core/mixpanel';
import type { MixpanelEvents } from '@affine/core/mixpanel/events';
import { AuthService, SubscriptionService } from '@affine/core/modules/cloud'; import { AuthService, SubscriptionService } from '@affine/core/modules/cloud';
import { mixpanel, mixpanelTrack } from '@affine/core/utils';
import { SubscriptionPlan } from '@affine/graphql'; import { SubscriptionPlan } from '@affine/graphql';
import { useI18n } from '@affine/i18n'; import { useI18n } from '@affine/i18n';
import { useService } from '@toeverything/infra'; import { useService } from '@toeverything/infra';
@@ -27,7 +27,7 @@ export const AICancel = ({ module, ...btnProps }: AICancelProps) => {
const cancel = useAsyncCallback(async () => { const cancel = useAsyncCallback(async () => {
const aiSubscription = subscription.ai$.value; const aiSubscription = subscription.ai$.value;
if (aiSubscription) { if (aiSubscription) {
mixpanelTrack('PlanChangeStarted', { mixpanel.track('PlanChangeStarted', {
module, module,
segment: 'settings panel', segment: 'settings panel',
control: 'cancel', control: 'cancel',

View File

@@ -5,9 +5,9 @@ import {
useConfirmModal, useConfirmModal,
} from '@affine/component'; } from '@affine/component';
import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks'; import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks';
import type { MixpanelEvents } from '@affine/core/mixpanel'; import { mixpanel } from '@affine/core/mixpanel';
import type { MixpanelEvents } from '@affine/core/mixpanel/events';
import { SubscriptionService } from '@affine/core/modules/cloud'; import { SubscriptionService } from '@affine/core/modules/cloud';
import { mixpanelTrack } from '@affine/core/utils';
import { SubscriptionPlan } from '@affine/graphql'; import { SubscriptionPlan } from '@affine/graphql';
import { useI18n } from '@affine/i18n'; import { useI18n } from '@affine/i18n';
import { SingleSelectSelectSolidIcon } from '@blocksuite/icons/rc'; import { SingleSelectSelectSolidIcon } from '@blocksuite/icons/rc';
@@ -32,7 +32,7 @@ export const AIResume = ({ module, ...btnProps }: AIResumeProps) => {
const resume = useAsyncCallback(async () => { const resume = useAsyncCallback(async () => {
const aiSubscription = subscription.ai$.value; const aiSubscription = subscription.ai$.value;
if (aiSubscription) { if (aiSubscription) {
mixpanelTrack('PlanChangeStarted', { mixpanel.track('PlanChangeStarted', {
module, module,
segment: 'settings panel', segment: 'settings panel',
control: 'paying', control: 'paying',
@@ -59,7 +59,7 @@ export const AIResume = ({ module, ...btnProps }: AIResumeProps) => {
SubscriptionPlan.AI SubscriptionPlan.AI
); );
if (aiSubscription) { if (aiSubscription) {
mixpanelTrack('PlanChangeSucceeded', { mixpanel.track('PlanChangeSucceeded', {
category: aiSubscription.recurring, category: aiSubscription.recurring,
control: 'paying', control: 'paying',
type: aiSubscription.plan, type: aiSubscription.plan,

View File

@@ -1,8 +1,9 @@
import { Button, type ButtonProps, Skeleton } from '@affine/component'; import { Button, type ButtonProps, Skeleton } from '@affine/component';
import { generateSubscriptionCallbackLink } from '@affine/core/hooks/affine/use-subscription-notify'; import { generateSubscriptionCallbackLink } from '@affine/core/hooks/affine/use-subscription-notify';
import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks'; import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks';
import { mixpanel } from '@affine/core/mixpanel';
import { AuthService, SubscriptionService } from '@affine/core/modules/cloud'; import { AuthService, SubscriptionService } from '@affine/core/modules/cloud';
import { mixpanel, popupWindow } from '@affine/core/utils'; import { popupWindow } from '@affine/core/utils';
import { SubscriptionPlan, SubscriptionRecurring } from '@affine/graphql'; import { SubscriptionPlan, SubscriptionRecurring } from '@affine/graphql';
import { useI18n } from '@affine/i18n'; import { useI18n } from '@affine/i18n';
import { useLiveData, useService } from '@toeverything/infra'; import { useLiveData, useService } from '@toeverything/infra';

View File

@@ -2,8 +2,9 @@ import { Button } from '@affine/component/ui/button';
import { Tooltip } from '@affine/component/ui/tooltip'; import { Tooltip } from '@affine/component/ui/tooltip';
import { generateSubscriptionCallbackLink } from '@affine/core/hooks/affine/use-subscription-notify'; import { generateSubscriptionCallbackLink } from '@affine/core/hooks/affine/use-subscription-notify';
import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks'; import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks';
import { mixpanel } from '@affine/core/mixpanel';
import { AuthService, SubscriptionService } from '@affine/core/modules/cloud'; import { AuthService, SubscriptionService } from '@affine/core/modules/cloud';
import { mixpanelTrack, popupWindow } from '@affine/core/utils'; import { popupWindow } from '@affine/core/utils';
import type { SubscriptionRecurring } from '@affine/graphql'; import type { SubscriptionRecurring } from '@affine/graphql';
import { SubscriptionPlan, SubscriptionStatus } from '@affine/graphql'; import { SubscriptionPlan, SubscriptionStatus } from '@affine/graphql';
import { Trans, useI18n } from '@affine/i18n'; import { Trans, useI18n } from '@affine/i18n';
@@ -16,7 +17,6 @@ import type { HTMLAttributes, PropsWithChildren } from 'react';
import { useCallback, useEffect, useMemo, useState } from 'react'; import { useCallback, useEffect, useMemo, useState } from 'react';
import { authAtom } from '../../../../../atoms/index'; import { authAtom } from '../../../../../atoms/index';
import { mixpanel } from '../../../../../utils';
import { CancelAction, ResumeAction } from './actions'; import { CancelAction, ResumeAction } from './actions';
import type { DynamicPrice, FixedPrice } from './cloud-plans'; import type { DynamicPrice, FixedPrice } from './cloud-plans';
import { ConfirmLoadingModal } from './modals'; import { ConfirmLoadingModal } from './modals';
@@ -337,7 +337,7 @@ const ChangeRecurring = ({
const subscription = useService(SubscriptionService).subscription; const subscription = useService(SubscriptionService).subscription;
const onStartChange = useCallback(() => { const onStartChange = useCallback(() => {
mixpanelTrack('PlanChangeStarted', { mixpanel.track('PlanChangeStarted', {
segment: 'settings panel', segment: 'settings panel',
module: 'pricing plan list', module: 'pricing plan list',
control: 'paying', control: 'paying',
@@ -422,7 +422,7 @@ const ResumeButton = () => {
setOpen(true); setOpen(true);
const pro = subscription.pro$.value; const pro = subscription.pro$.value;
if (pro) { if (pro) {
mixpanelTrack('PlanChangeStarted', { mixpanel.track('PlanChangeStarted', {
segment: 'settings panel', segment: 'settings panel',
module: 'pricing plan list', module: 'pricing plan list',
control: 'paying', control: 'paying',

View File

@@ -6,6 +6,7 @@ import { Avatar } from '@affine/component/ui/avatar';
import { Tooltip } from '@affine/component/ui/tooltip'; import { Tooltip } from '@affine/component/ui/tooltip';
import { WorkspaceAvatar } from '@affine/component/workspace-avatar'; import { WorkspaceAvatar } from '@affine/component/workspace-avatar';
import { useWorkspaceInfo } from '@affine/core/hooks/use-workspace-info'; import { useWorkspaceInfo } from '@affine/core/hooks/use-workspace-info';
import { mixpanel } from '@affine/core/mixpanel';
import { AuthService } from '@affine/core/modules/cloud'; import { AuthService } from '@affine/core/modules/cloud';
import { UserFeatureService } from '@affine/core/modules/cloud/services/user-feature'; import { UserFeatureService } from '@affine/core/modules/cloud/services/user-feature';
import { UNTITLED_WORKSPACE_NAME } from '@affine/env/constant'; import { UNTITLED_WORKSPACE_NAME } from '@affine/env/constant';
@@ -24,7 +25,6 @@ import { useAtom } from 'jotai/react';
import { Suspense, useCallback, useEffect, useMemo } from 'react'; import { Suspense, useCallback, useEffect, useMemo } from 'react';
import { authAtom } from '../../../../atoms'; import { authAtom } from '../../../../atoms';
import { mixpanel } from '../../../../utils';
import { UserPlanButton } from '../../auth/user-plan-button'; import { UserPlanButton } from '../../auth/user-plan-button';
import { useGeneralSettingList } from '../general-setting'; import { useGeneralSettingList } from '../general-setting';
import type { ActiveTab, WorkspaceSubTab } from '../types'; import type { ActiveTab, WorkspaceSubTab } from '../types';

View File

@@ -21,9 +21,9 @@ import { useMemberCount } from '@affine/core/hooks/affine/use-member-count';
import type { Member } from '@affine/core/hooks/affine/use-members'; import type { Member } from '@affine/core/hooks/affine/use-members';
import { useMembers } from '@affine/core/hooks/affine/use-members'; import { useMembers } from '@affine/core/hooks/affine/use-members';
import { useRevokeMemberPermission } from '@affine/core/hooks/affine/use-revoke-member-permission'; import { useRevokeMemberPermission } from '@affine/core/hooks/affine/use-revoke-member-permission';
import { mixpanel } from '@affine/core/mixpanel';
import { WorkspacePermissionService } from '@affine/core/modules/permissions'; import { WorkspacePermissionService } from '@affine/core/modules/permissions';
import { WorkspaceQuotaService } from '@affine/core/modules/quota'; import { WorkspaceQuotaService } from '@affine/core/modules/quota';
import { mixpanel } from '@affine/core/utils';
import { WorkspaceFlavour } from '@affine/env/workspace'; import { WorkspaceFlavour } from '@affine/env/workspace';
import { Permission } from '@affine/graphql'; import { Permission } from '@affine/graphql';
import { useI18n } from '@affine/i18n'; import { useI18n } from '@affine/i18n';

View File

@@ -4,9 +4,9 @@ import { Button } from '@affine/component/ui/button';
import { Menu, MenuItem, MenuTrigger } from '@affine/component/ui/menu'; import { Menu, MenuItem, MenuTrigger } from '@affine/component/ui/menu';
import { useSharingUrl } from '@affine/core/hooks/affine/use-share-url'; import { useSharingUrl } from '@affine/core/hooks/affine/use-share-url';
import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks'; import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks';
import { mixpanel } from '@affine/core/mixpanel';
import { ServerConfigService } from '@affine/core/modules/cloud'; import { ServerConfigService } from '@affine/core/modules/cloud';
import { ShareService } from '@affine/core/modules/share-doc'; import { ShareService } from '@affine/core/modules/share-doc';
import { mixpanel } from '@affine/core/utils';
import { WorkspaceFlavour } from '@affine/env/workspace'; import { WorkspaceFlavour } from '@affine/env/workspace';
import { PublicPageMode } from '@affine/graphql'; import { PublicPageMode } from '@affine/graphql';
import { useI18n } from '@affine/i18n'; import { useI18n } from '@affine/i18n';

View File

@@ -1,8 +1,8 @@
import { mixpanel } from '@affine/core/mixpanel';
import { CloseIcon, DownloadIcon } from '@blocksuite/icons/rc'; import { CloseIcon, DownloadIcon } from '@blocksuite/icons/rc';
import clsx from 'clsx'; import clsx from 'clsx';
import { useCallback, useState } from 'react'; import { useCallback, useState } from 'react';
import { mixpanel } from '../../../utils';
import * as styles from './index.css'; import * as styles from './index.css';
// Although it is called an input, it is actually a button. // Although it is called an input, it is actually a button.

View File

@@ -2,7 +2,7 @@ import { notify } from '@affine/component';
import { authAtom, openSettingModalAtom } from '@affine/core/atoms'; import { authAtom, openSettingModalAtom } from '@affine/core/atoms';
import { AIProvider } from '@affine/core/blocksuite/presets/ai'; import { AIProvider } from '@affine/core/blocksuite/presets/ai';
import { toggleGeneralAIOnboarding } from '@affine/core/components/affine/ai-onboarding/apis'; import { toggleGeneralAIOnboarding } from '@affine/core/components/affine/ai-onboarding/apis';
import { mixpanel } from '@affine/core/utils'; import { mixpanel } from '@affine/core/mixpanel';
import { import {
getBaseUrl, getBaseUrl,
type getCopilotHistoriesQuery, type getCopilotHistoriesQuery,

View File

@@ -1,5 +1,5 @@
import { AIProvider } from '@affine/core/blocksuite/presets/ai'; import { AIProvider } from '@affine/core/blocksuite/presets/ai';
import { mixpanel } from '@affine/core/utils'; import { mixpanel } from '@affine/core/mixpanel';
import type { EditorHost } from '@blocksuite/block-std'; import type { EditorHost } from '@blocksuite/block-std';
import type { BlockModel } from '@blocksuite/store'; import type { BlockModel } from '@blocksuite/store';
import { lowerCase, omit } from 'lodash-es'; import { lowerCase, omit } from 'lodash-es';

View File

@@ -1,5 +1,5 @@
import { mixpanel } from '@affine/core/mixpanel';
import { WorkspacePropertiesAdapter } from '@affine/core/modules/properties'; import { WorkspacePropertiesAdapter } from '@affine/core/modules/properties';
import { mixpanel } from '@affine/core/utils';
import { I18n, i18nTime } from '@affine/i18n'; import { I18n, i18nTime } from '@affine/i18n';
import type { EditorHost } from '@blocksuite/block-std'; import type { EditorHost } from '@blocksuite/block-std';
import type { AffineInlineEditor } from '@blocksuite/blocks'; import type { AffineInlineEditor } from '@blocksuite/blocks';

View File

@@ -2,7 +2,7 @@ import {
AIEdgelessRootBlockSpec, AIEdgelessRootBlockSpec,
AIPageRootBlockSpec, AIPageRootBlockSpec,
} from '@affine/core/blocksuite/presets/ai'; } from '@affine/core/blocksuite/presets/ai';
import { mixpanel } from '@affine/core/utils'; import { mixpanel } from '@affine/core/mixpanel';
import type { import type {
EdgelessRootBlockSpecType, EdgelessRootBlockSpecType,
PageRootBlockSpecType, PageRootBlockSpecType,
@@ -42,7 +42,7 @@ function withAffineRootService(Service: typeof RootService) {
eventName: T, eventName: T,
props: TelemetryEventMap[T] props: TelemetryEventMap[T]
) => { ) => {
mixpanel.track(eventName, props); mixpanel.track(eventName as string, props as Record<string, unknown>);
}, },
}; };
}; };

View File

@@ -7,6 +7,7 @@ import {
toReactNode, toReactNode,
type useConfirmModal, type useConfirmModal,
} from '@affine/component'; } from '@affine/component';
import { mixpanel } from '@affine/core/mixpanel';
import { DocsSearchService } from '@affine/core/modules/docs-search'; import { DocsSearchService } from '@affine/core/modules/docs-search';
import { resolveLinkToDoc } from '@affine/core/modules/navigation'; import { resolveLinkToDoc } from '@affine/core/modules/navigation';
import type { PeekViewService } from '@affine/core/modules/peek-view'; import type { PeekViewService } from '@affine/core/modules/peek-view';
@@ -18,7 +19,6 @@ import {
QuickSearchService, QuickSearchService,
RecentDocsQuickSearchSession, RecentDocsQuickSearchSession,
} from '@affine/core/modules/quicksearch'; } from '@affine/core/modules/quicksearch';
import { mixpanel } from '@affine/core/utils';
import { DebugLogger } from '@affine/debug'; import { DebugLogger } from '@affine/debug';
import type { BlockSpec, WidgetComponent } from '@blocksuite/block-std'; import type { BlockSpec, WidgetComponent } from '@blocksuite/block-std';
import { import {

View File

@@ -18,8 +18,8 @@ import { useEnableCloud } from '@affine/core/hooks/affine/use-enable-cloud';
import { useExportPage } from '@affine/core/hooks/affine/use-export-page'; import { useExportPage } from '@affine/core/hooks/affine/use-export-page';
import { useTrashModalHelper } from '@affine/core/hooks/affine/use-trash-modal-helper'; import { useTrashModalHelper } from '@affine/core/hooks/affine/use-trash-modal-helper';
import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks'; import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks';
import { mixpanel } from '@affine/core/mixpanel';
import { useDetailPageHeaderResponsive } from '@affine/core/pages/workspace/detail-page/use-header-responsive'; import { useDetailPageHeaderResponsive } from '@affine/core/pages/workspace/detail-page/use-header-responsive';
import { mixpanel } from '@affine/core/utils';
import { WorkspaceFlavour } from '@affine/env/workspace'; import { WorkspaceFlavour } from '@affine/env/workspace';
import { useI18n } from '@affine/i18n'; import { useI18n } from '@affine/i18n';
import { import {

View File

@@ -1,5 +1,6 @@
import { Tooltip } from '@affine/component/ui/tooltip'; import { Tooltip } from '@affine/component/ui/tooltip';
import { useBlockSuiteDocMeta } from '@affine/core/hooks/use-block-suite-page-meta'; import { useBlockSuiteDocMeta } from '@affine/core/hooks/use-block-suite-page-meta';
import { mixpanel } from '@affine/core/mixpanel';
import { useI18n } from '@affine/i18n'; import { useI18n } from '@affine/i18n';
import { import {
type DocMode, type DocMode,
@@ -11,7 +12,7 @@ import type { CSSProperties } from 'react';
import { useCallback, useEffect } from 'react'; import { useCallback, useEffect } from 'react';
import type { DocCollection } from '../../../shared'; import type { DocCollection } from '../../../shared';
import { mixpanel, toast } from '../../../utils'; import { toast } from '../../../utils';
import { StyledEditorModeSwitch, StyledKeyboardItem } from './style'; import { StyledEditorModeSwitch, StyledKeyboardItem } from './style';
import { EdgelessSwitchItem, PageSwitchItem } from './switch-items'; import { EdgelessSwitchItem, PageSwitchItem } from './switch-items';

View File

@@ -1,6 +1,6 @@
import { DropdownButton, Menu } from '@affine/component'; import { DropdownButton, Menu } from '@affine/component';
import { BlockCard } from '@affine/component/card/block-card'; import { BlockCard } from '@affine/component/card/block-card';
import { mixpanel } from '@affine/core/utils'; import { mixpanel } from '@affine/core/mixpanel';
import { useI18n } from '@affine/i18n'; import { useI18n } from '@affine/i18n';
import { EdgelessIcon, ImportIcon, PageIcon } from '@blocksuite/icons/rc'; import { EdgelessIcon, ImportIcon, PageIcon } from '@blocksuite/icons/rc';
import type { PropsWithChildren } from 'react'; import type { PropsWithChildren } from 'react';

View File

@@ -7,9 +7,9 @@ import {
} from '@affine/component'; } from '@affine/component';
import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks'; import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks';
import { useNavigateHelper } from '@affine/core/hooks/use-navigate-helper'; import { useNavigateHelper } from '@affine/core/hooks/use-navigate-helper';
import { mixpanel } from '@affine/core/mixpanel';
import type { Tag } from '@affine/core/modules/tag'; import type { Tag } from '@affine/core/modules/tag';
import { TagService } from '@affine/core/modules/tag'; import { TagService } from '@affine/core/modules/tag';
import { mixpanel } from '@affine/core/utils';
import type { Collection } from '@affine/env/filter'; import type { Collection } from '@affine/env/filter';
import { useI18n } from '@affine/i18n'; import { useI18n } from '@affine/i18n';
import { import {

View File

@@ -10,10 +10,10 @@ import {
import { useAppSettingHelper } from '@affine/core/hooks/affine/use-app-setting-helper'; import { useAppSettingHelper } from '@affine/core/hooks/affine/use-app-setting-helper';
import { useBlockSuiteMetaHelper } from '@affine/core/hooks/affine/use-block-suite-meta-helper'; import { useBlockSuiteMetaHelper } from '@affine/core/hooks/affine/use-block-suite-meta-helper';
import { useTrashModalHelper } from '@affine/core/hooks/affine/use-trash-modal-helper'; import { useTrashModalHelper } from '@affine/core/hooks/affine/use-trash-modal-helper';
import { mixpanel } from '@affine/core/mixpanel';
import { FavoriteService } from '@affine/core/modules/favorite'; import { FavoriteService } from '@affine/core/modules/favorite';
import { CompatibleFavoriteItemsAdapter } from '@affine/core/modules/properties'; import { CompatibleFavoriteItemsAdapter } from '@affine/core/modules/properties';
import { WorkbenchService } from '@affine/core/modules/workbench'; import { WorkbenchService } from '@affine/core/modules/workbench';
import { mixpanel } from '@affine/core/utils';
import type { Collection, DeleteCollectionInfo } from '@affine/env/filter'; import type { Collection, DeleteCollectionInfo } from '@affine/env/filter';
import { useI18n } from '@affine/i18n'; import { useI18n } from '@affine/i18n';
import { import {

View File

@@ -1,6 +1,7 @@
import { Loading } from '@affine/component'; import { Loading } from '@affine/component';
import { Divider } from '@affine/component/ui/divider'; import { Divider } from '@affine/component/ui/divider';
import { MenuItem } from '@affine/component/ui/menu'; import { MenuItem } from '@affine/component/ui/menu';
import { mixpanel } from '@affine/core/mixpanel';
import { AuthService } from '@affine/core/modules/cloud'; import { AuthService } from '@affine/core/modules/cloud';
import { useI18n } from '@affine/i18n'; import { useI18n } from '@affine/i18n';
import { Logo1Icon } from '@blocksuite/icons/rc'; import { Logo1Icon } from '@blocksuite/icons/rc';
@@ -13,7 +14,6 @@ import { useSetAtom } from 'jotai';
import { Suspense, useCallback } from 'react'; import { Suspense, useCallback } from 'react';
import { authAtom, openCreateWorkspaceModalAtom } from '../../../../atoms'; import { authAtom, openCreateWorkspaceModalAtom } from '../../../../atoms';
import { mixpanel } from '../../../../utils';
import { AddWorkspace } from './add-workspace'; import { AddWorkspace } from './add-workspace';
import * as styles from './index.css'; import * as styles from './index.css';
import { UserAccountItem } from './user-account'; import { UserAccountItem } from './user-account';

View File

@@ -1,6 +1,6 @@
import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks'; import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks';
import { mixpanel } from '@affine/core/mixpanel';
import { TelemetryWorkspaceContextService } from '@affine/core/modules/telemetry/services/telemetry'; import { TelemetryWorkspaceContextService } from '@affine/core/modules/telemetry/services/telemetry';
import { mixpanel } from '@affine/core/utils';
import { useI18n } from '@affine/i18n'; import { useI18n } from '@affine/i18n';
import { ImportIcon } from '@blocksuite/icons/rc'; import { ImportIcon } from '@blocksuite/icons/rc';
import { useService } from '@toeverything/infra'; import { useService } from '@toeverything/infra';

View File

@@ -1,6 +1,7 @@
import { openSettingModalAtom } from '@affine/core/atoms'; import { openSettingModalAtom } from '@affine/core/atoms';
import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks'; import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks';
import { useNavigateHelper } from '@affine/core/hooks/use-navigate-helper'; import { useNavigateHelper } from '@affine/core/hooks/use-navigate-helper';
import { mixpanel } from '@affine/core/mixpanel';
import { import {
ExplorerCollections, ExplorerCollections,
ExplorerFavorites, ExplorerFavorites,
@@ -12,7 +13,6 @@ import { ExplorerTags } from '@affine/core/modules/explorer/views/sections/tags'
import { CMDKQuickSearchService } from '@affine/core/modules/quicksearch/services/cmdk'; import { CMDKQuickSearchService } from '@affine/core/modules/quicksearch/services/cmdk';
import { TelemetryWorkspaceContextService } from '@affine/core/modules/telemetry/services/telemetry'; import { TelemetryWorkspaceContextService } from '@affine/core/modules/telemetry/services/telemetry';
import { pathGenerator } from '@affine/core/shared'; import { pathGenerator } from '@affine/core/shared';
import { mixpanel } from '@affine/core/utils';
import { apis, events } from '@affine/electron-api'; import { apis, events } from '@affine/electron-api';
import { useI18n } from '@affine/i18n'; import { useI18n } from '@affine/i18n';
import { FolderIcon, SettingsIcon } from '@blocksuite/icons/rc'; import { FolderIcon, SettingsIcon } from '@blocksuite/icons/rc';

View File

@@ -14,7 +14,7 @@ import {
openSettingModalAtom, openSettingModalAtom,
openSignOutModalAtom, openSignOutModalAtom,
} from '@affine/core/atoms'; } from '@affine/core/atoms';
import { mixpanel } from '@affine/core/utils'; import { mixpanel } from '@affine/core/mixpanel';
import { useI18n } from '@affine/i18n'; import { useI18n } from '@affine/i18n';
import { AccountIcon, SignOutIcon } from '@blocksuite/icons/rc'; import { AccountIcon, SignOutIcon } from '@blocksuite/icons/rc';
import { useLiveData, useService } from '@toeverything/infra'; import { useLiveData, useService } from '@toeverything/infra';

View File

@@ -1,10 +1,10 @@
import { Menu } from '@affine/component'; import { Menu } from '@affine/component';
import { mixpanel } from '@affine/core/mixpanel';
import { useService, WorkspacesService } from '@toeverything/infra'; import { useService, WorkspacesService } from '@toeverything/infra';
import { useAtom } from 'jotai'; import { useAtom } from 'jotai';
import { useCallback, useEffect } from 'react'; import { useCallback, useEffect } from 'react';
import { openWorkspaceListModalAtom } from '../../atoms'; import { openWorkspaceListModalAtom } from '../../atoms';
import { mixpanel } from '../../utils';
import { UserWithWorkspaceList } from '../pure/workspace-slider-bar/user-with-workspace-list'; import { UserWithWorkspaceList } from '../pure/workspace-slider-bar/user-with-workspace-list';
import { WorkspaceCard } from '../pure/workspace-slider-bar/workspace-card'; import { WorkspaceCard } from '../pure/workspace-slider-bar/workspace-card';

View File

@@ -2,12 +2,12 @@ import { Button } from '@affine/component/ui/button';
import { AffineShapeIcon } from '@affine/core/components/page-list'; // TODO(@eyhn): import from page-list temporarily, need to defined common svg icon/images management. import { AffineShapeIcon } from '@affine/core/components/page-list'; // TODO(@eyhn): import from page-list temporarily, need to defined common svg icon/images management.
import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks'; import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks';
import { useNavigateHelper } from '@affine/core/hooks/use-navigate-helper'; import { useNavigateHelper } from '@affine/core/hooks/use-navigate-helper';
import { mixpanel } from '@affine/core/mixpanel';
import { WorkspaceSubPath } from '@affine/core/shared'; import { WorkspaceSubPath } from '@affine/core/shared';
import { useI18n } from '@affine/i18n'; import { useI18n } from '@affine/i18n';
import { useLiveData, useService, WorkspaceService } from '@toeverything/infra'; import { useLiveData, useService, WorkspaceService } from '@toeverything/infra';
import { useState } from 'react'; import { useState } from 'react';
import { mixpanel } from '../../utils';
import * as styles from './upgrade.css'; import * as styles from './upgrade.css';
import { ArrowCircleIcon, HeartBreakIcon } from './upgrade-icon'; import { ArrowCircleIcon, HeartBreakIcon } from './upgrade-icon';

View File

@@ -3,7 +3,7 @@ import {
pushGlobalLoadingEventAtom, pushGlobalLoadingEventAtom,
resolveGlobalLoadingEventAtom, resolveGlobalLoadingEventAtom,
} from '@affine/component/global-loading'; } from '@affine/component/global-loading';
import { mixpanel } from '@affine/core/utils'; import { mixpanel } from '@affine/core/mixpanel';
import { apis } from '@affine/electron-api'; import { apis } from '@affine/electron-api';
import { useI18n } from '@affine/i18n'; import { useI18n } from '@affine/i18n';
import type { PageRootService, RootBlockModel } from '@blocksuite/blocks'; import type { PageRootService, RootBlockModel } from '@blocksuite/blocks';

View File

@@ -4,9 +4,9 @@ import {
PreconditionStrategy, PreconditionStrategy,
registerAffineCommand, registerAffineCommand,
} from '@affine/core/commands'; } from '@affine/core/commands';
import { mixpanel } from '@affine/core/mixpanel';
import { CompatibleFavoriteItemsAdapter } from '@affine/core/modules/properties'; import { CompatibleFavoriteItemsAdapter } from '@affine/core/modules/properties';
import { TelemetryWorkspaceContextService } from '@affine/core/modules/telemetry/services/telemetry'; import { TelemetryWorkspaceContextService } from '@affine/core/modules/telemetry/services/telemetry';
import { mixpanel } from '@affine/core/utils';
import { WorkspaceFlavour } from '@affine/env/workspace'; import { WorkspaceFlavour } from '@affine/env/workspace';
import { useI18n } from '@affine/i18n'; import { useI18n } from '@affine/i18n';
import { EdgelessIcon, HistoryIcon, PageIcon } from '@blocksuite/icons/rc'; import { EdgelessIcon, HistoryIcon, PageIcon } from '@blocksuite/icons/rc';

View File

@@ -1,6 +1,6 @@
import { notify } from '@affine/component'; import { notify } from '@affine/component';
import { mixpanel } from '@affine/core/mixpanel';
import { getAffineCloudBaseUrl } from '@affine/core/modules/cloud/services/fetch'; import { getAffineCloudBaseUrl } from '@affine/core/modules/cloud/services/fetch';
import { mixpanel } from '@affine/core/utils';
import { useI18n } from '@affine/i18n'; import { useI18n } from '@affine/i18n';
import type { Disposable } from '@blocksuite/global/utils'; import type { Disposable } from '@blocksuite/global/utils';
import { useCallback, useEffect, useMemo, useState } from 'react'; import { useCallback, useEffect, useMemo, useState } from 'react';

View File

@@ -1,5 +1,5 @@
import { useUpgradeNotify } from '@affine/core/components/affine/subscription-landing/notify'; import { useUpgradeNotify } from '@affine/core/components/affine/subscription-landing/notify';
import { mixpanelTrack } from '@affine/core/utils'; import { mixpanel } from '@affine/core/mixpanel';
import { SubscriptionPlan, SubscriptionRecurring } from '@affine/graphql'; import { SubscriptionPlan, SubscriptionRecurring } from '@affine/graphql';
import { nanoid } from 'nanoid'; import { nanoid } from 'nanoid';
import { useCallback, useEffect } from 'react'; import { useCallback, useEffect } from 'react';
@@ -130,7 +130,7 @@ export const useSubscriptionNotifyReader = () => {
localStorage.removeItem(localStorageKey); localStorage.removeItem(localStorageKey);
// mixpanel // mixpanel
mixpanelTrack('PlanChangeSucceeded', { mixpanel.track('PlanChangeSucceeded', {
category: recurring, category: recurring,
type: plan, type: plan,
control: 'new subscription', control: 'new subscription',

View File

@@ -7,7 +7,8 @@ import { atomWithObservable, atomWithStorage } from 'jotai/utils';
import { useCallback, useState } from 'react'; import { useCallback, useState } from 'react';
import { Observable } from 'rxjs'; import { Observable } from 'rxjs';
import { mixpanel, popupWindow } from '../utils'; import { mixpanel } from '../mixpanel';
import { popupWindow } from '../utils';
import { useAsyncCallback } from './affine-async-hooks'; import { useAsyncCallback } from './affine-async-hooks';
function rpcToObservable< function rpcToObservable<

View File

@@ -0,0 +1,23 @@
import type { PlanChangeStartedEvent } from './plan-change-started';
import type { PlanChangeSucceededEvent } from './plan-change-succeed';
export interface MixpanelEvents {
PlanChangeStarted: PlanChangeStartedEvent;
PlanChangeSucceeded: PlanChangeSucceededEvent;
OAuth: {
provider: string;
};
}
export interface GeneralMixpanelEvent {
// location
page?: string | null;
segment?: string | null;
module?: string | null;
control?: string | null;
// entity
type?: string | null;
category?: string | null;
id?: string | null;
}

View File

@@ -0,0 +1,16 @@
import type { SubscriptionPlan, SubscriptionRecurring } from '@affine/graphql';
/**
* Before subscription plan changed
*/
export interface PlanChangeStartedEvent {
segment?: 'settings panel';
module?: 'pricing plan list' | 'billing subscription list';
control?:
| 'new subscription' // no subscription before
| 'cancel'
| 'paying' // resume: subscribed before
| 'plan cancel action';
type?: SubscriptionPlan;
category?: SubscriptionRecurring;
}

View File

@@ -5,5 +5,5 @@ import type { PlanChangeStartedEvent } from './plan-change-started';
*/ */
export type PlanChangeSucceededEvent = Pick< export type PlanChangeSucceededEvent = Pick<
PlanChangeStartedEvent, PlanChangeStartedEvent,
'control' | 'type' | 'category' 'control' | 'type' | 'category' | 'segment'
>; >;

View File

@@ -1,7 +1,88 @@
import type { PlanChangeStartedEvent } from './plan-change-started'; import { DebugLogger } from '@affine/debug';
import type { PlanChangeSucceededEvent } from './plan-change-succeed'; import type { OverridedMixpanel } from 'mixpanel-browser';
import mixpanelBrowser from 'mixpanel-browser';
export interface MixpanelEvents { import type { GeneralMixpanelEvent, MixpanelEvents } from './events';
PlanChangeStarted: PlanChangeStartedEvent;
PlanChangeSucceeded: PlanChangeSucceededEvent; const logger = new DebugLogger('mixpanel');
function createMixpanel() {
let mixpanel;
if (process.env.MIXPANEL_TOKEN) {
mixpanelBrowser.init(process.env.MIXPANEL_TOKEN || '', {
track_pageview: true,
persistence: 'localStorage',
api_host: 'https://telemetry.affine.run',
});
mixpanel = mixpanelBrowser;
} else {
mixpanel = new Proxy(
function () {} as unknown as OverridedMixpanel,
createProxyHandler()
);
}
const wrapped = {
reset() {
mixpanel.reset();
mixpanel.register({
appVersion: runtimeConfig.appVersion,
environment: runtimeConfig.appBuildType,
editorVersion: runtimeConfig.editorVersion,
isSelfHosted: Boolean(runtimeConfig.isSelfHosted),
isDesktop: environment.isDesktop,
});
},
track<
T extends string,
P extends (T extends keyof MixpanelEvents
? MixpanelEvents[T]
: Record<string, unknown>) &
GeneralMixpanelEvent,
>(event_name: T, properties?: P) {
logger.debug('track', event_name, properties);
mixpanel.track(event_name, properties);
},
opt_out_tracking() {
mixpanel.opt_out_tracking();
},
opt_in_tracking() {
mixpanel.opt_in_tracking();
},
has_opted_in_tracking() {
mixpanel.has_opted_in_tracking();
},
has_opted_out_tracking() {
mixpanel.has_opted_out_tracking();
},
identify(unique_id?: string) {
mixpanel.identify(unique_id);
},
get people() {
return mixpanel.people;
},
track_pageview(properties?: { location?: string }) {
logger.debug('track_pageview', properties);
mixpanel.track_pageview(properties);
},
};
wrapped.reset();
return wrapped;
}
export const mixpanel = createMixpanel();
function createProxyHandler() {
const handler = {
get: () => {
return new Proxy(
function () {} as unknown as OverridedMixpanel,
createProxyHandler()
);
},
apply: () => {},
} as ProxyHandler<OverridedMixpanel>;
return handler;
} }

View File

@@ -0,0 +1,19 @@
// eslint-disable-next-line @typescript-eslint/no-unused-vars, unused-imports/no-unused-imports
import * as mixpanel from 'mixpanel-browser';
import type { GeneralMixpanelEvent, MixpanelEvents } from './events';
declare module 'mixpanel-browser' {
export interface OverridedMixpanel {
track<
T extends string,
P extends (T extends keyof MixpanelEvents
? MixpanelEvents[T]
: Record<string, unknown>) &
GeneralMixpanelEvent,
>(
event_name: T,
properties?: P
): void;
}
}

View File

@@ -1,15 +0,0 @@
import type { SubscriptionPlan, SubscriptionRecurring } from '@affine/graphql';
/**
* Before subscription plan changed
*/
export interface PlanChangeStartedEvent {
segment: 'settings panel';
module: 'pricing plan list' | 'billing subscription list';
control:
| 'new subscription' // no subscription before
| 'cancel'
| 'paying'; // resume: subscribed before
type: SubscriptionPlan;
category: SubscriptionRecurring;
}

View File

@@ -9,7 +9,7 @@ export const Empty = ({
}: { }: {
onDrop: (data: DropTargetDropEvent<AffineDNDData>) => void; onDrop: (data: DropTargetDropEvent<AffineDNDData>) => void;
}) => { }) => {
const { dropTargetRef } = useDropTarget( const { dropTargetRef } = useDropTarget<AffineDNDData>(
() => ({ () => ({
onDrop, onDrop,
}), }),

View File

@@ -1,4 +1,4 @@
import { mixpanel } from '@affine/core/utils'; import { mixpanel } from '@affine/core/mixpanel';
import type { QuotaQuery } from '@affine/graphql'; import type { QuotaQuery } from '@affine/graphql';
import type { WorkspaceScope } from '@toeverything/infra'; import type { WorkspaceScope } from '@toeverything/infra';
import { import {
@@ -31,20 +31,6 @@ export class TelemetryService extends Service {
} }
onApplicationStart() { onApplicationStart() {
if (process.env.MIXPANEL_TOKEN) {
mixpanel.init(process.env.MIXPANEL_TOKEN || '', {
track_pageview: true,
persistence: 'localStorage',
api_host: 'https://telemetry.affine.run',
});
mixpanel.register({
appVersion: runtimeConfig.appVersion,
environment: runtimeConfig.appBuildType,
editorVersion: runtimeConfig.editorVersion,
isSelfHosted: Boolean(runtimeConfig.isSelfHosted),
isDesktop: environment.isDesktop,
});
}
const account = this.auth.session.account$.value; const account = this.auth.session.account$.value;
this.updateIdentity(account); this.updateIdentity(account);
} }

View File

@@ -1,4 +1,4 @@
import { mixpanel } from '@affine/core/utils'; import { mixpanel } from '@affine/core/mixpanel';
import { createEvent, Service } from '@toeverything/infra'; import { createEvent, Service } from '@toeverything/infra';
import { combineLatest, distinctUntilChanged, map, skip } from 'rxjs'; import { combineLatest, distinctUntilChanged, map, skip } from 'rxjs';

View File

@@ -8,8 +8,8 @@ import { EMPTY, mergeMap, switchMap } from 'rxjs';
import { generateSubscriptionCallbackLink } from '../hooks/affine/use-subscription-notify'; import { generateSubscriptionCallbackLink } from '../hooks/affine/use-subscription-notify';
import { RouteLogic, useNavigateHelper } from '../hooks/use-navigate-helper'; import { RouteLogic, useNavigateHelper } from '../hooks/use-navigate-helper';
import { mixpanel } from '../mixpanel';
import { AuthService, SubscriptionService } from '../modules/cloud'; import { AuthService, SubscriptionService } from '../modules/cloud';
import { mixpanel } from '../utils';
import { container } from './subscribe.css'; import { container } from './subscribe.css';
export const Component = () => { export const Component = () => {

View File

@@ -7,7 +7,7 @@ import {
import { Header } from '@affine/core/components/pure/header'; import { Header } from '@affine/core/components/pure/header';
import { WorkspaceModeFilterTab } from '@affine/core/components/pure/workspace-mode-filter-tab'; import { WorkspaceModeFilterTab } from '@affine/core/components/pure/workspace-mode-filter-tab';
import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks'; import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks';
import { mixpanel } from '@affine/core/utils'; import { mixpanel } from '@affine/core/mixpanel';
import type { Filter } from '@affine/env/filter'; import type { Filter } from '@affine/env/filter';
import { PlusIcon } from '@blocksuite/icons/rc'; import { PlusIcon } from '@blocksuite/icons/rc';
import { useService, WorkspaceService } from '@toeverything/infra'; import { useService, WorkspaceService } from '@toeverything/infra';

View File

@@ -2,7 +2,7 @@ import { appSettingAtom } from '@toeverything/infra';
import { useAtomValue } from 'jotai/react'; import { useAtomValue } from 'jotai/react';
import { useLayoutEffect } from 'react'; import { useLayoutEffect } from 'react';
import { mixpanel } from './utils/mixpanel'; import { mixpanel } from './mixpanel';
export function Telemetry() { export function Telemetry() {
const settings = useAtomValue(appSettingAtom); const settings = useAtomValue(appSettingAtom);

View File

@@ -1,6 +1,5 @@
export * from './create-emotion-cache'; export * from './create-emotion-cache';
export * from './fractional-indexing'; export * from './fractional-indexing';
export * from './mixpanel';
export * from './popup'; export * from './popup';
export * from './string2color'; export * from './string2color';
export * from './toast'; export * from './toast';

View File

@@ -1,42 +0,0 @@
import { DebugLogger } from '@affine/debug';
import type { OverridedMixpanel } from 'mixpanel-browser';
import mixpanelBrowser from 'mixpanel-browser';
import type { MixpanelEvents } from '../mixpanel';
const logger = new DebugLogger('affine:mixpanel');
export const mixpanel = process.env.MIXPANEL_TOKEN
? mixpanelBrowser
: new Proxy(
function () {} as unknown as OverridedMixpanel,
createProxyHandler()
);
function createProxyHandler(property?: string | symbol) {
const handler = {
get: (_target, childProperty) => {
const path = property
? String(property) + '.' + String(childProperty)
: String(childProperty);
return new Proxy(
function () {} as unknown as OverridedMixpanel,
createProxyHandler(path)
);
},
apply: (_target, _thisArg, args) => {
logger.debug(
`mixpanel.${property ? String(property) : 'mixpanel'}`,
...args
);
},
} as ProxyHandler<OverridedMixpanel>;
return handler;
}
export function mixpanelTrack<T extends keyof MixpanelEvents>(
event: T,
properties?: MixpanelEvents[T]
) {
return mixpanel.track(event, properties);
}

View File

@@ -10,7 +10,7 @@ export async function waitForEditorLoad(page: Page) {
export async function waitForAllPagesLoad(page: Page) { export async function waitForAllPagesLoad(page: Page) {
// if filters tag is rendered, we believe all_pages is ready // if filters tag is rendered, we believe all_pages is ready
await page.waitForSelector('[data-testid="create-first-filter"]', { await page.waitForSelector('[data-testid="create-first-filter"]', {
timeout: 1000, timeout: 20000,
}); });
} }