From b343f975fbba74cf46132fcb9666a286a5a38bf8 Mon Sep 17 00:00:00 2001 From: EYHN Date: Tue, 30 Jul 2024 13:22:21 +0000 Subject: [PATCH] feat(core): add track events for sidebar (#7659) --- .../explorer/views/nodes/collection/index.tsx | 18 ++- .../views/nodes/collection/operations.tsx | 34 +++++- .../explorer/views/nodes/doc/index.tsx | 16 +++ .../explorer/views/nodes/doc/operations.tsx | 28 +++++ .../explorer/views/nodes/folder/index.tsx | 112 +++++++++++++++++- .../explorer/views/nodes/tag/index.tsx | 13 +- .../explorer/views/nodes/tag/operations.tsx | 28 +++++ .../views/sections/collections/index.tsx | 6 + .../views/sections/favorites/index.tsx | 34 ++++++ .../sections/migration-favorites/index.tsx | 16 +++ .../views/sections/organize/index.tsx | 13 ++ .../explorer/views/sections/tags/index.tsx | 6 + 12 files changed, 316 insertions(+), 8 deletions(-) diff --git a/packages/frontend/core/src/modules/explorer/views/nodes/collection/index.tsx b/packages/frontend/core/src/modules/explorer/views/nodes/collection/index.tsx index 7f72c3ad94..d5af9da23a 100644 --- a/packages/frontend/core/src/modules/explorer/views/nodes/collection/index.tsx +++ b/packages/frontend/core/src/modules/explorer/views/nodes/collection/index.tsx @@ -10,6 +10,7 @@ import { filterPage, useEditCollection, } from '@affine/core/components/page-list'; +import { mixpanel } from '@affine/core/mixpanel'; import { CollectionService } from '@affine/core/modules/collection'; import { CompatibleFavoriteItemsAdapter } from '@affine/core/modules/properties'; import { ShareDocsService } from '@affine/core/modules/share-doc'; @@ -77,11 +78,16 @@ export const ExplorerCollectionNode = ({ const handleRename = useCallback( (name: string) => { - if (collection) { + if (collection && collection.name !== name) { collectionService.updateCollection(collectionId, () => ({ ...collection, name, })); + mixpanel.track('CollectionRenamed', { + page: 'sidebar', + module: 'collection', + control: 'rename collection', + }); toast(t['com.affine.toastMessage.rename']()); } }, @@ -107,6 +113,11 @@ export const ExplorerCollectionNode = ({ if (collection && data.treeInstruction?.type === 'make-child') { if (data.source.data.entity?.type === 'doc') { handleAddDocToCollection(data.source.data.entity.id); + mixpanel.track('AddDocToCollection', { + page: 'sidebar', + module: 'collection', + control: 'drop doc on collection', + }); } } else { onDrop?.(data); @@ -133,6 +144,11 @@ export const ExplorerCollectionNode = ({ (data: DropTargetDropEvent) => { if (collection && data.source.data.entity?.type === 'doc') { handleAddDocToCollection(data.source.data.entity.id); + mixpanel.track('AddDocToCollection', { + page: 'sidebar', + module: 'collection', + control: 'drop doc on collection', + }); } }, [collection, handleAddDocToCollection] diff --git a/packages/frontend/core/src/modules/explorer/views/nodes/collection/operations.tsx b/packages/frontend/core/src/modules/explorer/views/nodes/collection/operations.tsx index 2862904dda..b422eeb55d 100644 --- a/packages/frontend/core/src/modules/explorer/views/nodes/collection/operations.tsx +++ b/packages/frontend/core/src/modules/explorer/views/nodes/collection/operations.tsx @@ -7,6 +7,7 @@ import { } from '@affine/component'; import { useAppSettingHelper } from '@affine/core/hooks/affine/use-app-setting-helper'; import { useDeleteCollectionInfo } from '@affine/core/hooks/affine/use-delete-collection-info'; +import { mixpanel } from '@affine/core/mixpanel'; import { CollectionService } from '@affine/core/modules/collection'; import { CompatibleFavoriteItemsAdapter } from '@affine/core/modules/properties'; import { WorkbenchService } from '@affine/core/modules/workbench'; @@ -56,6 +57,16 @@ export const useExplorerCollectionNodeOperations = ( const createAndAddDocument = useCallback(() => { const newDoc = docsService.createDoc(); collectionService.addPageToCollection(collectionId, newDoc.id); + mixpanel.track('DocCreated', { + page: 'sidebar', + module: 'collection', + control: 'add doc button', + }); + mixpanel.track('AddDocToCollection', { + page: 'sidebar', + module: 'collection', + control: 'add doc button', + }); workbenchService.workbench.openDoc(newDoc.id); onOpenCollapsed(); }, [ @@ -66,8 +77,15 @@ export const useExplorerCollectionNodeOperations = ( workbenchService.workbench, ]); - const handleToggleFavoritePage = useCallback(() => { + const handleToggleFavoriteCollection = useCallback(() => { compatibleFavoriteItemsAdapter.toggle(collectionId, 'collection'); + mixpanel.track('ToggleFavorite', { + page: 'sidebar', + module: 'collection', + control: 'toggle favorite collection button', + type: 'collection', + id: collectionId, + }); }, [compatibleFavoriteItemsAdapter, collectionId]); const handleAddDocToCollection = useCallback(() => { @@ -85,10 +103,20 @@ export const useExplorerCollectionNodeOperations = ( const handleOpenInSplitView = useCallback(() => { workbenchService.workbench.openCollection(collectionId, { at: 'beside' }); + mixpanel.track('OpenInSplitView', { + page: 'sidebar', + module: 'collection', + control: 'open in split view button', + }); }, [collectionId, workbenchService.workbench]); const handleDeleteCollection = useCallback(() => { collectionService.deleteCollection(deleteInfo, collectionId); + mixpanel.track('CollectionDeleted', { + page: 'sidebar', + module: 'collection', + control: 'delete collection button', + }); }, [collectionId, collectionService, deleteInfo]); const handleShowEdit = useCallback(() => { @@ -155,7 +183,7 @@ export const useExplorerCollectionNodeOperations = ( )} } - onClick={handleToggleFavoritePage} + onClick={handleToggleFavoriteCollection} > {favorite ? t['com.affine.favoritePageOperation.remove']() @@ -210,7 +238,7 @@ export const useExplorerCollectionNodeOperations = ( handleDeleteCollection, handleOpenInSplitView, handleShowEdit, - handleToggleFavoritePage, + handleToggleFavoriteCollection, t, ] ); diff --git a/packages/frontend/core/src/modules/explorer/views/nodes/doc/index.tsx b/packages/frontend/core/src/modules/explorer/views/nodes/doc/index.tsx index ef44b236ed..c43563ec9b 100644 --- a/packages/frontend/core/src/modules/explorer/views/nodes/doc/index.tsx +++ b/packages/frontend/core/src/modules/explorer/views/nodes/doc/index.tsx @@ -7,6 +7,7 @@ import { } from '@affine/component'; import { InfoModal } from '@affine/core/components/affine/page-properties'; import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks'; +import { mixpanel } from '@affine/core/mixpanel'; import { DocsSearchService } from '@affine/core/modules/docs-search'; import type { AffineDNDData } from '@affine/core/types/dnd'; import { useI18n } from '@affine/i18n'; @@ -115,6 +116,11 @@ export const ExplorerDocNode = ({ const handleRename = useAsyncCallback( async (newName: string) => { await docsService.changeDocTitle(docId, newName); + mixpanel.track('DocRenamed', { + page: 'sidebar', + module: 'doc', + control: 'doc rename', + }); }, [docId, docsService] ); @@ -124,6 +130,11 @@ export const ExplorerDocNode = ({ if (data.treeInstruction?.type === 'make-child') { if (data.source.data.entity?.type === 'doc') { await docsService.addLinkedDoc(docId, data.source.data.entity.id); + mixpanel.track('LinkedDocCreated', { + page: 'sidebar', + module: 'doc', + control: 'drop doc on doc', + }); } else { toast(t['com.affine.rootAppSidebar.doc.link-doc-only']()); } @@ -153,6 +164,11 @@ export const ExplorerDocNode = ({ if (data.source.data.entity?.type === 'doc') { // TODO(eyhn): timeout&error handling await docsService.addLinkedDoc(docId, data.source.data.entity.id); + mixpanel.track('LinkedDocCreated', { + page: 'sidebar', + module: 'doc', + control: 'drop doc on doc', + }); } else { toast(t['com.affine.rootAppSidebar.doc.link-doc-only']()); } diff --git a/packages/frontend/core/src/modules/explorer/views/nodes/doc/operations.tsx b/packages/frontend/core/src/modules/explorer/views/nodes/doc/operations.tsx index bec89e178d..fc749611e4 100644 --- a/packages/frontend/core/src/modules/explorer/views/nodes/doc/operations.tsx +++ b/packages/frontend/core/src/modules/explorer/views/nodes/doc/operations.tsx @@ -7,6 +7,7 @@ import { } from '@affine/component'; import { useAppSettingHelper } from '@affine/core/hooks/affine/use-app-setting-helper'; import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks'; +import { mixpanel } from '@affine/core/mixpanel'; import { CompatibleFavoriteItemsAdapter } from '@affine/core/modules/properties'; import { WorkbenchService } from '@affine/core/modules/workbench'; import { useI18n } from '@affine/i18n'; @@ -64,6 +65,11 @@ export const useExplorerDocNodeOperations = ( }, onConfirm() { docRecord.moveToTrash(); + mixpanel.track('DocMovedTrash', { + page: 'sidebar', + module: 'doc', + control: 'move to trash button', + }); toast(t['com.affine.toastMessage.movedTrash']()); }, }); @@ -73,18 +79,40 @@ export const useExplorerDocNodeOperations = ( workbenchService.workbench.openDoc(docId, { at: 'beside', }); + mixpanel.track('OpenInSplitView', { + page: 'sidebar', + module: 'doc', + control: 'open in split view button', + }); }, [docId, workbenchService]); const handleAddLinkedPage = useAsyncCallback(async () => { const newDoc = docsService.createDoc(); // TODO: handle timeout & error await docsService.addLinkedDoc(docId, newDoc.id); + mixpanel.track('DocCreated', { + page: 'sidebar', + module: 'doc', + control: 'add linked doc button', + }); + mixpanel.track('LinkedDocCreated', { + page: 'sidebar', + module: 'doc', + control: 'add linked doc button', + }); workbenchService.workbench.openDoc(newDoc.id); options.openNodeCollapsed(); }, [docId, options, docsService, workbenchService.workbench]); const handleToggleFavoriteDoc = useCallback(() => { compatibleFavoriteItemsAdapter.toggle(docId, 'doc'); + mixpanel.track('ToggleFavorite', { + page: 'sidebar', + module: 'doc', + control: 'toggle favorite button', + type: 'doc', + id: docId, + }); }, [docId, compatibleFavoriteItemsAdapter]); return useMemo( diff --git a/packages/frontend/core/src/modules/explorer/views/nodes/folder/index.tsx b/packages/frontend/core/src/modules/explorer/views/nodes/folder/index.tsx index ae2d1ad72e..6c0c783f79 100644 --- a/packages/frontend/core/src/modules/explorer/views/nodes/folder/index.tsx +++ b/packages/frontend/core/src/modules/explorer/views/nodes/folder/index.tsx @@ -14,6 +14,7 @@ import { useSelectDoc, useSelectTag, } from '@affine/core/components/page-list/selector'; +import { mixpanel } from '@affine/core/mixpanel'; import { type FolderNode, OrganizeService, @@ -173,6 +174,11 @@ export const ExplorerFolderNodeFolder = ({ const handleDelete = useCallback(() => { node.delete(); + mixpanel.track('FolderDeleted', { + page: 'sidebar', + module: 'organize', + control: `delete folder`, + }); }, [node]); const children = useLiveData(node.sortedChildren$); @@ -213,10 +219,24 @@ export const ExplorerFolderNodeFolder = ({ return; } node.moveHere(data.source.data.entity.id, node.indexAt('before')); + mixpanel.track('FolderMoved', { + page: 'sidebar', + module: 'organize', + control: 'drop folder at folder', + type: 'folder', + id: data.source.data.entity.id, + }); } else if ( data.source.data.from?.at === 'explorer:organize:folder-node' ) { node.moveHere(data.source.data.from.nodeId, node.indexAt('before')); + mixpanel.track('FolderLinkMoved', { + page: 'sidebar', + module: 'organize', + control: 'drop folder link at folder', + type: data.source.data.entity?.type, + id: data.source.data.entity?.id, + }); } else if ( data.source.data.entity?.type === 'collection' || data.source.data.entity?.type === 'doc' || @@ -227,6 +247,13 @@ export const ExplorerFolderNodeFolder = ({ data.source.data.entity.id, node.indexAt('before') ); + mixpanel.track('FolderLinkCreated', { + page: 'sidebar', + module: 'organize', + control: 'drop entity at folder', + type: data.source.data.entity?.type, + id: data.source.data.entity?.id, + }); } } else { onDrop?.(data); @@ -275,10 +302,24 @@ export const ExplorerFolderNodeFolder = ({ return; } node.moveHere(data.source.data.entity.id, node.indexAt('before')); + mixpanel.track('FolderMoved', { + page: 'sidebar', + module: 'organize', + control: 'drop folder at folder', + type: 'folder', + id: data.source.data.entity.id, + }); } else if ( data.source.data.from?.at === 'explorer:organize:folder-node' ) { node.moveHere(data.source.data.from.nodeId, node.indexAt('before')); + mixpanel.track('FolderLinkMoved', { + page: 'sidebar', + module: 'organize', + control: 'drop folder link at folder', + type: data.source.data.entity?.type, + id: data.source.data.entity?.id, + }); } else if ( data.source.data.entity?.type === 'collection' || data.source.data.entity?.type === 'doc' || @@ -289,6 +330,13 @@ export const ExplorerFolderNodeFolder = ({ data.source.data.entity.id, node.indexAt('before') ); + mixpanel.track('FolderLinkCreated', { + page: 'sidebar', + module: 'organize', + control: 'drop entity at folder', + type: data.source.data.entity?.type, + id: data.source.data.entity?.id, + }); } }, [node] @@ -316,6 +364,13 @@ export const ExplorerFolderNodeFolder = ({ data.source.data.entity.id, node.indexAt(at, dropAtNode.id) ); + mixpanel.track('FolderMoved', { + page: 'sidebar', + module: 'organize', + control: `drop folder ${at === 'before' ? 'above' : 'below'} node`, + type: 'folder', + id: data.source.data.entity?.id, + }); } else if ( data.source.data.from?.at === 'explorer:organize:folder-node' ) { @@ -323,6 +378,13 @@ export const ExplorerFolderNodeFolder = ({ data.source.data.from.nodeId, node.indexAt(at, dropAtNode.id) ); + mixpanel.track('FolderLinkMoved', { + page: 'sidebar', + module: 'organize', + control: `drop folder link ${at === 'before' ? 'above' : 'below'} node`, + type: data.source.data.entity?.type, + id: data.source.data.entity?.id, + }); } else if ( data.source.data.entity?.type === 'collection' || data.source.data.entity?.type === 'doc' || @@ -333,6 +395,13 @@ export const ExplorerFolderNodeFolder = ({ data.source.data.entity.id, node.indexAt(at, dropAtNode.id) ); + mixpanel.track('FolderLinkCreated', { + page: 'sidebar', + module: 'organize', + control: `drop entity ${at === 'before' ? 'above' : 'below'} node`, + type: data.source.data.entity?.type, + id: data.source.data.entity?.id, + }); } } else if (data.treeInstruction?.type === 'reparent') { const currentLevel = data.treeInstruction.currentLevel; @@ -481,6 +550,18 @@ export const ExplorerFolderNodeFolder = ({ const newDoc = docsService.createDoc(); node.createLink('doc', newDoc.id, node.indexAt('before')); workbenchService.workbench.openDoc(newDoc.id); + mixpanel.track('DocCreated', { + page: 'sidebar', + module: 'organize', + control: `folder new doc button`, + }); + mixpanel.track('FolderLinkCreated', { + page: 'sidebar', + module: 'organize', + control: `folder new doc button`, + type: 'doc', + id: newDoc.id, + }); setCollapsed(false); }, [docsService, node, workbenchService.workbench]); @@ -489,6 +570,11 @@ export const ExplorerFolderNodeFolder = ({ t['com.affine.rootAppSidebar.organize.new-folders'](), node.indexAt('before') ); + mixpanel.track('FolderCreated', { + page: 'sidebar', + module: 'organize', + control: `create sub folder`, + }); setCollapsed(false); setNewFolderId(newFolderId); }, [node, t]); @@ -514,9 +600,16 @@ export const ExplorerFolderNodeFolder = ({ !!node.data$.value && removedItemIds.includes(node.data$.value) ); - newItemIds.forEach(id => - node.createLink(type, id, node.indexAt('after')) - ); + newItemIds.forEach(id => { + node.createLink(type, id, node.indexAt('after')); + mixpanel.track('FolderLinkCreated', { + page: 'sidebar', + module: 'organize', + control: `add selector`, + type, + id, + }); + }); removedItems.forEach(node => node.delete()); const updated = newItemIds.length + removedItems.length; updated && setCollapsed(false); @@ -649,6 +742,19 @@ export const ExplorerFolderNodeFolder = ({ const handleDeleteChildren = useCallback((node: FolderNode) => { node.delete(); + if (node.type$.value === 'folder') { + mixpanel.track('FolderDeleted', { + page: 'sidebar', + module: 'organize', + control: 'remove from folder button', + }); + } else { + mixpanel.track('FolderLinkDeleted', { + page: 'sidebar', + module: 'organize', + control: 'remove from folder button', + }); + } }, []); const childrenOperations = useCallback( diff --git a/packages/frontend/core/src/modules/explorer/views/nodes/tag/index.tsx b/packages/frontend/core/src/modules/explorer/views/nodes/tag/index.tsx index 3afa6c5ff8..ae01597a66 100644 --- a/packages/frontend/core/src/modules/explorer/views/nodes/tag/index.tsx +++ b/packages/frontend/core/src/modules/explorer/views/nodes/tag/index.tsx @@ -3,6 +3,7 @@ import { type DropTargetOptions, toast, } from '@affine/component'; +import { mixpanel } from '@affine/core/mixpanel'; import type { Tag } from '@affine/core/modules/tag'; import { TagService } from '@affine/core/modules/tag'; import type { AffineDNDData } from '@affine/core/types/dnd'; @@ -81,8 +82,13 @@ export const ExplorerTagNode = ({ const handleRename = useCallback( (newName: string) => { - if (tagRecord) { + if (tagRecord && tagRecord.value$.value !== newName) { tagRecord.rename(newName); + mixpanel.track('TagRenamed', { + page: 'sidebar', + module: 'tag', + control: 'tag rename', + }); } }, [tagRecord] @@ -93,6 +99,11 @@ export const ExplorerTagNode = ({ if (data.treeInstruction?.type === 'make-child' && tagRecord) { if (data.source.data.entity?.type === 'doc') { tagRecord.tag(data.source.data.entity.id); + mixpanel.track('DocTagged', { + page: 'sidebar', + module: 'tag', + control: 'drop doc on tag', + }); } else { toast(t['com.affine.rootAppSidebar.tag.doc-only']()); } diff --git a/packages/frontend/core/src/modules/explorer/views/nodes/tag/operations.tsx b/packages/frontend/core/src/modules/explorer/views/nodes/tag/operations.tsx index c255b4ad27..ed93507df6 100644 --- a/packages/frontend/core/src/modules/explorer/views/nodes/tag/operations.tsx +++ b/packages/frontend/core/src/modules/explorer/views/nodes/tag/operations.tsx @@ -6,6 +6,7 @@ import { toast, } from '@affine/component'; import { useAppSettingHelper } from '@affine/core/hooks/affine/use-app-setting-helper'; +import { mixpanel } from '@affine/core/mixpanel'; import { FavoriteService } from '@affine/core/modules/favorite'; import { TagService } from '@affine/core/modules/tag'; import { WorkbenchService } from '@affine/core/modules/workbench'; @@ -49,6 +50,16 @@ export const useExplorerTagNodeOperations = ( if (tagRecord) { const newDoc = docsService.createDoc(); tagRecord?.tag(newDoc.id); + mixpanel.track('DocCreated', { + page: 'sidebar', + module: 'tag', + control: 'add doc button', + }); + mixpanel.track('DocTagged', { + page: 'sidebar', + module: 'tag', + control: 'add doc button', + }); workbenchService.workbench.openDoc(newDoc.id); openNodeCollapsed(); } @@ -56,6 +67,11 @@ export const useExplorerTagNodeOperations = ( const handleMoveToTrash = useCallback(() => { tagService.tagList.deleteTag(tagId); + mixpanel.track('TagDeleted', { + page: 'sidebar', + module: 'tag', + control: 'remove tag button', + }); toast(t['com.affine.tags.delete-tags.toast']()); }, [t, tagId, tagService.tagList]); @@ -63,10 +79,22 @@ export const useExplorerTagNodeOperations = ( workbenchService.workbench.openTag(tagId, { at: 'beside', }); + mixpanel.track('OpenInSplitView', { + page: 'sidebar', + module: 'tag', + control: 'open in split view button', + }); }, [tagId, workbenchService]); const handleToggleFavoriteTag = useCallback(() => { favoriteService.favoriteList.toggle('tag', tagId); + mixpanel.track('ToggleFavorite', { + page: 'sidebar', + module: 'tag', + control: 'toggle favorite tag button', + type: 'tag', + id: tagId, + }); }, [favoriteService, tagId]); return useMemo( diff --git a/packages/frontend/core/src/modules/explorer/views/sections/collections/index.tsx b/packages/frontend/core/src/modules/explorer/views/sections/collections/index.tsx index 68360a4219..0c60d331f0 100644 --- a/packages/frontend/core/src/modules/explorer/views/sections/collections/index.tsx +++ b/packages/frontend/core/src/modules/explorer/views/sections/collections/index.tsx @@ -2,6 +2,7 @@ import { IconButton } from '@affine/component'; import { CategoryDivider } from '@affine/core/components/app-sidebar'; import { useEditCollectionName } from '@affine/core/components/page-list'; import { createEmptyCollection } from '@affine/core/components/page-list/use-collection-manager'; +import { mixpanel } from '@affine/core/mixpanel'; import { CollectionService } from '@affine/core/modules/collection'; import { ExplorerTreeRoot } from '@affine/core/modules/explorer/views/tree'; import { WorkbenchService } from '@affine/core/modules/workbench'; @@ -38,6 +39,11 @@ export const ExplorerCollections = ({ .then(name => { const id = nanoid(); collectionService.addCollection(createEmptyCollection(id, { name })); + mixpanel.track('CollectionCreated', { + page: 'sidebar', + module: 'collections', + control: 'new collection button', + }); workbenchService.workbench.openCollection(id); setCollapsed(false); }) diff --git a/packages/frontend/core/src/modules/explorer/views/sections/favorites/index.tsx b/packages/frontend/core/src/modules/explorer/views/sections/favorites/index.tsx index faa4395e97..bf6b866ad0 100644 --- a/packages/frontend/core/src/modules/explorer/views/sections/favorites/index.tsx +++ b/packages/frontend/core/src/modules/explorer/views/sections/favorites/index.tsx @@ -5,6 +5,7 @@ import { useDropTarget, } from '@affine/component'; import { CategoryDivider } from '@affine/core/components/app-sidebar'; +import { mixpanel } from '@affine/core/mixpanel'; import { DropEffect, type ExplorerTreeNodeDropEffect, @@ -57,6 +58,13 @@ export const ExplorerFavorites = ({ data.source.data.entity.id, favoriteService.favoriteList.indexAt('before') ); + mixpanel.track('AddFavorite', { + page: 'sidebar', + module: 'favorite', + control: 'drop entity to favorite', + type: data.source.data.entity.type, + id: data.source.data.entity.id, + }); setCollapsed(false); } }, @@ -89,6 +97,18 @@ export const ExplorerFavorites = ({ newDoc.id, favoriteService.favoriteList.indexAt('before') ); + mixpanel.track('DocCreated', { + page: 'sidebar', + module: 'favorites', + control: 'new favorite doc button', + }); + mixpanel.track('AddFavorite', { + page: 'sidebar', + module: 'favorite', + control: 'new favorite doc button', + type: 'doc', + id: newDoc.id, + }); workbenchService.workbench.openDoc(newDoc.id); setCollapsed(false); }, [docsService, favoriteService, workbenchService]); @@ -118,6 +138,13 @@ export const ExplorerFavorites = ({ favorite ) ); + mixpanel.track('ReorderFavorite', { + page: 'sidebar', + module: 'favorite', + control: 'drop to reorder favorite', + type: data.source.data.entity.type, + id: data.source.data.entity.id, + }); } else if ( data.source.data.entity?.type && isFavoriteSupportType(data.source.data.entity.type) @@ -132,6 +159,13 @@ export const ExplorerFavorites = ({ favorite ) ); + mixpanel.track('AddFavorite', { + page: 'sidebar', + module: 'favorite', + control: 'drop entity to favorite', + type: data.source.data.entity.type, + id: data.source.data.entity.id, + }); } else { return; // not supported } diff --git a/packages/frontend/core/src/modules/explorer/views/sections/migration-favorites/index.tsx b/packages/frontend/core/src/modules/explorer/views/sections/migration-favorites/index.tsx index c94604aeb5..adfa6bb8df 100644 --- a/packages/frontend/core/src/modules/explorer/views/sections/migration-favorites/index.tsx +++ b/packages/frontend/core/src/modules/explorer/views/sections/migration-favorites/index.tsx @@ -1,5 +1,6 @@ import { IconButton, useConfirmModal } from '@affine/component'; import { CategoryDivider } from '@affine/core/components/app-sidebar'; +import { mixpanel } from '@affine/core/mixpanel'; import { ExplorerTreeRoot } from '@affine/core/modules/explorer/views/tree'; import { FavoriteItemsAdapter } from '@affine/core/modules/properties'; import { Trans, useI18n } from '@affine/i18n'; @@ -64,8 +65,18 @@ export const ExplorerMigrationFavorites = ({ t['com.affine.rootAppSidebar.migration-data.clean-all.cancel'](), onConfirm() { favoriteItemsAdapter.clearAll(); + mixpanel.track('AllMigrationDataCleared', { + page: 'sidebar', + module: 'migration data', + control: 'clear button', + }); }, }); + mixpanel.track('ClickClearMigrationDataButton', { + page: 'sidebar', + module: 'migration data', + control: 'clear button', + }); }, [favoriteItemsAdapter, openConfirmModal, t]); const handleClickHelp = useCallback(() => { @@ -89,6 +100,11 @@ export const ExplorerMigrationFavorites = ({ }, }, }); + mixpanel.track('OpenMigrationDataHelp', { + page: 'sidebar', + module: 'migration data', + control: 'help button', + }); }, [handleClickClear, openConfirmModal, t]); if (favorites.length === 0) { diff --git a/packages/frontend/core/src/modules/explorer/views/sections/organize/index.tsx b/packages/frontend/core/src/modules/explorer/views/sections/organize/index.tsx index 91be86b4fd..7c2228f216 100644 --- a/packages/frontend/core/src/modules/explorer/views/sections/organize/index.tsx +++ b/packages/frontend/core/src/modules/explorer/views/sections/organize/index.tsx @@ -5,6 +5,7 @@ import { toast, } from '@affine/component'; import { CategoryDivider } from '@affine/core/components/app-sidebar'; +import { mixpanel } from '@affine/core/mixpanel'; import { type ExplorerTreeNodeDropEffect, ExplorerTreeRoot, @@ -44,6 +45,11 @@ export const ExplorerOrganize = ({ 'New Folder', rootFolder.indexAt('before') ); + mixpanel.track('FolderCreated', { + page: 'sidebar', + module: 'organize', + control: 'new folder', + }); setNewFolderId(newFolderId); setCollapsed(false); }, [rootFolder]); @@ -64,6 +70,13 @@ export const ExplorerOrganize = ({ data.source.data.entity.id, rootFolder.indexAt(at, node.id) ); + mixpanel.track('FolderMoved', { + page: 'sidebar', + module: 'organize', + control: 'drop at root', + type: 'folder', + id: node.id, + }); } else { toast(t['com.affine.rootAppSidebar.organize.root-folder-only']()); } diff --git a/packages/frontend/core/src/modules/explorer/views/sections/tags/index.tsx b/packages/frontend/core/src/modules/explorer/views/sections/tags/index.tsx index 44f4882713..f29ae4f8d1 100644 --- a/packages/frontend/core/src/modules/explorer/views/sections/tags/index.tsx +++ b/packages/frontend/core/src/modules/explorer/views/sections/tags/index.tsx @@ -1,5 +1,6 @@ import { IconButton } from '@affine/component'; import { CategoryDivider } from '@affine/core/components/app-sidebar'; +import { mixpanel } from '@affine/core/mixpanel'; import { ExplorerTreeRoot } from '@affine/core/modules/explorer/views/tree'; import type { Tag } from '@affine/core/modules/tag'; import { TagService } from '@affine/core/modules/tag'; @@ -34,6 +35,11 @@ export const ExplorerTags = ({ tagService.randomTagColor() ); setCreatedTag(newTags); + mixpanel.track('TagCreated', { + page: 'sidebar', + module: 'tags', + control: 'new tag button', + }); setCollapsed(false); }, [t, tagService]);