mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-25 02:13:00 +08:00
feat(editor): track citation events (#12664)
Closes: [BS-3551](https://linear.app/affine-design/issue/BS-3551/citation埋点) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **New Features** - Enhanced citation tracking across attachments, bookmarks, embedded documents, paragraphs, footnotes, rename modals, and toolbars for actions like editing, deleting, expanding, and hovering on citations. - Introduced a centralized citation service to unify citation detection and telemetry event management. - **Chores** - Updated service exports and telemetry modules to include the new citation service and citation-related event types. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
@@ -0,0 +1,84 @@
|
||||
import { type Container, createIdentifier } from '@blocksuite/global/di';
|
||||
import { type BlockStdScope, StdIdentifier } from '@blocksuite/std';
|
||||
import { type BlockModel, Extension } from '@blocksuite/store';
|
||||
|
||||
import { DocModeProvider } from '../doc-mode-service';
|
||||
import type {
|
||||
CitationEvents,
|
||||
CitationEventType,
|
||||
} from '../telemetry-service/citation';
|
||||
import { TelemetryProvider } from '../telemetry-service/telemetry-service';
|
||||
|
||||
const CitationEventTypeMap = {
|
||||
Hover: 'AICitationHoverSource',
|
||||
Expand: 'AICitationExpandSource',
|
||||
Delete: 'AICitationDelete',
|
||||
Edit: 'AICitationEdit',
|
||||
} as const;
|
||||
|
||||
type EventType = keyof typeof CitationEventTypeMap;
|
||||
|
||||
type EventTypeMapping = {
|
||||
[K in EventType]: CitationEventType;
|
||||
};
|
||||
|
||||
export interface CitationViewService {
|
||||
/**
|
||||
* Tracks citation-related events
|
||||
* @param type - The type of citation event to track
|
||||
* @param properties - The properties of the event
|
||||
*/
|
||||
trackEvent<T extends EventType>(
|
||||
type: T,
|
||||
properties?: CitationEvents[EventTypeMapping[T]]
|
||||
): void;
|
||||
/**
|
||||
* Checks if the model is a citation model
|
||||
* @param model - The model to check
|
||||
* @returns True if the model is a citation model, false otherwise
|
||||
*/
|
||||
isCitationModel(model: BlockModel): boolean;
|
||||
}
|
||||
|
||||
export const CitationProvider =
|
||||
createIdentifier<CitationViewService>('CitationService');
|
||||
|
||||
export class CitationService extends Extension implements CitationViewService {
|
||||
constructor(private readonly std: BlockStdScope) {
|
||||
super();
|
||||
}
|
||||
|
||||
static override setup(di: Container) {
|
||||
di.addImpl(CitationProvider, CitationService, [StdIdentifier]);
|
||||
}
|
||||
|
||||
get docModeService() {
|
||||
return this.std.getOptional(DocModeProvider);
|
||||
}
|
||||
|
||||
get telemetryService() {
|
||||
return this.std.getOptional(TelemetryProvider);
|
||||
}
|
||||
|
||||
isCitationModel = (model: BlockModel) => {
|
||||
return (
|
||||
'footnoteIdentifier' in model.props &&
|
||||
!!model.props.footnoteIdentifier &&
|
||||
'style' in model.props &&
|
||||
model.props.style === 'citation'
|
||||
);
|
||||
};
|
||||
|
||||
trackEvent<T extends EventType>(
|
||||
type: T,
|
||||
properties?: CitationEvents[EventTypeMapping[T]]
|
||||
) {
|
||||
const editorMode = this.docModeService?.getEditorMode() ?? 'page';
|
||||
this.telemetryService?.track(CitationEventTypeMap[type], {
|
||||
page: editorMode === 'page' ? 'doc editor' : 'whiteboard editor',
|
||||
module: 'AI Result',
|
||||
control: 'Source',
|
||||
...properties,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
export * from './citation-service';
|
||||
@@ -1,5 +1,6 @@
|
||||
export * from './auto-clear-selection-service';
|
||||
export * from './block-meta-service';
|
||||
export * from './citation-service';
|
||||
export * from './doc-display-meta-service';
|
||||
export * from './doc-mode-service';
|
||||
export * from './drag-handle-config';
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
import type { TelemetryEvent } from './types';
|
||||
export type CitationEventType =
|
||||
| 'AICitationHoverSource'
|
||||
| 'AICitationExpandSource'
|
||||
| 'AICitationDelete'
|
||||
| 'AICitationEdit';
|
||||
|
||||
export type CitationEvents = Record<CitationEventType, TelemetryEvent>;
|
||||
@@ -1,3 +1,4 @@
|
||||
export * from './citation.js';
|
||||
export * from './database.js';
|
||||
export * from './link.js';
|
||||
export * from './telemetry-service.js';
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { createIdentifier } from '@blocksuite/global/di';
|
||||
import type { ExtensionType } from '@blocksuite/store';
|
||||
|
||||
import type { CitationEvents } from './citation.js';
|
||||
import type { CodeBlockEvents } from './code-block.js';
|
||||
import type { OutDatabaseAllEvents } from './database.js';
|
||||
import type { LinkToolbarEvents } from './link.js';
|
||||
@@ -28,7 +29,8 @@ export type TelemetryEventMap = OutDatabaseAllEvents &
|
||||
LinkToolbarEvents &
|
||||
SlashMenuEvents &
|
||||
CodeBlockEvents &
|
||||
NoteEvents & {
|
||||
NoteEvents &
|
||||
CitationEvents & {
|
||||
DocCreated: DocCreatedEvent;
|
||||
Link: TelemetryEvent;
|
||||
LinkedDocCreated: LinkedDocCreatedEvent;
|
||||
|
||||
Reference in New Issue
Block a user