248 lines
7.7 KiB
TypeScript
248 lines
7.7 KiB
TypeScript
import type { AiAgentId } from './aiAgents'
|
|
import type { AiAgentPermissionMode } from './aiAgentPermissionMode'
|
|
import { trackEvent } from './telemetry'
|
|
import type { AllNotesFileVisibility } from '../utils/allNotesFileVisibility'
|
|
import type { DateDisplayFormat } from '../utils/dateDisplay'
|
|
import type { FilePreviewKind } from '../utils/filePreview'
|
|
import type { GitProviderId, NoteWidthMode } from '../types'
|
|
import type { CommitMessageDraftSource } from '../utils/commitMessageDraft'
|
|
import type { ThemeMode } from './themeMode'
|
|
|
|
type TrackedPreviewKind = FilePreviewKind | 'unsupported'
|
|
type FilePreviewAction = 'copy_deep_link' | 'copy_path' | 'open_external' | 'reveal'
|
|
type AgentBlockedReason = 'agent_unavailable' | 'missing_vault'
|
|
type AiWorkspaceMode = 'docked' | 'side' | 'window'
|
|
type AiWorkspaceTitleSource = 'generated' | 'manual'
|
|
type NotePdfExportFailureReason = 'export_unavailable' | 'export_error'
|
|
type NotePdfExportSource = 'breadcrumb' | 'app_command' | 'note_list_context_menu'
|
|
type AnalyticsBoolean = boolean
|
|
type AiAgentResponseText = string
|
|
type AiAgentToolCount = number
|
|
type AiAgentResponseTextFlag = 'had_text' | 'had_partial_response'
|
|
type SheetFormulaFunctionName = string
|
|
|
|
const ALL_NOTES_VISIBILITY_CATEGORIES: ReadonlyArray<keyof AllNotesFileVisibility> = [
|
|
'pdfs',
|
|
'images',
|
|
'unsupported',
|
|
]
|
|
|
|
function trackedPreviewKind(previewKind: FilePreviewKind | null): TrackedPreviewKind {
|
|
return previewKind ?? 'unsupported'
|
|
}
|
|
|
|
function numericFlag(value: AnalyticsBoolean): number {
|
|
return value ? 1 : 0
|
|
}
|
|
|
|
function aiAgentResponsePayload(
|
|
agent: AiAgentId,
|
|
response: AiAgentResponseText,
|
|
toolCount: AiAgentToolCount,
|
|
textFlag: AiAgentResponseTextFlag,
|
|
) {
|
|
return {
|
|
agent,
|
|
[textFlag]: numericFlag(response.trim().length > 0),
|
|
tool_count: toolCount,
|
|
}
|
|
}
|
|
|
|
export function trackFilePreviewOpened(previewKind: FilePreviewKind | null): void {
|
|
trackEvent('file_preview_opened', {
|
|
preview_kind: trackedPreviewKind(previewKind),
|
|
})
|
|
}
|
|
|
|
export function trackFilePreviewAction(action: FilePreviewAction, previewKind: FilePreviewKind | null): void {
|
|
trackEvent('file_preview_action', {
|
|
action,
|
|
preview_kind: trackedPreviewKind(previewKind),
|
|
})
|
|
}
|
|
|
|
export function trackFilePreviewFailed(previewKind: FilePreviewKind): void {
|
|
trackEvent('file_preview_failed', { preview_kind: previewKind })
|
|
}
|
|
|
|
export function trackNotePdfExportStarted(source: NotePdfExportSource): void {
|
|
trackEvent('note_pdf_export_started', { source })
|
|
}
|
|
|
|
export function trackNotePdfExportFailed(
|
|
source: NotePdfExportSource,
|
|
reason: NotePdfExportFailureReason,
|
|
): void {
|
|
trackEvent('note_pdf_export_failed', { reason, source })
|
|
}
|
|
|
|
export function trackAllNotesVisibilityChanged(
|
|
previous: AllNotesFileVisibility,
|
|
next: AllNotesFileVisibility,
|
|
): void {
|
|
for (const category of ALL_NOTES_VISIBILITY_CATEGORIES) {
|
|
const previousValue = Reflect.get(previous, category) as boolean
|
|
const nextValue = Reflect.get(next, category) as boolean
|
|
if (previousValue === nextValue) continue
|
|
trackEvent('all_notes_visibility_changed', {
|
|
category,
|
|
enabled: numericFlag(nextValue),
|
|
})
|
|
}
|
|
}
|
|
|
|
export function trackAiFeaturesEnabledChanged(enabled: AnalyticsBoolean): void {
|
|
trackEvent('ai_features_visibility_changed', {
|
|
enabled: numericFlag(enabled),
|
|
})
|
|
}
|
|
|
|
export function trackGitFeaturesEnabledChanged(enabled: AnalyticsBoolean): void {
|
|
trackEvent('git_features_visibility_changed', {
|
|
enabled: numericFlag(enabled),
|
|
})
|
|
}
|
|
|
|
export function trackGitProviderChanged(provider: GitProviderId): void {
|
|
trackEvent('git_provider_changed', { provider })
|
|
}
|
|
|
|
export function trackGitWslDistroChanged(hasDistro: AnalyticsBoolean): void {
|
|
trackEvent('git_wsl_distro_changed', {
|
|
has_distro: numericFlag(hasDistro),
|
|
})
|
|
}
|
|
|
|
export function trackGitProviderTested(provider: GitProviderId, available: AnalyticsBoolean): void {
|
|
trackEvent('git_provider_tested', {
|
|
available: numericFlag(available),
|
|
provider,
|
|
})
|
|
}
|
|
|
|
export function trackCommitMessageGenerated(params: {
|
|
aiAttempted: AnalyticsBoolean
|
|
fileCount: number
|
|
source: CommitMessageDraftSource
|
|
}): void {
|
|
trackEvent('commit_message_generated', {
|
|
ai_attempted: numericFlag(params.aiAttempted),
|
|
file_count: params.fileCount,
|
|
source: params.source,
|
|
})
|
|
}
|
|
|
|
export function trackDefaultNoteWidthChanged(mode: NoteWidthMode): void {
|
|
trackEvent('note_width_default_changed', { mode })
|
|
}
|
|
|
|
export function trackDateDisplayFormatChanged(format: DateDisplayFormat): void {
|
|
trackEvent('date_display_format_changed', { format })
|
|
}
|
|
|
|
export function trackSidebarTypePluralizationChanged(enabled: AnalyticsBoolean): void {
|
|
trackEvent('sidebar_type_pluralization_changed', {
|
|
enabled: numericFlag(enabled),
|
|
})
|
|
}
|
|
|
|
export function trackThemeModeChanged(mode: ThemeMode): void {
|
|
trackEvent('theme_mode_changed', { mode })
|
|
}
|
|
|
|
export function trackInlineImageLightboxOpened(): void {
|
|
trackEvent('inline_image_lightbox_opened')
|
|
}
|
|
|
|
export function trackDatePropertyDirectEntrySaved(): void {
|
|
trackEvent('date_property_direct_entry_saved', { source: 'properties_panel' })
|
|
}
|
|
|
|
export function trackSheetEditorOpened(params: {
|
|
columnCount: number
|
|
hasMetadata: boolean
|
|
rowCount: number
|
|
}): void {
|
|
trackEvent('sheet_editor_opened', {
|
|
column_count: params.columnCount,
|
|
has_metadata: numericFlag(params.hasMetadata),
|
|
row_count: params.rowCount,
|
|
})
|
|
}
|
|
|
|
export function trackSheetFormulaAutocompleteUsed(functionName: SheetFormulaFunctionName): void {
|
|
trackEvent('sheet_formula_autocomplete_used', { function_name: functionName })
|
|
}
|
|
|
|
export function trackAiAgentMessageBlocked(agent: AiAgentId, reason: AgentBlockedReason): void {
|
|
trackEvent('ai_agent_message_blocked', { agent, reason })
|
|
}
|
|
|
|
export function trackAiAgentMessageSent(params: {
|
|
agent: AiAgentId
|
|
permissionMode: AiAgentPermissionMode
|
|
hasContext: boolean
|
|
referenceCount: number
|
|
historyMessageCount: number
|
|
}): void {
|
|
trackEvent('ai_agent_message_sent', {
|
|
agent: params.agent,
|
|
permission_mode: params.permissionMode,
|
|
has_context: numericFlag(params.hasContext),
|
|
reference_count: params.referenceCount,
|
|
history_message_count: params.historyMessageCount,
|
|
})
|
|
}
|
|
|
|
export function trackAiAgentResponseCompleted(
|
|
agent: AiAgentId,
|
|
response: AiAgentResponseText,
|
|
toolCount: AiAgentToolCount,
|
|
skipped: AnalyticsBoolean,
|
|
): void {
|
|
if (skipped) return
|
|
trackEvent('ai_agent_response_completed', aiAgentResponsePayload(agent, response, toolCount, 'had_text'))
|
|
}
|
|
|
|
export function trackAiAgentResponseFailed(
|
|
agent: AiAgentId,
|
|
response: AiAgentResponseText,
|
|
toolCount: AiAgentToolCount,
|
|
): void {
|
|
trackEvent('ai_agent_response_failed', {
|
|
...aiAgentResponsePayload(agent, response, toolCount, 'had_partial_response'),
|
|
error_kind: 'stream_error',
|
|
})
|
|
}
|
|
|
|
export function trackAiAgentResponseStopped(
|
|
agent: AiAgentId,
|
|
response: AiAgentResponseText,
|
|
toolCount: AiAgentToolCount,
|
|
): void {
|
|
trackEvent('ai_agent_response_stopped', aiAgentResponsePayload(agent, response, toolCount, 'had_partial_response'))
|
|
}
|
|
|
|
export function trackAiAgentPermissionModeChanged(agent: AiAgentId, permissionMode: AiAgentPermissionMode): void {
|
|
trackEvent('ai_agent_permission_mode_changed', {
|
|
agent,
|
|
permission_mode: permissionMode,
|
|
})
|
|
}
|
|
|
|
export function trackAiWorkspaceSidebarToggled(collapsed: AnalyticsBoolean, mode: AiWorkspaceMode): void {
|
|
trackEvent('ai_workspace_sidebar_toggled', {
|
|
collapsed: numericFlag(collapsed),
|
|
mode,
|
|
})
|
|
}
|
|
|
|
export function trackAiWorkspaceChatTitled(source: AiWorkspaceTitleSource): void {
|
|
trackEvent('ai_workspace_chat_titled', { source })
|
|
}
|
|
|
|
export function trackAiWorkspaceConversationDeleted(archived: AnalyticsBoolean): void {
|
|
trackEvent('ai_workspace_conversation_deleted', {
|
|
archived: numericFlag(archived),
|
|
})
|
|
}
|