mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-08-31 21:59:10 +08:00
feat: add more tracking events (#6866)
Added most tracking events what is missing: - still need a way to track events in blocksuite - some events may not 100% accurate of the one defined in the PRD
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import { Button, FlexWrapper, notify } from '@affine/component';
|
||||
import { openSettingModalAtom } from '@affine/core/atoms';
|
||||
import { SubscriptionService } from '@affine/core/modules/cloud';
|
||||
import { mixpanel } from '@affine/core/utils';
|
||||
import { WorkspaceFlavour } from '@affine/env/workspace';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { AiIcon } from '@blocksuite/icons';
|
||||
@@ -69,6 +70,11 @@ export const AIOnboardingEdgeless = ({
|
||||
const mode = useLiveData(doc.mode$);
|
||||
|
||||
const goToPricingPlans = useCallback(() => {
|
||||
mixpanel.track('PlansViewed', {
|
||||
page: 'whiteboard editor',
|
||||
segment: 'ai onboarding',
|
||||
module: 'whiteboard dialog',
|
||||
});
|
||||
setSettingModal({
|
||||
open: true,
|
||||
activeTab: 'plans',
|
||||
|
||||
@@ -2,6 +2,7 @@ import { Button, IconButton, Modal } from '@affine/component';
|
||||
import { openSettingModalAtom } from '@affine/core/atoms';
|
||||
import { useBlurRoot } from '@affine/core/hooks/use-blur-root';
|
||||
import { SubscriptionService } from '@affine/core/modules/cloud';
|
||||
import { mixpanel } from '@affine/core/utils';
|
||||
import { WorkspaceFlavour } from '@affine/env/workspace';
|
||||
import { Trans } from '@affine/i18n';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
@@ -122,6 +123,11 @@ export const AIOnboardingGeneral = ({
|
||||
activeTab: 'plans',
|
||||
scrollAnchor: 'aiPricingPlan',
|
||||
});
|
||||
mixpanel.track('PlansViewed', {
|
||||
page: 'whiteboard-editor',
|
||||
segment: 'ai onboarding',
|
||||
module: 'general',
|
||||
});
|
||||
closeAndDismiss();
|
||||
}, [closeAndDismiss, setSettingModal]);
|
||||
const onPrev = useCallback(() => {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { Tooltip } from '@affine/component/ui/tooltip';
|
||||
import { mixpanel } from '@affine/core/utils';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { useLiveData, useServices } from '@toeverything/infra';
|
||||
import { useSetAtom } from 'jotai';
|
||||
@@ -40,6 +41,10 @@ export const UserPlanButton = () => {
|
||||
open: true,
|
||||
activeTab: 'plans',
|
||||
});
|
||||
mixpanel.track('PlansViewed', {
|
||||
segment: 'settings panel',
|
||||
module: 'profile and badge',
|
||||
});
|
||||
},
|
||||
[setSettingModalAtom]
|
||||
);
|
||||
|
||||
@@ -225,6 +225,9 @@ const PlanPrompt = () => {
|
||||
open: true,
|
||||
activeTab: 'plans',
|
||||
});
|
||||
mixpanel.track('PlansViewed', {
|
||||
segment: 'doc history',
|
||||
});
|
||||
}, [setSettingModalAtom]);
|
||||
|
||||
const t = useAFFiNEI18N();
|
||||
@@ -233,7 +236,7 @@ const PlanPrompt = () => {
|
||||
return (
|
||||
<div className={styles.planPromptTitle}>
|
||||
{
|
||||
isProWorkspace === null
|
||||
isProWorkspace !== null
|
||||
? !isProWorkspace
|
||||
? t[
|
||||
'com.affine.history.confirm-restore-modal.plan-prompt.limited-title'
|
||||
|
||||
@@ -3,6 +3,7 @@ import { openQuotaModalAtom, openSettingModalAtom } from '@affine/core/atoms';
|
||||
import { UserQuotaService } from '@affine/core/modules/cloud';
|
||||
import { WorkspacePermissionService } from '@affine/core/modules/permissions';
|
||||
import { WorkspaceQuotaService } from '@affine/core/modules/quota';
|
||||
import { mixpanel } from '@affine/core/utils';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { useLiveData, useService, WorkspaceService } from '@toeverything/infra';
|
||||
import bytes from 'bytes';
|
||||
@@ -48,6 +49,11 @@ export const CloudQuotaModal = () => {
|
||||
activeTab: 'plans',
|
||||
});
|
||||
|
||||
mixpanel.track('PlansViewed', {
|
||||
segment: 'payment wall',
|
||||
category: 'payment wall storage',
|
||||
});
|
||||
|
||||
setOpen(false);
|
||||
}, [setOpen, setSettingModalAtom]);
|
||||
|
||||
|
||||
+7
@@ -6,6 +6,7 @@ import {
|
||||
SubscriptionService,
|
||||
UserCopilotQuotaService,
|
||||
} from '@affine/core/modules/cloud';
|
||||
import { mixpanel } from '@affine/core/utils';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { useLiveData, useService } from '@toeverything/infra';
|
||||
import { cssVar } from '@toeverything/theme';
|
||||
@@ -46,6 +47,12 @@ export const AIUsagePanel = () => {
|
||||
open: true,
|
||||
activeTab: 'billing',
|
||||
});
|
||||
mixpanel.track('BillingViewed', {
|
||||
segment: 'settings panel',
|
||||
module: 'account usage list',
|
||||
control: 'change plan button',
|
||||
type: 'ai subscription',
|
||||
});
|
||||
}, [setOpenSettingModal]);
|
||||
|
||||
if (loading) {
|
||||
|
||||
+5
-2
@@ -162,8 +162,11 @@ const StoragePanel = () => {
|
||||
|
||||
const setSettingModalAtom = useSetAtom(openSettingModalAtom);
|
||||
const onUpgrade = useCallback(() => {
|
||||
mixpanel.track('Button', {
|
||||
resolve: 'UpgradeStorage',
|
||||
mixpanel.track('PlansViewed', {
|
||||
segment: 'settings panel',
|
||||
module: 'account usage list',
|
||||
control: 'cloud storage upgrade button',
|
||||
type: 'cloud subscription',
|
||||
});
|
||||
setSettingModalAtom({
|
||||
open: true,
|
||||
|
||||
+9
-4
@@ -108,17 +108,22 @@ const SubscriptionSettings = () => {
|
||||
|
||||
const openPlans = useCallback(
|
||||
(scrollAnchor?: string) => {
|
||||
mixpanel.track('Button', {
|
||||
resolve: 'ChangePlan',
|
||||
currentPlan: proSubscription?.plan,
|
||||
mixpanel.track('PlansViewed', {
|
||||
type: proSubscription?.plan,
|
||||
category: proSubscription?.recurring,
|
||||
// page:
|
||||
segment: 'settings panel',
|
||||
module: 'billing subscription list',
|
||||
control: 'change plan button',
|
||||
});
|
||||
|
||||
setOpenSettingModalAtom({
|
||||
open: true,
|
||||
activeTab: 'plans',
|
||||
scrollAnchor: scrollAnchor,
|
||||
});
|
||||
},
|
||||
[proSubscription?.plan, setOpenSettingModalAtom]
|
||||
[proSubscription?.plan, proSubscription?.recurring, setOpenSettingModalAtom]
|
||||
);
|
||||
const gotoCloudPlansSetting = useCallback(() => openPlans(), [openPlans]);
|
||||
const gotoAiPlanSetting = useCallback(
|
||||
|
||||
+5
-1
@@ -1,7 +1,7 @@
|
||||
import { Button, type ButtonProps } from '@affine/component';
|
||||
import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks';
|
||||
import { SubscriptionService } from '@affine/core/modules/cloud';
|
||||
import { popupWindow } from '@affine/core/utils';
|
||||
import { mixpanel, popupWindow } from '@affine/core/utils';
|
||||
import { SubscriptionPlan, SubscriptionRecurring } from '@affine/graphql';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { useLiveData, useService } from '@toeverything/infra';
|
||||
@@ -42,6 +42,10 @@ export const AISubscribe = ({ ...btnProps }: AISubscribeProps) => {
|
||||
|
||||
const subscribe = useAsyncCallback(async () => {
|
||||
setMutating(true);
|
||||
mixpanel.track('plan upgrade started', {
|
||||
category: SubscriptionRecurring.Yearly,
|
||||
type: SubscriptionPlan.AI,
|
||||
});
|
||||
try {
|
||||
const session = await subscriptionService.createCheckoutSession({
|
||||
recurring: SubscriptionRecurring.Yearly,
|
||||
|
||||
+26
-7
@@ -115,15 +115,22 @@ export const SettingSidebar = ({
|
||||
const loginStatus = useLiveData(useService(AuthService).session.status$);
|
||||
const generalList = useGeneralSettingList();
|
||||
const onAccountSettingClick = useCallback(() => {
|
||||
mixpanel.track('Button', {
|
||||
resolve: 'AccountSetting',
|
||||
mixpanel.track('AccountSettingsViewed', {
|
||||
// page:
|
||||
segment: 'settings panel',
|
||||
module: 'settings menu',
|
||||
control: 'menu item',
|
||||
});
|
||||
onTabChange('account', null);
|
||||
}, [onTabChange]);
|
||||
const onWorkspaceSettingClick = useCallback(
|
||||
(subTab: WorkspaceSubTab, workspaceMetadata: WorkspaceMetadata) => {
|
||||
mixpanel.track('Button', {
|
||||
resolve: 'WorkspaceSetting',
|
||||
mixpanel.track(`view workspace setting`, {
|
||||
// page:
|
||||
segment: 'settings panel',
|
||||
module: 'settings menu',
|
||||
control: 'menu item',
|
||||
type: subTab,
|
||||
workspaceId: workspaceMetadata.id,
|
||||
});
|
||||
onTabChange(`workspace:${subTab}`, workspaceMetadata);
|
||||
@@ -148,9 +155,21 @@ export const SettingSidebar = ({
|
||||
key={key}
|
||||
title={title}
|
||||
onClick={() => {
|
||||
mixpanel.track('Button', {
|
||||
resolve: key,
|
||||
});
|
||||
if (key === 'billing') {
|
||||
mixpanel.track('BillingViewed', {
|
||||
// page:
|
||||
segment: 'settings panel',
|
||||
module: 'settings menu',
|
||||
control: 'menu item',
|
||||
});
|
||||
} else if (key === 'plans') {
|
||||
mixpanel.track('PlansViewed', {
|
||||
// page:
|
||||
segment: 'settings panel',
|
||||
module: 'settings menu',
|
||||
control: 'menu item',
|
||||
});
|
||||
}
|
||||
onTabChange(key, null);
|
||||
}}
|
||||
data-testid={testId}
|
||||
|
||||
+7
@@ -23,6 +23,7 @@ import { useMembers } from '@affine/core/hooks/affine/use-members';
|
||||
import { useRevokeMemberPermission } from '@affine/core/hooks/affine/use-revoke-member-permission';
|
||||
import { WorkspacePermissionService } from '@affine/core/modules/permissions';
|
||||
import { WorkspaceQuotaService } from '@affine/core/modules/quota';
|
||||
import { mixpanel } from '@affine/core/utils';
|
||||
import { WorkspaceFlavour } from '@affine/env/workspace';
|
||||
import { Permission } from '@affine/graphql';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
@@ -144,6 +145,12 @@ export const CloudWorkspaceMembersPanel = () => {
|
||||
open: true,
|
||||
activeTab: 'plans',
|
||||
});
|
||||
mixpanel.track('PlansViewed', {
|
||||
// page:
|
||||
segment: 'settings panel',
|
||||
module: 'workspace setting',
|
||||
control: 'invite member',
|
||||
});
|
||||
}, [setSettingModalAtom]);
|
||||
|
||||
const listContainerRef = useRef<HTMLDivElement | null>(null);
|
||||
|
||||
+7
@@ -11,6 +11,7 @@ import { Button } from '@affine/component/ui/button';
|
||||
import { Menu, MenuItem, MenuTrigger } from '@affine/component/ui/menu';
|
||||
import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks';
|
||||
import { ShareService } from '@affine/core/modules/share-doc';
|
||||
import { mixpanel } from '@affine/core/utils';
|
||||
import { WorkspaceFlavour } from '@affine/env/workspace';
|
||||
import { PublicPageMode } from '@affine/graphql';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
@@ -101,6 +102,12 @@ export const AffineSharePage = (props: ShareMenuProps) => {
|
||||
await shareService.share.enableShare(
|
||||
mode === 'edgeless' ? PublicPageMode.Edgeless : PublicPageMode.Page
|
||||
);
|
||||
mixpanel.track('ShareCreated', {
|
||||
segment: 'sharing panel',
|
||||
module: 'public share',
|
||||
control: 'share panel',
|
||||
type: mode,
|
||||
});
|
||||
notify.success({
|
||||
title:
|
||||
t[
|
||||
|
||||
+6
-1
@@ -1,5 +1,6 @@
|
||||
import { toast } from '@affine/component';
|
||||
import { getAffineCloudBaseUrl } from '@affine/core/modules/cloud/services/fetch';
|
||||
import { mixpanel } from '@affine/core/utils';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { useCallback, useMemo } from 'react';
|
||||
|
||||
@@ -52,10 +53,14 @@ export const useSharingUrl = ({
|
||||
.catch(err => {
|
||||
console.error(err);
|
||||
});
|
||||
mixpanel.track('ShareLinkCopied', {
|
||||
module: urlType === 'share' ? 'public share' : 'private share',
|
||||
type: 'link',
|
||||
});
|
||||
} else {
|
||||
toast('Network not available');
|
||||
}
|
||||
}, [sharingUrl, t]);
|
||||
}, [sharingUrl, t, urlType]);
|
||||
|
||||
return {
|
||||
sharingUrl,
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { notify } from '@affine/component';
|
||||
import { authAtom, openSettingModalAtom } from '@affine/core/atoms';
|
||||
import { mixpanel } from '@affine/core/utils';
|
||||
import { getBaseUrl } from '@affine/graphql';
|
||||
import { Trans } from '@affine/i18n';
|
||||
import { UnauthorizedError } from '@blocksuite/blocks';
|
||||
@@ -345,6 +346,11 @@ Could you make a new website based on these notes and send back just the html fi
|
||||
getCurrentStore().set(openSettingModalAtom, {
|
||||
activeTab: 'billing',
|
||||
open: true,
|
||||
scrollAnchor: 'aiPricingPlan',
|
||||
});
|
||||
mixpanel.track('PlansViewed', {
|
||||
segment: 'payment wall',
|
||||
category: 'payment wall ai action count',
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -11,6 +11,8 @@ import { Export, MoveToTrash } from '@affine/core/components/page-list';
|
||||
import { useBlockSuiteMetaHelper } from '@affine/core/hooks/affine/use-block-suite-meta-helper';
|
||||
import { useExportPage } from '@affine/core/hooks/affine/use-export-page';
|
||||
import { useTrashModalHelper } from '@affine/core/hooks/affine/use-trash-modal-helper';
|
||||
import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks';
|
||||
import { mixpanel } from '@affine/core/utils';
|
||||
import { WorkspaceFlavour } from '@affine/env/workspace';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import {
|
||||
@@ -97,8 +99,34 @@ export const PageHeaderMenuButton = ({
|
||||
|
||||
const handleDuplicate = useCallback(() => {
|
||||
duplicate(pageId);
|
||||
mixpanel.track('DocCreated', {
|
||||
segment: 'editor header',
|
||||
module: 'header menu',
|
||||
control: 'copy doc',
|
||||
type: 'doc duplicate',
|
||||
category: 'doc',
|
||||
});
|
||||
}, [duplicate, pageId]);
|
||||
|
||||
const onImportFile = useAsyncCallback(async () => {
|
||||
const options = await importFile();
|
||||
if (options.isWorkspaceFile) {
|
||||
mixpanel.track('WorkspaceCreated', {
|
||||
segment: 'editor header',
|
||||
module: 'header menu',
|
||||
control: 'import button',
|
||||
type: 'imported workspace',
|
||||
});
|
||||
} else {
|
||||
mixpanel.track('DocCreated', {
|
||||
segment: 'editor header',
|
||||
module: 'header menu',
|
||||
control: 'import button',
|
||||
type: 'imported doc',
|
||||
});
|
||||
}
|
||||
}, [importFile]);
|
||||
|
||||
const EditMenu = (
|
||||
<>
|
||||
{!isJournal && (
|
||||
@@ -179,7 +207,7 @@ export const PageHeaderMenuButton = ({
|
||||
</MenuIcon>
|
||||
}
|
||||
data-testid="editor-option-menu-import"
|
||||
onSelect={importFile}
|
||||
onSelect={onImportFile}
|
||||
style={menuItemStyle}
|
||||
>
|
||||
{t['Import']()}
|
||||
|
||||
@@ -36,30 +36,47 @@ export const usePageHelper = (docCollection: DocCollection) => {
|
||||
return createPageAndOpen('edgeless');
|
||||
}, [createPageAndOpen]);
|
||||
|
||||
const importFileAndOpen = useAsyncCallback(async () => {
|
||||
const { showImportModal } = await import('@blocksuite/blocks');
|
||||
const onSuccess = (
|
||||
pageIds: string[],
|
||||
options: { isWorkspaceFile: boolean; importedCount: number }
|
||||
) => {
|
||||
toast(
|
||||
`Successfully imported ${options.importedCount} Page${
|
||||
options.importedCount > 1 ? 's' : ''
|
||||
}.`
|
||||
);
|
||||
if (options.isWorkspaceFile) {
|
||||
jumpToSubPath(docCollection.id, WorkspaceSubPath.ALL);
|
||||
return;
|
||||
}
|
||||
const importFileAndOpen = useMemo(
|
||||
() => async () => {
|
||||
const { showImportModal } = await import('@blocksuite/blocks');
|
||||
const { promise, resolve, reject } =
|
||||
Promise.withResolvers<
|
||||
Parameters<
|
||||
NonNullable<Parameters<typeof showImportModal>[0]['onSuccess']>
|
||||
>[1]
|
||||
>();
|
||||
const onSuccess = (
|
||||
pageIds: string[],
|
||||
options: { isWorkspaceFile: boolean; importedCount: number }
|
||||
) => {
|
||||
resolve(options);
|
||||
toast(
|
||||
`Successfully imported ${options.importedCount} Page${
|
||||
options.importedCount > 1 ? 's' : ''
|
||||
}.`
|
||||
);
|
||||
if (options.isWorkspaceFile) {
|
||||
jumpToSubPath(docCollection.id, WorkspaceSubPath.ALL);
|
||||
return;
|
||||
}
|
||||
|
||||
if (pageIds.length === 0) {
|
||||
return;
|
||||
}
|
||||
const pageId = pageIds[0];
|
||||
openPage(docCollection.id, pageId);
|
||||
};
|
||||
showImportModal({ collection: docCollection, onSuccess });
|
||||
}, [docCollection, openPage, jumpToSubPath]);
|
||||
if (pageIds.length === 0) {
|
||||
return;
|
||||
}
|
||||
const pageId = pageIds[0];
|
||||
openPage(docCollection.id, pageId);
|
||||
};
|
||||
showImportModal({
|
||||
collection: docCollection,
|
||||
onSuccess,
|
||||
onFail: message => {
|
||||
reject(new Error(message));
|
||||
},
|
||||
});
|
||||
return await promise;
|
||||
},
|
||||
[docCollection, openPage, jumpToSubPath]
|
||||
);
|
||||
|
||||
const createLinkedPageAndOpen = useAsyncCallback(
|
||||
async (pageId: string) => {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { DropdownButton, Menu } from '@affine/component';
|
||||
import { BlockCard } from '@affine/component/card/block-card';
|
||||
import { mixpanel } from '@affine/core/utils';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { EdgelessIcon, ImportIcon, PageIcon } from '@blocksuite/icons';
|
||||
import type { PropsWithChildren } from 'react';
|
||||
@@ -69,11 +70,27 @@ export const NewPageButton = ({
|
||||
const handleCreateNewPage = useCallback(() => {
|
||||
createNewPage();
|
||||
setOpen(false);
|
||||
mixpanel.track('DocCreated', {
|
||||
page: 'doc library',
|
||||
segment: 'all doc',
|
||||
module: 'doc list header',
|
||||
control: 'new doc button',
|
||||
type: 'doc',
|
||||
category: 'page',
|
||||
});
|
||||
}, [createNewPage]);
|
||||
|
||||
const handleCreateNewEdgeless = useCallback(() => {
|
||||
createNewEdgeless();
|
||||
setOpen(false);
|
||||
mixpanel.track('DocCreated', {
|
||||
page: 'doc library',
|
||||
segment: 'all doc',
|
||||
module: 'doc list header',
|
||||
control: 'new whiteboard button',
|
||||
type: 'doc',
|
||||
category: 'whiteboard',
|
||||
});
|
||||
}, [createNewEdgeless]);
|
||||
|
||||
const handleImportFile = useCallback(() => {
|
||||
@@ -104,10 +121,7 @@ export const NewPageButton = ({
|
||||
>
|
||||
<DropdownButton
|
||||
size={size}
|
||||
onClick={useCallback(() => {
|
||||
createNewPage();
|
||||
setOpen(false);
|
||||
}, [createNewPage])}
|
||||
onClick={handleCreateNewPage}
|
||||
onClickDropDown={useCallback(() => setOpen(open => !open), [])}
|
||||
>
|
||||
{children}
|
||||
|
||||
@@ -9,6 +9,7 @@ import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks';
|
||||
import { useNavigateHelper } from '@affine/core/hooks/use-navigate-helper';
|
||||
import type { Tag } 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 { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import {
|
||||
@@ -46,6 +47,28 @@ export const PageListHeader = () => {
|
||||
return t['com.affine.all-pages.header']();
|
||||
}, [t]);
|
||||
|
||||
const onImportFile = useAsyncCallback(async () => {
|
||||
const options = await importFile();
|
||||
if (options.isWorkspaceFile) {
|
||||
mixpanel.track('WorkspaceCreated', {
|
||||
page: 'doc library',
|
||||
segment: 'all doc',
|
||||
module: 'doc list header',
|
||||
control: 'import button',
|
||||
type: 'imported workspace',
|
||||
});
|
||||
} else {
|
||||
mixpanel.track('DocCreated', {
|
||||
page: 'doc library',
|
||||
segment: 'all doc',
|
||||
module: 'doc list header',
|
||||
control: 'import button',
|
||||
type: 'imported doc',
|
||||
// category
|
||||
});
|
||||
}
|
||||
}, [importFile]);
|
||||
|
||||
return (
|
||||
<div className={styles.docListHeader}>
|
||||
<div className={styles.docListHeaderTitle}>{title}</div>
|
||||
@@ -54,7 +77,7 @@ export const PageListHeader = () => {
|
||||
testId="new-page-button-trigger"
|
||||
onCreateEdgeless={createEdgeless}
|
||||
onCreatePage={createPage}
|
||||
onImportFile={importFile}
|
||||
onImportFile={onImportFile}
|
||||
>
|
||||
<div className={styles.buttonText}>{t['New Page']()}</div>
|
||||
</PageListNewPageButton>
|
||||
|
||||
@@ -12,6 +12,7 @@ import { useBlockSuiteMetaHelper } from '@affine/core/hooks/affine/use-block-sui
|
||||
import { useTrashModalHelper } from '@affine/core/hooks/affine/use-trash-modal-helper';
|
||||
import { FavoriteItemsAdapter } from '@affine/core/modules/properties';
|
||||
import { WorkbenchService } from '@affine/core/modules/workbench';
|
||||
import { mixpanel } from '@affine/core/utils';
|
||||
import type { Collection, DeleteCollectionInfo } from '@affine/env/filter';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import {
|
||||
@@ -96,6 +97,13 @@ export const PageOperationCell = ({
|
||||
|
||||
const onDuplicate = useCallback(() => {
|
||||
duplicate(page.id, false);
|
||||
mixpanel.track('DocCreated', {
|
||||
segment: 'all doc',
|
||||
module: 'doc item menu',
|
||||
control: 'copy doc',
|
||||
type: 'doc duplicate',
|
||||
category: 'doc',
|
||||
});
|
||||
}, [duplicate, page.id]);
|
||||
|
||||
const OperationMenu = (
|
||||
|
||||
@@ -3,6 +3,7 @@ import { useGetDocCollectionPageTitle } from '@affine/core/hooks/use-block-suite
|
||||
import { useJournalHelper } from '@affine/core/hooks/use-journal';
|
||||
import { CollectionService } from '@affine/core/modules/collection';
|
||||
import { WorkspaceSubPath } from '@affine/core/shared';
|
||||
import { mixpanel } from '@affine/core/utils';
|
||||
import type { Collection } from '@affine/env/filter';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import {
|
||||
@@ -235,6 +236,9 @@ export const usePageCommands = () => {
|
||||
page.id,
|
||||
blockId
|
||||
);
|
||||
mixpanel.track('AppendToJournal', {
|
||||
control: 'cmdk',
|
||||
});
|
||||
},
|
||||
icon: <TodayIcon />,
|
||||
});
|
||||
@@ -250,6 +254,10 @@ export const usePageCommands = () => {
|
||||
const page = pageHelper.createPage();
|
||||
page.load();
|
||||
pageMetaHelper.setDocTitle(page.id, query);
|
||||
mixpanel.track('DocCreated', {
|
||||
control: 'cmdk',
|
||||
type: 'doc',
|
||||
});
|
||||
},
|
||||
icon: <PageIcon />,
|
||||
});
|
||||
@@ -265,6 +273,10 @@ export const usePageCommands = () => {
|
||||
const page = pageHelper.createEdgeless();
|
||||
page.load();
|
||||
pageMetaHelper.setDocTitle(page.id, query);
|
||||
mixpanel.track('DocCreated', {
|
||||
control: 'cmdk',
|
||||
type: 'whiteboard',
|
||||
});
|
||||
},
|
||||
icon: <EdgelessIcon />,
|
||||
});
|
||||
|
||||
+17
@@ -1,6 +1,7 @@
|
||||
import { IconButton } from '@affine/component/ui/button';
|
||||
import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks';
|
||||
import { FavoriteItemsAdapter } from '@affine/core/modules/properties';
|
||||
import { mixpanel } from '@affine/core/utils';
|
||||
import { PlusIcon } from '@blocksuite/icons';
|
||||
import type { DocCollection } from '@blocksuite/store';
|
||||
import { useService } from '@toeverything/infra';
|
||||
@@ -24,10 +25,26 @@ export const AddFavouriteButton = ({
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
createLinkedPage(pageId);
|
||||
mixpanel.track('DocCreated', {
|
||||
// page:
|
||||
segment: 'all doc',
|
||||
module: 'favorite',
|
||||
control: 'new fav sub doc',
|
||||
type: 'doc',
|
||||
category: 'page',
|
||||
});
|
||||
} else {
|
||||
const page = createPage();
|
||||
page.load();
|
||||
favAdapter.set(page.id, 'doc', true);
|
||||
mixpanel.track('DocCreated', {
|
||||
// page:
|
||||
segment: 'all doc',
|
||||
module: 'favorite',
|
||||
control: 'new fav doc',
|
||||
type: 'doc',
|
||||
category: 'page',
|
||||
});
|
||||
}
|
||||
},
|
||||
[pageId, createLinkedPage, createPage, favAdapter]
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks';
|
||||
import { mixpanel } from '@affine/core/utils';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { ImportIcon } from '@blocksuite/icons';
|
||||
|
||||
@@ -8,8 +10,31 @@ import { usePageHelper } from '../blocksuite/block-suite-page-list/utils';
|
||||
const ImportPage = ({ docCollection }: { docCollection: DocCollection }) => {
|
||||
const t = useAFFiNEI18N();
|
||||
const { importFile } = usePageHelper(docCollection);
|
||||
|
||||
const onImportFile = useAsyncCallback(async () => {
|
||||
const options = await importFile();
|
||||
if (options.isWorkspaceFile) {
|
||||
mixpanel.track('WorkspaceCreated', {
|
||||
page: 'doc library',
|
||||
segment: 'navigation panel',
|
||||
module: 'doc list header',
|
||||
control: 'import button',
|
||||
type: 'imported workspace',
|
||||
});
|
||||
} else {
|
||||
mixpanel.track('DocCreated', {
|
||||
page: 'doc library',
|
||||
segment: 'navigation panel',
|
||||
module: 'doc list header',
|
||||
control: 'import button',
|
||||
type: 'imported doc',
|
||||
// category
|
||||
});
|
||||
}
|
||||
}, [importFile]);
|
||||
|
||||
return (
|
||||
<MenuItem icon={<ImportIcon />} onClick={importFile}>
|
||||
<MenuItem icon={<ImportIcon />} onClick={onImportFile}>
|
||||
{t['Import']()}
|
||||
</MenuItem>
|
||||
);
|
||||
|
||||
@@ -2,6 +2,7 @@ import { AnimatedDeleteIcon } from '@affine/component';
|
||||
import { getDNDId } from '@affine/core/hooks/affine/use-global-dnd-helper';
|
||||
import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks';
|
||||
import { CollectionService } from '@affine/core/modules/collection';
|
||||
import { mixpanel } from '@affine/core/utils';
|
||||
import { apis, events } from '@affine/electron-api';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { FolderIcon, SettingsIcon } from '@blocksuite/icons';
|
||||
@@ -106,11 +107,23 @@ export const RootAppSidebar = ({
|
||||
)
|
||||
);
|
||||
|
||||
const allPageActive = currentPath === '/all';
|
||||
|
||||
const trashActive = currentPath === '/trash';
|
||||
|
||||
const onClickNewPage = useAsyncCallback(async () => {
|
||||
const page = createPage();
|
||||
page.load();
|
||||
openPage(page.id);
|
||||
}, [createPage, openPage]);
|
||||
mixpanel.track('DocCreated', {
|
||||
page: allPageActive ? 'all' : trashActive ? 'trash' : 'other',
|
||||
segment: 'navigation panel',
|
||||
module: 'bottom button',
|
||||
control: 'new doc button',
|
||||
category: 'page',
|
||||
type: 'doc',
|
||||
});
|
||||
}, [allPageActive, createPage, openPage, trashActive]);
|
||||
|
||||
const { trashModal, setTrashModal, handleOnConfirm } =
|
||||
useTrashModalHelper(docCollection);
|
||||
@@ -166,10 +179,6 @@ export const RootAppSidebar = ({
|
||||
});
|
||||
}, [docCollection.id, collection, navigateHelper, open]);
|
||||
|
||||
const allPageActive = currentPath === '/all';
|
||||
|
||||
const trashActive = currentPath === '/trash';
|
||||
|
||||
return (
|
||||
<AppSidebar
|
||||
clientBorder={appSettings.clientBorder}
|
||||
|
||||
@@ -14,6 +14,7 @@ import {
|
||||
openSettingModalAtom,
|
||||
openSignOutModalAtom,
|
||||
} from '@affine/core/atoms';
|
||||
import { mixpanel } from '@affine/core/utils';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { AccountIcon, SignOutIcon } from '@blocksuite/icons';
|
||||
import { useLiveData, useService } from '@toeverything/infra';
|
||||
@@ -79,6 +80,12 @@ const AccountMenu = () => {
|
||||
const setOpenSignOutModalAtom = useSetAtom(openSignOutModalAtom);
|
||||
|
||||
const onOpenAccountSetting = useCallback(() => {
|
||||
mixpanel.track('AccountSettingsViewed', {
|
||||
// page:
|
||||
segment: 'navigation panel',
|
||||
module: 'profile and badge',
|
||||
control: 'profile and email',
|
||||
});
|
||||
setSettingModalAtom(prev => ({
|
||||
...prev,
|
||||
open: true,
|
||||
|
||||
@@ -23,10 +23,12 @@ export const AppContainer = ({
|
||||
useNoisyBackground,
|
||||
useBlurBackground,
|
||||
children,
|
||||
...rest
|
||||
}: WorkspaceRootProps) => {
|
||||
const noisyBackground = useNoisyBackground && environment.isDesktop;
|
||||
return (
|
||||
<div
|
||||
{...rest}
|
||||
className={clsx(appStyle, {
|
||||
'noisy-background': noisyBackground,
|
||||
'blur-background': environment.isDesktop && useBlurBackground,
|
||||
|
||||
Reference in New Issue
Block a user