Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions src/platform/settings/settingStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@ import { compare, valid } from 'semver'
import { ref } from 'vue'

import type { SettingParams } from '@/platform/settings/types'
import { useTelemetry } from '@/platform/telemetry'
import type { Settings } from '@/schemas/apiSchema'
import { api } from '@/scripts/api'
import { app } from '@/scripts/app'
import { useDialogStore } from '@/stores/dialogStore'
import type { TreeNode } from '@/types/treeExplorerTypes'

export const getSettingInfo = (setting: SettingParams) => {
Expand Down Expand Up @@ -73,6 +75,39 @@ export const useSettingStore = defineStore('setting', () => {
onChange(settingsById.value[key], newValue, oldValue)
settingValues.value[key] = newValue
await api.storeSetting(key, newValue)

try {
const dialogStore = useDialogStore()
if (dialogStore.isDialogOpen('global-settings')) {
const telemetry = useTelemetry()
const settingParameter = settingsById.value[key]
const { category, subCategory } = getSettingInfo(
settingParameter ??
({
id: String(key)
} as unknown as SettingParams)
)

const inputType = (() => {
const settingType = settingParameter?.type
if (!settingType) return undefined
return typeof settingType === 'function'
? 'custom'
: String(settingType)
})()

telemetry?.trackSettingChanged({
setting_id: String(key),
input_type: inputType,
category,
sub_category: subCategory,
previous_value: oldValue,
new_value: newValue
})
}
} catch (err) {
console.error('Failed to track setting change', err)
}
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import { app } from '@/scripts/app'
import { useNodeDefStore } from '@/stores/nodeDefStore'
import { NodeSourceType } from '@/types/nodeSource'
import { reduceAllNodes } from '@/utils/graphTraversalUtil'
import { normalizeSurveyResponses } from '../../utils/surveyNormalization'

import type {
AuthMetadata,
Expand All @@ -19,18 +18,20 @@ import type {
NodeSearchResultMetadata,
PageVisibilityMetadata,
RunButtonProperties,
SettingChangedMetadata,
SurveyResponses,
TabCountMetadata,
TelemetryEventName,
TelemetryEventProperties,
TelemetryProvider,
TemplateFilterMetadata,
TemplateLibraryMetadata,
TemplateLibraryClosedMetadata,
TemplateLibraryMetadata,
TemplateMetadata,
WorkflowImportMetadata
} from '../../types'
import { TelemetryEvents } from '../../types'
import { normalizeSurveyResponses } from '../../utils/surveyNormalization'

interface QueuedEvent {
eventName: TelemetryEventName
Expand Down Expand Up @@ -282,6 +283,10 @@ export class MixpanelTelemetryProvider implements TelemetryProvider {
this.trackEvent(TelemetryEvents.EXECUTION_SUCCESS, metadata)
}

trackSettingChanged(metadata: SettingChangedMetadata): void {
this.trackEvent(TelemetryEvents.SETTING_CHANGED, metadata)
}

getExecutionContext(): ExecutionContext {
const workflowStore = useWorkflowStore()
const templatesStore = useWorkflowTemplatesStore()
Expand Down
19 changes: 19 additions & 0 deletions src/platform/telemetry/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,18 @@ export interface TabCountMetadata {
tab_count: number
}

/**
* Settings change metadata
*/
export interface SettingChangedMetadata {
setting_id: string
input_type?: string
category?: string
sub_category?: string
previous_value?: unknown
new_value?: unknown
}

/**
* Node search metadata
*/
Expand Down Expand Up @@ -239,6 +251,9 @@ export interface TelemetryProvider {
trackWorkflowExecution(): void
trackExecutionError(metadata: ExecutionErrorMetadata): void
trackExecutionSuccess(metadata: ExecutionSuccessMetadata): void

// Settings events
trackSettingChanged(metadata: SettingChangedMetadata): void
}

/**
Expand Down Expand Up @@ -293,6 +308,9 @@ export const TelemetryEvents = {
// Template Filter Analytics
TEMPLATE_FILTER_CHANGED: 'app:template_filter_changed',

// Settings
SETTING_CHANGED: 'app:setting_changed',

// Execution Lifecycle
EXECUTION_START: 'execution_start',
EXECUTION_ERROR: 'execution_error',
Expand Down Expand Up @@ -322,3 +340,4 @@ export type TelemetryEventProperties =
| NodeSearchMetadata
| NodeSearchResultMetadata
| TemplateFilterMetadata
| SettingChangedMetadata
56 changes: 56 additions & 0 deletions tests-ui/tests/store/settingStore.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
import type { SettingParams } from '@/platform/settings/types'
import { api } from '@/scripts/api'
import { app } from '@/scripts/app'
import { useDialogStore } from '@/stores/dialogStore'

// Mock the api
vi.mock('@/scripts/api', () => ({
Expand All @@ -17,6 +18,14 @@ vi.mock('@/scripts/api', () => ({
}
}))

// Mock telemetry provider
const trackSettingChanged = vi.fn()
vi.mock('@/platform/telemetry', () => ({
useTelemetry: vi.fn(() => ({
trackSettingChanged
}))
}))

// Mock the app
vi.mock('@/scripts/app', () => ({
app: {
Expand Down Expand Up @@ -399,6 +408,53 @@ describe('useSettingStore', () => {
)
})

it('should send telemetry when global settings dialog is visible', async () => {
const setting: SettingParams = {
id: 'main.sub.setting.name',
name: 'Telemetry Visible',
type: 'text',
defaultValue: 'default'
}

store.addSetting(setting)

const dialogStore = useDialogStore()
dialogStore.showDialog({
key: 'global-settings',
title: 'Settings',
component: {}
})

await store.set('main.sub.setting.name', 'newvalue')

expect(trackSettingChanged).toHaveBeenCalledTimes(1)
expect(trackSettingChanged).toHaveBeenCalledWith(
expect.objectContaining({
setting_id: 'main.sub.setting.name',
input_type: 'text',
category: 'main',
sub_category: 'sub',
previous_value: 'default',
new_value: 'newvalue'
})
)
})

it('should not send telemetry when global settings dialog is not visible', async () => {
const setting: SettingParams = {
id: 'main.sub.setting.name',
name: 'Telemetry Invisible',
type: 'text',
defaultValue: 'default'
}

store.addSetting(setting)

await store.set('main.sub.setting.name', 'newvalue')

expect(trackSettingChanged).not.toHaveBeenCalled()
})

describe('object mutation prevention', () => {
beforeEach(() => {
const setting: SettingParams = {
Expand Down