Skip to content

Commit

Permalink
chore: populate page prop for mixpanel (#7425)
Browse files Browse the repository at this point in the history
  • Loading branch information
pengx17 committed Jul 5, 2024
1 parent 481a226 commit 8dfa601
Show file tree
Hide file tree
Showing 11 changed files with 127 additions and 24 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import type { BlockSpec, WidgetElement } from '@blocksuite/block-std';
import {
type AffineReference,
AffineSlashMenuWidget,
EdgelessRootBlockComponent,
EmbedLinkedDocBlockComponent,
type ParagraphBlockService,
type RootService,
Expand Down Expand Up @@ -463,23 +464,28 @@ export function patchQuickSearchService(
pageId: linkedDoc.id,
},
]);
const isEdgeless =
rootElement instanceof EdgelessRootBlockComponent;
if (result.isNewDoc) {
mixpanel.track('DocCreated', {
control: 'linked doc',
module: 'slash commands',
type: 'linked doc',
category: 'doc',
page: isEdgeless ? 'whiteboard editor' : 'page editor',
});
mixpanel.track('LinkedDocCreated', {
control: 'new doc',
module: 'slash commands',
type: 'doc',
page: isEdgeless ? 'whiteboard editor' : 'page editor',
});
} else {
mixpanel.track('LinkedDocCreated', {
control: 'linked doc',
module: 'slash commands',
type: 'doc',
page: isEdgeless ? 'whiteboard editor' : 'page editor',
});
}
} else if ('userInput' in result) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,31 +110,34 @@ export const PageHeaderMenuButton = ({
duplicate(pageId);
mixpanel.track('DocCreated', {
segment: 'editor header',
page: doc.mode$.value === 'page' ? 'page editor' : 'edgeless editor',
module: 'header menu',
control: 'copy doc',
type: 'doc duplicate',
category: 'doc',
});
}, [duplicate, pageId]);
}, [doc.mode$.value, duplicate, pageId]);

const onImportFile = useAsyncCallback(async () => {
const options = await importFile();
if (options.isWorkspaceFile) {
mixpanel.track('WorkspaceCreated', {
segment: 'editor header',
page: doc.mode$.value === 'page' ? 'page editor' : 'edgeless editor',
module: 'header menu',
control: 'import button',
type: 'imported workspace',
});
} else {
mixpanel.track('DocCreated', {
segment: 'editor header',
page: doc.mode$.value === 'page' ? 'page editor' : 'edgeless editor',
module: 'header menu',
control: 'import button',
type: 'imported doc',
});
}
}, [importFile]);
}, [doc.mode$.value, importFile]);

const showResponsiveMenu = hideShare;
const ResponsiveMenuItems = (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ export const PageOperationCell = ({
control: 'copy doc',
type: 'doc duplicate',
category: 'doc',
page: 'doc library',
});
}, [duplicate, page.id]);

Expand Down
Original file line number Diff line number Diff line change
@@ -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 { TelemetryWorkspaceContextService } from '@affine/core/modules/telemetry/services/telemetry';
import { mixpanel } from '@affine/core/utils';
import { PlusIcon } from '@blocksuite/icons/rc';
import { useService, useServices, WorkspaceService } from '@toeverything/infra';
Expand All @@ -19,8 +20,11 @@ export const AddFavouriteButton = ({ pageId }: AddFavouriteButtonProps) => {
workspaceService.workspace.docCollection
);
const favAdapter = useService(FavoriteItemsAdapter);
const telemetry = useService(TelemetryWorkspaceContextService);
const handleAddFavorite = useAsyncCallback(
async e => {
const page = telemetry.getPageContext();

if (pageId) {
e.stopPropagation();
e.preventDefault();
Expand All @@ -32,6 +36,7 @@ export const AddFavouriteButton = ({ pageId }: AddFavouriteButtonProps) => {
control: 'new fav sub doc',
type: 'doc',
category: 'page',
page: page,
});
} else {
const page = createPage();
Expand All @@ -44,10 +49,11 @@ export const AddFavouriteButton = ({ pageId }: AddFavouriteButtonProps) => {
control: 'new fav doc',
type: 'doc',
category: 'page',
page: page,
});
}
},
[pageId, createLinkedPage, createPage, favAdapter]
[telemetry, pageId, createLinkedPage, createPage, favAdapter]
);

return (
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks';
import { TelemetryWorkspaceContextService } from '@affine/core/modules/telemetry/services/telemetry';
import { mixpanel } from '@affine/core/utils';
import { useI18n } from '@affine/i18n';
import { ImportIcon } from '@blocksuite/icons/rc';
import { useService } from '@toeverything/infra';

import type { DocCollection } from '../../shared';
import { MenuItem } from '../app-sidebar';
Expand All @@ -10,28 +12,30 @@ import { usePageHelper } from '../blocksuite/block-suite-page-list/utils';
const ImportPage = ({ docCollection }: { docCollection: DocCollection }) => {
const t = useI18n();
const { importFile } = usePageHelper(docCollection);
const telemetry = useService(TelemetryWorkspaceContextService);

const onImportFile = useAsyncCallback(async () => {
const options = await importFile();
const page = telemetry.getPageContext();
if (options.isWorkspaceFile) {
mixpanel.track('WorkspaceCreated', {
page: 'doc library',
page,
segment: 'navigation panel',
module: 'doc list header',
control: 'import button',
type: 'imported workspace',
});
} else {
mixpanel.track('DocCreated', {
page: 'doc library',
page,
segment: 'navigation panel',
module: 'doc list header',
control: 'import button',
type: 'imported doc',
// category
});
}
}, [importFile]);
}, [importFile, telemetry]);

return (
<MenuItem icon={<ImportIcon />} onClick={onImportFile}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 { TelemetryWorkspaceContextService } from '@affine/core/modules/telemetry/services/telemetry';
import { mixpanel } from '@affine/core/utils';
import { apis, events } from '@affine/electron-api';
import { useI18n } from '@affine/i18n';
Expand Down Expand Up @@ -103,6 +104,8 @@ export const RootAppSidebar = memo(
)
);

const telemetry = useService(TelemetryWorkspaceContextService);

const allPageActive = currentPath === '/all';

const trashActive = currentPath === '/trash';
Expand All @@ -112,14 +115,14 @@ export const RootAppSidebar = memo(
page.load();
openPage(page.id);
mixpanel.track('DocCreated', {
page: allPageActive ? 'all' : trashActive ? 'trash' : 'other',
page: telemetry.getPageContext(),
segment: 'navigation panel',
module: 'bottom button',
control: 'new doc button',
category: 'page',
type: 'doc',
});
}, [allPageActive, createPage, openPage, trashActive]);
}, [createPage, openPage, telemetry]);

const navigateHelper = useNavigateHelper();
// Listen to the "New Page" action from the menu
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
registerAffineCommand,
} from '@affine/core/commands';
import { FavoriteItemsAdapter } from '@affine/core/modules/properties';
import { TelemetryWorkspaceContextService } from '@affine/core/modules/telemetry/services/telemetry';
import { mixpanel } from '@affine/core/utils';
import { WorkspaceFlavour } from '@affine/env/workspace';
import { useI18n } from '@affine/i18n';
Expand Down Expand Up @@ -58,6 +59,8 @@ export function useRegisterBlocksuiteEditorCommands() {
[docId, setTrashModal]
);

const telemetry = useService(TelemetryWorkspaceContextService);

const isCloudWorkspace = workspace.flavour === WorkspaceFlavour.AFFINE_CLOUD;

useEffect(() => {
Expand Down Expand Up @@ -144,6 +147,7 @@ export function useRegisterBlocksuiteEditorCommands() {
control: 'cmdk',
type: 'doc duplicate',
category: 'doc',
page: telemetry.getPageContext(),
});
},
})
Expand Down Expand Up @@ -275,5 +279,6 @@ export function useRegisterBlocksuiteEditorCommands() {
favAdapter,
docId,
doc,
telemetry,
]);
}
2 changes: 1 addition & 1 deletion packages/frontend/core/src/modules/navigation/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
export { Navigator } from './entities/navigator';
export { resolveLinkToDoc } from './utils';
export { resolveLinkToDoc, resolveRouteLinkMeta } from './utils';
export { NavigationButtons } from './view/navigation-buttons';

import { type Framework, WorkspaceScope } from '@toeverything/infra';
Expand Down
50 changes: 38 additions & 12 deletions packages/frontend/core/src/modules/navigation/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ function maybeAffineOrigin(origin: string) {
);
}

export const resolveLinkToDoc = (href: string) => {
export const resolveRouteLinkMeta = (href: string) => {
try {
const url = new URL(href, location.origin);

Expand All @@ -18,23 +18,49 @@ export const resolveLinkToDoc = (href: string) => {
return null;
}

// http://xxx/workspace/48__RTCSwASvWZxyAk3Jw/-Uge-K6SYcAbcNYfQ5U-j#xxxx
// http://xxx/workspace/all/yyy
// to { workspaceId: '48__RTCSwASvWZxyAk3Jw', docId: '-Uge-K6SYcAbcNYfQ5U-j', blockId: 'xxxx' }

const [_, workspaceId, docId, blockId] =
const [_, workspaceId, moduleName, subModuleName] =
url.toString().match(/\/workspace\/([^/]+)\/([^#]+)(?:#(.+))?/) || [];

/**
* @see /packages/frontend/core/src/router.tsx
*/
const excludedPaths = ['all', 'collection', 'tag', 'trash'];

if (!docId || excludedPaths.includes(docId)) {
return null;
if (isRouteModulePath(moduleName)) {
return {
workspaceId,
moduleName,
subModuleName,
};
} else if (moduleName) {
// for now we assume all other cases are doc links
return {
workspaceId,
moduleName: 'doc' as const,
docId: moduleName,
blockId: subModuleName,
};
}

return { workspaceId, docId, blockId };
return;
} catch {
return null;
}
};

/**
* @see /packages/frontend/core/src/router.tsx
*/
const routeModulePaths = ['all', 'collection', 'tag', 'trash'] as const;

const isRouteModulePath = (
path: string
): path is (typeof routeModulePaths)[number] =>
routeModulePaths.includes(path as any);

export const resolveLinkToDoc = (href: string) => {
const meta = resolveRouteLinkMeta(href);
if (!meta || meta.moduleName !== 'doc') return null;
return {
workspaceId: meta.workspaceId,
docId: meta.docId,
blockId: meta.blockId,
};
};
10 changes: 8 additions & 2 deletions packages/frontend/core/src/modules/telemetry/index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
import type { Framework } from '@toeverything/infra';
import { type Framework, WorkspaceScope } from '@toeverything/infra';

import { AuthService } from '../cloud';
import { TelemetryService } from './services/telemetry';
import {
TelemetryService,
TelemetryWorkspaceContextService,
} from './services/telemetry';

export function configureTelemetryModule(framework: Framework) {
framework.service(TelemetryService, [AuthService]);
framework
.scope(WorkspaceScope)
.service(TelemetryWorkspaceContextService, [WorkspaceScope]);
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
import { mixpanel } from '@affine/core/utils';
import type { QuotaQuery } from '@affine/graphql';
import { ApplicationStarted, OnEvent, Service } from '@toeverything/infra';
import type { WorkspaceScope } from '@toeverything/infra';
import {
ApplicationStarted,
DocsService,
OnEvent,
Service,
} from '@toeverything/infra';

import {
AccountChanged,
Expand All @@ -9,6 +15,8 @@ import {
} from '../../cloud';
import { AccountLoggedOut } from '../../cloud/services/auth';
import { UserQuotaChanged } from '../../cloud/services/user-quota';
import { resolveRouteLinkMeta } from '../../navigation';
import { WorkbenchService } from '../../workbench';

@OnEvent(ApplicationStarted, e => e.onApplicationStart)
@OnEvent(AccountChanged, e => e.updateIdentity)
Expand Down Expand Up @@ -67,3 +75,38 @@ export class TelemetryService extends Service {
this.prevQuota = quota;
}
}

// get telemetry related context in Workspace scope
export class TelemetryWorkspaceContextService extends Service {
constructor(private readonly provider: WorkspaceScope) {
super();
}

getPageContext() {
const workbench = this.provider?.getOptional(WorkbenchService)?.workbench;
const docs = this.provider?.getOptional(DocsService);

if (!workbench || !docs) return '';

const basename = workbench.basename$.value;
const path = workbench.location$.value;
const fullPath = basename + path.pathname + path.search + path.hash;
const linkMeta = resolveRouteLinkMeta(fullPath);
return (() => {
const moduleName =
linkMeta?.moduleName === 'doc'
? docs.list.getMode(linkMeta.docId)
: linkMeta?.moduleName;
switch (moduleName) {
case 'page':
return 'page editor';
case 'edgeless':
return 'whiteboard editor';
case 'trash':
return 'trash';
default:
return 'doc library';
}
})();
}
}

0 comments on commit 8dfa601

Please sign in to comment.