From eb01e764269b1b1c607e03c8773ffd195efc7ca0 Mon Sep 17 00:00:00 2001 From: JimmFly Date: Wed, 7 Aug 2024 05:52:42 +0000 Subject: [PATCH] feat(core): add track events for cmdk (#7668) --- .../core/src/commands/affine-creation.tsx | 13 +++++ .../core/src/commands/affine-help.tsx | 3 ++ .../core/src/commands/affine-layout.tsx | 3 ++ .../core/src/commands/affine-navigation.tsx | 20 +++++++ .../core/src/commands/affine-settings.tsx | 52 +++++++++++++++++++ .../core/src/commands/affine-updates.tsx | 3 ++ .../block-suite-header/menu/index.tsx | 4 +- ...se-register-blocksuite-editor-commands.tsx | 32 +++++++++++- .../use-register-copy-link-commands.tsx | 5 +- .../use-register-find-in-page-commands.ts | 5 +- packages/frontend/core/src/mixpanel/events.ts | 37 ++++++++++--- .../view/use-register-navigation-commands.ts | 5 ++ .../src/modules/quicksearch/services/cmdk.ts | 5 ++ 13 files changed, 175 insertions(+), 12 deletions(-) diff --git a/packages/frontend/core/src/commands/affine-creation.tsx b/packages/frontend/core/src/commands/affine-creation.tsx index b2f5697faf1d..e926d5bb0dfe 100644 --- a/packages/frontend/core/src/commands/affine-creation.tsx +++ b/packages/frontend/core/src/commands/affine-creation.tsx @@ -4,6 +4,7 @@ import type { createStore } from 'jotai'; import { openCreateWorkspaceModalAtom } from '../atoms'; import type { usePageHelper } from '../components/blocksuite/block-suite-page-list/utils'; +import { track } from '../mixpanel'; import { registerAffineCommand } from './registry'; export function registerAffineCreationCommands({ @@ -29,6 +30,8 @@ export function registerAffineCreationCommands({ } : undefined, run() { + track.$.cmdk.creation.createDoc({ mode: 'page' }); + pageHelper.createPage(); }, }) @@ -41,6 +44,10 @@ export function registerAffineCreationCommands({ icon: , label: t['com.affine.cmdk.affine.new-edgeless-page'](), run() { + track.$.cmdk.creation.createDoc({ + mode: 'edgeless', + }); + pageHelper.createEdgeless(); }, }) @@ -53,6 +60,8 @@ export function registerAffineCreationCommands({ icon: , label: t['com.affine.cmdk.affine.new-workspace'](), run() { + track.$.cmdk.workspace.createWorkspace(); + store.set(openCreateWorkspaceModalAtom, 'new'); }, }) @@ -67,6 +76,10 @@ export function registerAffineCreationCommands({ return environment.isDesktop; }, run() { + track.$.cmdk.workspace.createWorkspace({ + control: 'import', + }); + store.set(openCreateWorkspaceModalAtom, 'add'); }, }) diff --git a/packages/frontend/core/src/commands/affine-help.tsx b/packages/frontend/core/src/commands/affine-help.tsx index dfb10a3c8e8c..369beee72751 100644 --- a/packages/frontend/core/src/commands/affine-help.tsx +++ b/packages/frontend/core/src/commands/affine-help.tsx @@ -3,6 +3,7 @@ import { ContactWithUsIcon, NewIcon } from '@blocksuite/icons/rc'; import type { createStore } from 'jotai'; import { openSettingModalAtom } from '../atoms'; +import { track } from '../mixpanel'; import { popupWindow } from '../utils'; import { registerAffineCommand } from './registry'; @@ -21,6 +22,7 @@ export function registerAffineHelpCommands({ icon: , label: t['com.affine.cmdk.affine.whats-new'](), run() { + track.$.cmdk.help.openChangelog(); popupWindow(runtimeConfig.changelogUrl); }, }) @@ -32,6 +34,7 @@ export function registerAffineHelpCommands({ icon: , label: t['com.affine.cmdk.affine.contact-us'](), run() { + track.$.cmdk.help.contactUs(); store.set(openSettingModalAtom, { open: true, activeTab: 'about', diff --git a/packages/frontend/core/src/commands/affine-layout.tsx b/packages/frontend/core/src/commands/affine-layout.tsx index 584927f263f3..730171c99fd3 100644 --- a/packages/frontend/core/src/commands/affine-layout.tsx +++ b/packages/frontend/core/src/commands/affine-layout.tsx @@ -3,6 +3,7 @@ import { SidebarIcon } from '@blocksuite/icons/rc'; import type { createStore } from 'jotai'; import { appSidebarOpenAtom } from '../components/app-sidebar'; +import { track } from '../mixpanel'; import { registerAffineCommand } from './registry'; export function registerAffineLayoutCommands({ @@ -27,6 +28,8 @@ export function registerAffineLayoutCommands({ binding: '$mod+/', }, run() { + track.$.navigationPanel.$.toggle(); + store.set(appSidebarOpenAtom, v => !v); }, }) diff --git a/packages/frontend/core/src/commands/affine-navigation.tsx b/packages/frontend/core/src/commands/affine-navigation.tsx index 0a3094c4b0c4..7ce36bbefd16 100644 --- a/packages/frontend/core/src/commands/affine-navigation.tsx +++ b/packages/frontend/core/src/commands/affine-navigation.tsx @@ -28,6 +28,10 @@ export function registerAffineNavigationCommands({ icon: , label: t['com.affine.cmdk.affine.navigation.goto-all-pages'](), run() { + track.$.cmdk.navigation.navigate({ + to: 'allDocs', + }); + navigationHelper.jumpToSubPath(docCollection.id, WorkspaceSubPath.ALL); }, }) @@ -40,6 +44,10 @@ export function registerAffineNavigationCommands({ icon: , label: 'Go to Collection List', run() { + track.$.cmdk.navigation.navigate({ + to: 'collectionList', + }); + navigationHelper.jumpToCollections(docCollection.id); }, }) @@ -52,6 +60,10 @@ export function registerAffineNavigationCommands({ icon: , label: 'Go to Tag List', run() { + track.$.cmdk.navigation.navigate({ + to: 'tagList', + }); + navigationHelper.jumpToTags(docCollection.id); }, }) @@ -64,6 +76,10 @@ export function registerAffineNavigationCommands({ icon: , label: t['com.affine.cmdk.affine.navigation.goto-workspace'](), run() { + track.$.cmdk.navigation.navigate({ + to: 'workspace', + }); + store.set(openWorkspaceListModalAtom, true); }, }) @@ -109,6 +125,10 @@ export function registerAffineNavigationCommands({ icon: , label: t['com.affine.cmdk.affine.navigation.goto-trash'](), run() { + track.$.cmdk.navigation.navigate({ + to: 'trash', + }); + navigationHelper.jumpToSubPath( docCollection.id, WorkspaceSubPath.TRASH diff --git a/packages/frontend/core/src/commands/affine-settings.tsx b/packages/frontend/core/src/commands/affine-settings.tsx index 78c0aee75f2e..6e0164374ae1 100644 --- a/packages/frontend/core/src/commands/affine-settings.tsx +++ b/packages/frontend/core/src/commands/affine-settings.tsx @@ -6,6 +6,7 @@ import type { createStore } from 'jotai'; import type { useTheme } from 'next-themes'; import type { useLanguageHelper } from '../hooks/affine/use-language-helper'; +import { track } from '../mixpanel'; import { registerAffineCommand } from './registry'; export function registerAffineSettingsCommands({ @@ -34,6 +35,10 @@ export function registerAffineSettingsCommands({ icon: , preconditionStrategy: () => theme.theme !== 'system', run() { + track.$.cmdk.settings.changeAppSetting({ + key: 'theme', + value: 'system', + }); theme.setTheme('system'); }, }) @@ -48,6 +53,10 @@ export function registerAffineSettingsCommands({ icon: , preconditionStrategy: () => theme.theme !== 'dark', run() { + track.$.cmdk.settings.changeAppSetting({ + key: 'theme', + value: 'dark', + }); theme.setTheme('dark'); }, }) @@ -63,6 +72,11 @@ export function registerAffineSettingsCommands({ icon: , preconditionStrategy: () => theme.theme !== 'light', run() { + track.$.cmdk.settings.changeAppSetting({ + key: 'theme', + value: 'light', + }); + theme.setTheme('light'); }, }) @@ -80,6 +94,11 @@ export function registerAffineSettingsCommands({ preconditionStrategy: () => store.get(appSettingAtom).fontStyle !== 'Sans', run() { + track.$.cmdk.settings.changeAppSetting({ + key: 'fontStyle', + value: 'Sans', + }); + store.set(appSettingAtom, prev => ({ ...prev, fontStyle: 'Sans', @@ -99,6 +118,11 @@ export function registerAffineSettingsCommands({ preconditionStrategy: () => store.get(appSettingAtom).fontStyle !== 'Serif', run() { + track.$.cmdk.settings.changeAppSetting({ + key: 'fontStyle', + value: 'Serif', + }); + store.set(appSettingAtom, prev => ({ ...prev, fontStyle: 'Serif', @@ -118,6 +142,11 @@ export function registerAffineSettingsCommands({ preconditionStrategy: () => store.get(appSettingAtom).fontStyle !== 'Mono', run() { + track.$.cmdk.settings.changeAppSetting({ + key: 'fontStyle', + value: 'Mono', + }); + store.set(appSettingAtom, prev => ({ ...prev, fontStyle: 'Mono', @@ -138,6 +167,11 @@ export function registerAffineSettingsCommands({ icon: , preconditionStrategy: () => currentLanguage?.tag !== language.tag, run() { + track.$.cmdk.settings.changeAppSetting({ + key: 'language', + value: language.name, + }); + onLanguageChange(language.tag); }, }) @@ -158,6 +192,10 @@ export function registerAffineSettingsCommands({ icon: , preconditionStrategy: () => environment.isDesktop, run() { + track.$.cmdk.settings.changeAppSetting({ + key: 'clientBorder', + value: store.get(appSettingAtom).clientBorder ? 'off' : 'on', + }); store.set(appSettingAtom, prev => ({ ...prev, clientBorder: !prev.clientBorder, @@ -178,6 +216,11 @@ export function registerAffineSettingsCommands({ category: 'affine:settings', icon: , run() { + track.$.cmdk.settings.changeAppSetting({ + key: 'fullWidthLayout', + value: store.get(appSettingAtom).fullWidthLayout ? 'off' : 'on', + }); + store.set(appSettingAtom, prev => ({ ...prev, fullWidthLayout: !prev.fullWidthLayout, @@ -201,6 +244,11 @@ export function registerAffineSettingsCommands({ icon: , preconditionStrategy: () => environment.isDesktop, run() { + track.$.cmdk.settings.changeAppSetting({ + key: 'enableNoisyBackground', + value: store.get(appSettingAtom).enableNoisyBackground ? 'off' : 'on', + }); + store.set(appSettingAtom, prev => ({ ...prev, enableNoisyBackground: !prev.enableNoisyBackground, @@ -222,6 +270,10 @@ export function registerAffineSettingsCommands({ icon: , preconditionStrategy: () => environment.isDesktop && environment.isMacOs, run() { + track.$.cmdk.settings.changeAppSetting({ + key: 'enableBlurBackground', + value: store.get(appSettingAtom).enableBlurBackground ? 'off' : 'on', + }); store.set(appSettingAtom, prev => ({ ...prev, enableBlurBackground: !prev.enableBlurBackground, diff --git a/packages/frontend/core/src/commands/affine-updates.tsx b/packages/frontend/core/src/commands/affine-updates.tsx index 2d43150943a1..39921883f00e 100644 --- a/packages/frontend/core/src/commands/affine-updates.tsx +++ b/packages/frontend/core/src/commands/affine-updates.tsx @@ -5,6 +5,7 @@ import type { useI18n } from '@affine/i18n'; import { ResetIcon } from '@blocksuite/icons/rc'; import type { createStore } from 'jotai'; +import { track } from '../mixpanel'; import { registerAffineCommand } from './registry'; export function registerAffineUpdatesCommands({ @@ -24,6 +25,8 @@ export function registerAffineUpdatesCommands({ label: t['com.affine.cmdk.affine.restart-to-upgrade'](), preconditionStrategy: () => !!store.get(updateReadyAtom), run() { + track.$.cmdk.updates.quitAndInstall(); + apis?.updater.quitAndInstall().catch(err => { notify.error({ title: 'Failed to restart to upgrade', diff --git a/packages/frontend/core/src/components/blocksuite/block-suite-header/menu/index.tsx b/packages/frontend/core/src/components/blocksuite/block-suite-header/menu/index.tsx index 2f7134bb8bf1..cc345a313f79 100644 --- a/packages/frontend/core/src/components/blocksuite/block-suite-header/menu/index.tsx +++ b/packages/frontend/core/src/components/blocksuite/block-suite-header/menu/index.tsx @@ -150,7 +150,9 @@ export const PageHeaderMenuButton = ({ const handleSwitchMode = useCallback(() => { doc.toggleMode(); - track.$.header.docOptions.switchPageMode(); + track.$.header.docOptions.switchPageMode({ + mode: currentMode === 'page' ? 'edgeless' : 'page', + }); toast( currentMode === 'page' ? t['com.affine.toastMessage.edgelessMode']() diff --git a/packages/frontend/core/src/hooks/affine/use-register-blocksuite-editor-commands.tsx b/packages/frontend/core/src/hooks/affine/use-register-blocksuite-editor-commands.tsx index 9d0b36a06c79..058b457553f9 100644 --- a/packages/frontend/core/src/hooks/affine/use-register-blocksuite-editor-commands.tsx +++ b/packages/frontend/core/src/hooks/affine/use-register-blocksuite-editor-commands.tsx @@ -102,6 +102,8 @@ export function useRegisterBlocksuiteEditorCommands() { icon: mode === 'page' ? : , label: t['com.affine.page-properties.page-info.view'](), run() { + track.$.cmdk.docInfo.open(); + openInfoModal(); }, }) @@ -118,6 +120,8 @@ export function useRegisterBlocksuiteEditorCommands() { : t['com.affine.favoritePageOperation.add'](), run() { favAdapter.toggle(docId, 'doc'); + track.$.cmdk.editor.toggleFavorite(); + toast( favorite ? t['com.affine.cmdk.affine.editor.remove-from-favourites']() @@ -141,6 +145,10 @@ export function useRegisterBlocksuiteEditorCommands() { : t['com.affine.pageMode.page']() }`, run() { + track.$.cmdk.editor.switchPageMode({ + mode: mode === 'page' ? 'edgeless' : 'page', + }); + doc.toggleMode(); toast( mode === 'page' @@ -161,7 +169,7 @@ export function useRegisterBlocksuiteEditorCommands() { label: t['com.affine.header.option.duplicate'](), run() { duplicate(docId); - track.$.cmdk.$.createDoc({ + track.$.cmdk.editor.createDoc({ control: 'duplicate', }); }, @@ -176,6 +184,10 @@ export function useRegisterBlocksuiteEditorCommands() { icon: mode === 'page' ? : , label: t['Export to PDF'](), async run() { + track.$.cmdk.editor.export({ + type: 'pdf', + }); + await exportHandler('pdf'); }, }) @@ -189,6 +201,10 @@ export function useRegisterBlocksuiteEditorCommands() { icon: mode === 'page' ? : , label: t['Export to HTML'](), async run() { + track.$.cmdk.editor.export({ + type: 'html', + }); + await exportHandler('html'); }, }) @@ -202,6 +218,10 @@ export function useRegisterBlocksuiteEditorCommands() { icon: mode === 'page' ? : , label: t['Export to PNG'](), async run() { + track.$.cmdk.editor.export({ + type: 'png', + }); + await exportHandler('png'); }, }) @@ -215,6 +235,10 @@ export function useRegisterBlocksuiteEditorCommands() { icon: mode === 'page' ? : , label: t['Export to Markdown'](), async run() { + track.$.cmdk.editor.export({ + type: 'markdown', + }); + await exportHandler('markdown'); }, }) @@ -228,6 +252,8 @@ export function useRegisterBlocksuiteEditorCommands() { icon: mode === 'page' ? : , label: t['com.affine.moveToTrash.title'](), run() { + track.$.cmdk.editor.deleteDoc(); + onClickDelete(doc.title$.value); }, }) @@ -242,6 +268,8 @@ export function useRegisterBlocksuiteEditorCommands() { icon: mode === 'page' ? : , label: t['com.affine.cmdk.affine.editor.restore-from-trash'](), run() { + track.$.cmdk.editor.restoreDoc(); + doc.restoreFromTrash(); }, }) @@ -255,6 +283,8 @@ export function useRegisterBlocksuiteEditorCommands() { icon: , label: t['com.affine.cmdk.affine.editor.reveal-page-history-modal'](), run() { + track.$.cmdk.docHistory.open(); + openHistoryModal(); }, }) diff --git a/packages/frontend/core/src/hooks/affine/use-register-copy-link-commands.tsx b/packages/frontend/core/src/hooks/affine/use-register-copy-link-commands.tsx index ca1912344f47..a40ccfec76cf 100644 --- a/packages/frontend/core/src/hooks/affine/use-register-copy-link-commands.tsx +++ b/packages/frontend/core/src/hooks/affine/use-register-copy-link-commands.tsx @@ -3,9 +3,10 @@ import { registerAffineCommand, } from '@affine/core/commands'; import { useSharingUrl } from '@affine/core/hooks/affine/use-share-url'; +import { track } from '@affine/core/mixpanel'; import { useIsActiveView } from '@affine/core/modules/workbench'; import { WorkspaceFlavour } from '@affine/env/workspace'; -import type { WorkspaceMetadata } from '@toeverything/infra'; +import { type WorkspaceMetadata } from '@toeverything/infra'; import { useEffect } from 'react'; export function useRegisterCopyLinkCommands({ @@ -38,6 +39,8 @@ export function useRegisterCopyLinkCommands({ label: '', icon: null, run() { + track.$.cmdk.general.copyShareLink({ type: 'private' }); + isActiveView && isCloud && onClickCopyLink(); }, }) diff --git a/packages/frontend/core/src/hooks/affine/use-register-find-in-page-commands.ts b/packages/frontend/core/src/hooks/affine/use-register-find-in-page-commands.ts index dbca1c48c774..5c0751d8e5ce 100644 --- a/packages/frontend/core/src/hooks/affine/use-register-find-in-page-commands.ts +++ b/packages/frontend/core/src/hooks/affine/use-register-find-in-page-commands.ts @@ -2,6 +2,7 @@ import { PreconditionStrategy, registerAffineCommand, } from '@affine/core/commands'; +import { track } from '@affine/core/mixpanel'; import { FindInPageService } from '@affine/core/modules/find-in-page/services/find-in-page'; import { useService } from '@toeverything/infra'; import { useCallback, useEffect } from 'react'; @@ -24,13 +25,15 @@ export function useRegisterFindInPageCommands() { unsubs.push( registerAffineCommand({ preconditionStrategy: PreconditionStrategy.Never, - id: `editor:find-in-page`, + id: `affine:find-in-page`, keyBinding: { binding: '$mod+f', }, icon: null, label: '', run() { + track.$.cmdk.general.findInPage(); + toggleVisible(); }, }) diff --git a/packages/frontend/core/src/mixpanel/events.ts b/packages/frontend/core/src/mixpanel/events.ts index cc40f95389b3..df79c8abf89d 100644 --- a/packages/frontend/core/src/mixpanel/events.ts +++ b/packages/frontend/core/src/mixpanel/events.ts @@ -2,21 +2,26 @@ /* eslint-disable rxjs/finnish */ // SECTION: app events -type GeneralEvents = 'openMigrationDataHelp' | 'export'; -type CmdkEvents = 'quickSearch'; +type GeneralEvents = 'openMigrationDataHelp'; +type CmdkEvents = 'quickSearch' | 'recentDocs' | 'searchResultsDocs'; type AppEvents = | 'checkUpdates' | 'downloadUpdate' | 'downloadApp' | 'quitAndInstall' | 'openChangelog' - | 'dismissChangelog'; + | 'dismissChangelog' + | 'contactUs' + | 'findInPage'; type NavigationEvents = | 'openInNewTab' | 'openInSplitView' | 'switchTab' | 'switchSplitView' | 'navigate' + | 'goBack' + | 'goForward' + | 'toggle' // toggle navigation panel | 'open' | 'close'; // openclose modal/diaglog @@ -35,6 +40,7 @@ type DocEvents = | 'renameDoc' | 'linkDoc' | 'deleteDoc' + | 'restoreDoc' | 'switchPageMode' | 'openDocOptionsMenu' | 'openDocInfo'; @@ -61,7 +67,6 @@ type FolderEvents = | 'deleteFolder'; type TagEvents = 'createTag' | 'deleteTag' | 'renameTag' | 'tagDoc'; type FavoriteEvents = 'toggleFavorite'; -type DocInfoEvents = 'toggle' | 'open'; type OrganizeItemEvents = // doc, link, folder, collection, tag | 'createOrganizeItem' @@ -111,8 +116,7 @@ type UserEvents = | ShareEvents | AuthEvents | AccountEvents - | PaymentEvents - | DocInfoEvents; + | PaymentEvents; interface PageDivision { [page: string]: { @@ -161,11 +165,28 @@ const PageEvents = { about: ['checkUpdates', 'downloadUpdate', 'changeAppSetting'], }, cmdk: { - $: ['createDoc'], + recent: ['recentDocs'], + results: ['searchResultsDocs'], + general: ['copyShareLink', 'goBack', 'goForward', 'findInPage'], + creation: ['createDoc'], + workspace: ['createWorkspace'], settings: ['openSettings', 'changeAppSetting'], + navigation: ['navigate'], + editor: [ + 'toggleFavorite', + 'switchPageMode', + 'createDoc', + 'export', + 'deleteDoc', + 'restoreDoc', + ], + docInfo: ['open'], + docHistory: ['open'], + updates: ['quitAndInstall'], + help: ['contactUs', 'openChangelog'], }, navigationPanel: { - $: ['quickSearch', 'createDoc', 'navigate', 'openSettings'], + $: ['quickSearch', 'createDoc', 'navigate', 'openSettings', 'toggle'], organize: [ 'createOrganizeItem', 'renameOrganizeItem', diff --git a/packages/frontend/core/src/modules/navigation/view/use-register-navigation-commands.ts b/packages/frontend/core/src/modules/navigation/view/use-register-navigation-commands.ts index c349fed65df4..32307240b1f1 100644 --- a/packages/frontend/core/src/modules/navigation/view/use-register-navigation-commands.ts +++ b/packages/frontend/core/src/modules/navigation/view/use-register-navigation-commands.ts @@ -2,6 +2,7 @@ import { PreconditionStrategy, registerAffineCommand, } from '@affine/core/commands'; +import { track } from '@affine/core/mixpanel'; import { useService } from '@toeverything/infra'; import { useEffect } from 'react'; @@ -23,6 +24,8 @@ export function useRegisterNavigationCommands() { binding: '$mod+[', }, run() { + track.$.cmdk.general.goBack(); + navigator.back(); }, }) @@ -38,6 +41,8 @@ export function useRegisterNavigationCommands() { binding: '$mod+]', }, run() { + track.$.cmdk.general.goForward(); + navigator.forward(); }, }) diff --git a/packages/frontend/core/src/modules/quicksearch/services/cmdk.ts b/packages/frontend/core/src/modules/quicksearch/services/cmdk.ts index 548ed5875fc7..2c7097088c93 100644 --- a/packages/frontend/core/src/modules/quicksearch/services/cmdk.ts +++ b/packages/frontend/core/src/modules/quicksearch/services/cmdk.ts @@ -1,3 +1,4 @@ +import { track } from '@affine/core/mixpanel'; import type { DocsService } from '@toeverything/infra'; import { Service } from '@toeverything/infra'; @@ -47,6 +48,10 @@ export class CMDKQuickSearchService extends Service { blockId?: string; } = result.payload; + result.source === 'recent-doc' && track.$.cmdk.recent.recentDocs(); + result.source === 'docs' && + track.$.cmdk.results.searchResultsDocs(); + this.workbenchService.workbench.openDoc({ docId: doc.docId, blockId: doc.blockId,