mirror of
https://github.com/langgenius/dify.git
synced 2026-05-10 14:14:17 +08:00
refactor: update app creation tracking to use appMode instead of source identifiers
This commit is contained in:
parent
2d2b107a75
commit
2c121b38af
@ -247,8 +247,7 @@ describe('Apps', () => {
|
||||
})
|
||||
|
||||
expect(mockTrackCreateApp).toHaveBeenCalledWith({
|
||||
source: 'studio_template_list',
|
||||
templateId: 'Alpha',
|
||||
appMode: AppModeEnum.CHAT,
|
||||
})
|
||||
expect(mockToastSuccess).toHaveBeenCalledWith('app.newApp.appCreated')
|
||||
expect(onSuccess).toHaveBeenCalled()
|
||||
|
||||
@ -127,8 +127,7 @@ const Apps = ({
|
||||
icon_background,
|
||||
description,
|
||||
})
|
||||
if (currApp?.app.id)
|
||||
trackCreateApp({ source: 'studio_template_list', templateId: currApp.app.id })
|
||||
trackCreateApp({ appMode: mode })
|
||||
|
||||
setIsShowCreateModal(false)
|
||||
toast.success(t('newApp.appCreated', { ns: 'app' }))
|
||||
|
||||
@ -178,7 +178,7 @@ describe('CreateAppModal', () => {
|
||||
mode: AppModeEnum.ADVANCED_CHAT,
|
||||
}))
|
||||
|
||||
expect(mockTrackCreateApp).toHaveBeenCalledWith({ source: 'studio_blank' })
|
||||
expect(mockTrackCreateApp).toHaveBeenCalledWith({ appMode: AppModeEnum.ADVANCED_CHAT })
|
||||
expect(mockToastSuccess).toHaveBeenCalledWith('app.newApp.appCreated')
|
||||
expect(onSuccess).toHaveBeenCalled()
|
||||
expect(onClose).toHaveBeenCalled()
|
||||
|
||||
@ -80,7 +80,7 @@ function CreateApp({ onClose, onSuccess, onCreateFromTemplate, defaultAppMode }:
|
||||
mode: appMode,
|
||||
})
|
||||
|
||||
trackCreateApp({ source: 'studio_blank' })
|
||||
trackCreateApp({ appMode: app.mode })
|
||||
|
||||
toast.success(t('newApp.appCreated', { ns: 'app' }))
|
||||
onSuccess()
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
import { act, fireEvent, render, screen, waitFor } from '@testing-library/react'
|
||||
import { NEED_REFRESH_APP_LIST_KEY } from '@/config'
|
||||
import { DSLImportMode, DSLImportStatus } from '@/models/app'
|
||||
import { AppModeEnum } from '@/types/app'
|
||||
import CreateFromDSLModal, { CreateFromDSLModalTab } from '../index'
|
||||
|
||||
const mockPush = vi.fn()
|
||||
@ -172,7 +173,7 @@ describe('CreateFromDSLModal', () => {
|
||||
id: 'import-1',
|
||||
status: DSLImportStatus.COMPLETED,
|
||||
app_id: 'app-1',
|
||||
app_mode: 'chat',
|
||||
app_mode: AppModeEnum.CHAT,
|
||||
})
|
||||
|
||||
render(
|
||||
@ -196,7 +197,7 @@ describe('CreateFromDSLModal', () => {
|
||||
mode: DSLImportMode.YAML_URL,
|
||||
yaml_url: 'https://example.com/app.yml',
|
||||
})
|
||||
expect(mockTrackCreateApp).toHaveBeenCalledWith({ source: 'studio_upload' })
|
||||
expect(mockTrackCreateApp).toHaveBeenCalledWith({ appMode: AppModeEnum.CHAT })
|
||||
expect(handleSuccess).toHaveBeenCalledTimes(1)
|
||||
expect(handleClose).toHaveBeenCalledTimes(1)
|
||||
expect(localStorage.getItem(NEED_REFRESH_APP_LIST_KEY)).toBe('1')
|
||||
@ -209,7 +210,7 @@ describe('CreateFromDSLModal', () => {
|
||||
id: 'import-2',
|
||||
status: DSLImportStatus.COMPLETED_WITH_WARNINGS,
|
||||
app_id: 'app-2',
|
||||
app_mode: 'chat',
|
||||
app_mode: AppModeEnum.CHAT,
|
||||
})
|
||||
|
||||
render(
|
||||
@ -272,7 +273,7 @@ describe('CreateFromDSLModal', () => {
|
||||
mockImportDSLConfirm.mockResolvedValue({
|
||||
status: DSLImportStatus.COMPLETED,
|
||||
app_id: 'app-3',
|
||||
app_mode: 'workflow',
|
||||
app_mode: AppModeEnum.WORKFLOW,
|
||||
})
|
||||
|
||||
render(
|
||||
@ -302,7 +303,7 @@ describe('CreateFromDSLModal', () => {
|
||||
expect(mockImportDSLConfirm).toHaveBeenCalledWith({
|
||||
import_id: 'import-3',
|
||||
})
|
||||
expect(mockTrackCreateApp).toHaveBeenCalledWith({ source: 'studio_upload' })
|
||||
expect(mockTrackCreateApp).toHaveBeenCalledWith({ appMode: AppModeEnum.WORKFLOW })
|
||||
})
|
||||
|
||||
it('should ignore empty import responses and prevent duplicate submissions while a request is in flight', async () => {
|
||||
@ -330,7 +331,7 @@ describe('CreateFromDSLModal', () => {
|
||||
id: 'import-in-flight',
|
||||
status: DSLImportStatus.COMPLETED,
|
||||
app_id: 'app-1',
|
||||
app_mode: 'chat',
|
||||
app_mode: AppModeEnum.CHAT,
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
@ -112,7 +112,7 @@ const CreateFromDSLModal = ({ show, onSuccess, onClose, activeTab = CreateFromDS
|
||||
return
|
||||
const { id, status, app_id, app_mode, imported_dsl_version, current_dsl_version } = response
|
||||
if (status === DSLImportStatus.COMPLETED || status === DSLImportStatus.COMPLETED_WITH_WARNINGS) {
|
||||
trackCreateApp({ source: 'studio_upload' })
|
||||
trackCreateApp({ appMode: app_mode })
|
||||
|
||||
if (onSuccess)
|
||||
onSuccess()
|
||||
@ -174,7 +174,7 @@ const CreateFromDSLModal = ({ show, onSuccess, onClose, activeTab = CreateFromDS
|
||||
const { status, app_id, app_mode } = response
|
||||
|
||||
if (status === DSLImportStatus.COMPLETED) {
|
||||
trackCreateApp({ source: 'studio_upload' })
|
||||
trackCreateApp({ appMode: app_mode })
|
||||
if (onSuccess)
|
||||
onSuccess()
|
||||
if (onClose)
|
||||
|
||||
@ -238,8 +238,7 @@ describe('Apps', () => {
|
||||
await waitFor(() => {
|
||||
expect(mockFetchAppDetail).toHaveBeenCalledWith('template-1')
|
||||
expect(mockTrackCreateApp).toHaveBeenCalledWith({
|
||||
source: 'studio_template_preview',
|
||||
templateId: 'template-1',
|
||||
appMode: AppModeEnum.CHAT,
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
'use client'
|
||||
import type { CreateAppModalProps } from '../explore/create-app-modal'
|
||||
import type { TryAppSelection } from '@/types/try-app'
|
||||
import { useCallback, useState } from 'react'
|
||||
import { useCallback, useRef, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useEducationInit } from '@/app/education-apply/hooks'
|
||||
import AppListContext from '@/context/app-list-context'
|
||||
@ -24,6 +24,7 @@ const Apps = () => {
|
||||
useEducationInit()
|
||||
|
||||
const [currentTryAppParams, setCurrentTryAppParams] = useState<TryAppSelection | undefined>(undefined)
|
||||
const currentCreateAppModeRef = useRef<TryAppSelection['app']['app']['mode'] | null>(null)
|
||||
const currApp = currentTryAppParams?.app
|
||||
const [isShowTryAppPanel, setIsShowTryAppPanel] = useState(false)
|
||||
const hideTryAppPanel = useCallback(() => {
|
||||
@ -42,12 +43,11 @@ const Apps = () => {
|
||||
setIsShowCreateModal(true)
|
||||
}, [])
|
||||
const trackCurrentCreateApp = useCallback(() => {
|
||||
const templateId = currApp?.app.id
|
||||
if (!templateId)
|
||||
if (!currentCreateAppModeRef.current)
|
||||
return
|
||||
|
||||
trackCreateApp({ source: 'studio_template_preview', templateId })
|
||||
}, [currApp?.app.id])
|
||||
trackCreateApp({ appMode: currentCreateAppModeRef.current })
|
||||
}, [])
|
||||
|
||||
const [controlRefreshList, setControlRefreshList] = useState(0)
|
||||
const [controlHideCreateFromTemplatePanel, setControlHideCreateFromTemplatePanel] = useState(0)
|
||||
@ -83,9 +83,10 @@ const Apps = () => {
|
||||
}) => {
|
||||
hideTryAppPanel()
|
||||
|
||||
const { export_data } = await fetchAppDetail(
|
||||
const { export_data, mode } = await fetchAppDetail(
|
||||
currApp?.app.id as string,
|
||||
)
|
||||
currentCreateAppModeRef.current = mode
|
||||
const payload = {
|
||||
mode: DSLImportMode.YAML_CONTENT,
|
||||
yaml_content: export_data,
|
||||
|
||||
@ -5,7 +5,7 @@ import * as amplitude from '@amplitude/analytics-browser'
|
||||
import { sessionReplayPlugin } from '@amplitude/plugin-session-replay-browser'
|
||||
import * as React from 'react'
|
||||
import { useEffect } from 'react'
|
||||
import { AMPLITUDE_API_KEY, isAmplitudeEnabled } from '@/config'
|
||||
import { AMPLITUDE_API_KEY } from '@/config'
|
||||
|
||||
export type IAmplitudeProps = {
|
||||
sessionReplaySampleRate?: number
|
||||
@ -54,8 +54,8 @@ const AmplitudeProvider: FC<IAmplitudeProps> = ({
|
||||
}) => {
|
||||
useEffect(() => {
|
||||
// Only enable in Saas edition with valid API key
|
||||
if (!isAmplitudeEnabled)
|
||||
return
|
||||
// if (!isAmplitudeEnabled)
|
||||
// return
|
||||
|
||||
// Initialize Amplitude
|
||||
amplitude.init(AMPLITUDE_API_KEY, {
|
||||
|
||||
@ -218,7 +218,7 @@ describe('AppList', () => {
|
||||
categories: ['Writing'],
|
||||
allList: [createApp()],
|
||||
};
|
||||
(fetchAppDetail as unknown as Mock).mockResolvedValue({ export_data: 'yaml-content' })
|
||||
(fetchAppDetail as unknown as Mock).mockResolvedValue({ export_data: 'yaml-content', mode: AppModeEnum.CHAT })
|
||||
mockHandleImportDSL.mockImplementation(async (_payload: unknown, options: { onSuccess?: () => void, onPending?: () => void }) => {
|
||||
options.onPending?.()
|
||||
})
|
||||
@ -240,8 +240,7 @@ describe('AppList', () => {
|
||||
await waitFor(() => {
|
||||
expect(mockHandleImportDSLConfirm).toHaveBeenCalledTimes(1)
|
||||
expect(mockTrackCreateApp).toHaveBeenCalledWith({
|
||||
source: 'explore_template_list',
|
||||
templateId: 'app-basic-id',
|
||||
appMode: AppModeEnum.CHAT,
|
||||
})
|
||||
expect(onSuccess).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
@ -315,7 +314,7 @@ describe('AppList', () => {
|
||||
categories: ['Writing'],
|
||||
allList: [createApp()],
|
||||
};
|
||||
(fetchAppDetail as unknown as Mock).mockResolvedValue({ export_data: 'yaml' })
|
||||
(fetchAppDetail as unknown as Mock).mockResolvedValue({ export_data: 'yaml', mode: AppModeEnum.CHAT })
|
||||
|
||||
renderAppList(true)
|
||||
fireEvent.click(screen.getByText('explore.appCard.addToWorkspace'))
|
||||
@ -333,7 +332,7 @@ describe('AppList', () => {
|
||||
categories: ['Writing'],
|
||||
allList: [createApp()],
|
||||
};
|
||||
(fetchAppDetail as unknown as Mock).mockResolvedValue({ export_data: 'yaml' })
|
||||
(fetchAppDetail as unknown as Mock).mockResolvedValue({ export_data: 'yaml', mode: AppModeEnum.CHAT })
|
||||
mockHandleImportDSL.mockImplementation(async (_payload: unknown, options: { onSuccess?: () => void }) => {
|
||||
options.onSuccess?.()
|
||||
})
|
||||
@ -346,8 +345,7 @@ describe('AppList', () => {
|
||||
expect(screen.queryByTestId('create-app-modal')).not.toBeInTheDocument()
|
||||
})
|
||||
expect(mockTrackCreateApp).toHaveBeenCalledWith({
|
||||
source: 'explore_template_list',
|
||||
templateId: 'app-basic-id',
|
||||
appMode: AppModeEnum.CHAT,
|
||||
})
|
||||
})
|
||||
|
||||
@ -357,7 +355,7 @@ describe('AppList', () => {
|
||||
categories: ['Writing'],
|
||||
allList: [createApp()],
|
||||
};
|
||||
(fetchAppDetail as unknown as Mock).mockResolvedValue({ export_data: 'yaml' })
|
||||
(fetchAppDetail as unknown as Mock).mockResolvedValue({ export_data: 'yaml', mode: AppModeEnum.CHAT })
|
||||
mockHandleImportDSL.mockImplementation(async (_payload: unknown, options: { onPending?: () => void }) => {
|
||||
options.onPending?.()
|
||||
})
|
||||
@ -403,7 +401,7 @@ describe('AppList', () => {
|
||||
categories: ['Writing'],
|
||||
allList: [createApp()],
|
||||
};
|
||||
(fetchAppDetail as unknown as Mock).mockResolvedValue({ export_data: 'yaml' })
|
||||
(fetchAppDetail as unknown as Mock).mockResolvedValue({ export_data: 'yaml', mode: AppModeEnum.CHAT })
|
||||
mockHandleImportDSL.mockImplementation(async (_payload: unknown, options: { onSuccess?: () => void }) => {
|
||||
options.onSuccess?.()
|
||||
})
|
||||
@ -416,8 +414,7 @@ describe('AppList', () => {
|
||||
|
||||
await waitFor(() => {
|
||||
expect(mockTrackCreateApp).toHaveBeenCalledWith({
|
||||
source: 'explore_template_preview',
|
||||
templateId: 'app-basic-id',
|
||||
appMode: AppModeEnum.CHAT,
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@ -6,7 +6,7 @@ import type { TryAppSelection } from '@/types/try-app'
|
||||
import { useDebounceFn } from 'ahooks'
|
||||
import { useQueryState } from 'nuqs'
|
||||
import * as React from 'react'
|
||||
import { useCallback, useMemo, useState } from 'react'
|
||||
import { useCallback, useMemo, useRef, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import DSLConfirmModal from '@/app/components/app/create-from-dsl-modal/dsl-confirm-modal'
|
||||
import Button from '@/app/components/base/button'
|
||||
@ -92,7 +92,6 @@ const Apps = ({
|
||||
|
||||
const [currApp, setCurrApp] = useState<App | null>(null)
|
||||
const [isShowCreateModal, setIsShowCreateModal] = useState(false)
|
||||
const [createAppSource, setCreateAppSource] = useState<'explore_template_list' | 'explore_template_preview'>('explore_template_list')
|
||||
|
||||
const {
|
||||
handleImportDSL,
|
||||
@ -103,6 +102,7 @@ const Apps = ({
|
||||
const [showDSLConfirmModal, setShowDSLConfirmModal] = useState(false)
|
||||
|
||||
const [currentTryApp, setCurrentTryApp] = useState<TryAppSelection | undefined>(undefined)
|
||||
const currentCreateAppModeRef = useRef<App['app']['mode'] | null>(null)
|
||||
const isShowTryAppPanel = !!currentTryApp
|
||||
const hideTryAppPanel = useCallback(() => {
|
||||
setCurrentTryApp(undefined)
|
||||
@ -112,16 +112,14 @@ const Apps = ({
|
||||
}, [])
|
||||
const handleShowFromTryApp = useCallback(() => {
|
||||
setCurrApp(currentTryApp?.app || null)
|
||||
setCreateAppSource('explore_template_preview')
|
||||
setIsShowCreateModal(true)
|
||||
}, [currentTryApp?.app])
|
||||
const trackCurrentCreateApp = useCallback(() => {
|
||||
const templateId = currApp?.app.id
|
||||
if (!templateId)
|
||||
if (!currentCreateAppModeRef.current)
|
||||
return
|
||||
|
||||
trackCreateApp({ source: createAppSource, templateId })
|
||||
}, [createAppSource, currApp?.app.id])
|
||||
trackCreateApp({ appMode: currentCreateAppModeRef.current })
|
||||
}, [])
|
||||
|
||||
const onCreate: CreateAppModalProps['onConfirm'] = useCallback(async ({
|
||||
name,
|
||||
@ -132,9 +130,10 @@ const Apps = ({
|
||||
}) => {
|
||||
hideTryAppPanel()
|
||||
|
||||
const { export_data } = await fetchAppDetail(
|
||||
const { export_data, mode } = await fetchAppDetail(
|
||||
currApp?.app.id as string,
|
||||
)
|
||||
currentCreateAppModeRef.current = mode
|
||||
const payload = {
|
||||
mode: DSLImportMode.YAML_CONTENT,
|
||||
yaml_content: export_data,
|
||||
@ -240,7 +239,6 @@ const Apps = ({
|
||||
canCreate={hasEditPermission}
|
||||
onCreate={() => {
|
||||
setCurrApp(app)
|
||||
setCreateAppSource('explore_template_list')
|
||||
setIsShowCreateModal(true)
|
||||
}}
|
||||
onTry={handleTryApp}
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import * as amplitude from '@/app/components/base/amplitude'
|
||||
import { AppModeEnum } from '@/types/app'
|
||||
import {
|
||||
buildCreateAppEventPayload,
|
||||
extractExternalCreateAppAttribution,
|
||||
@ -42,21 +43,58 @@ describe('create-app-tracking', () => {
|
||||
})
|
||||
|
||||
describe('buildCreateAppEventPayload', () => {
|
||||
it('should build template payloads with template id', () => {
|
||||
it('should build original payloads with normalized app mode and timestamp', () => {
|
||||
expect(buildCreateAppEventPayload({
|
||||
source: 'explore_template_preview',
|
||||
templateId: 'template-1',
|
||||
})).toEqual({
|
||||
source: 'explore_template_preview',
|
||||
template_id: 'template-1',
|
||||
appMode: AppModeEnum.ADVANCED_CHAT,
|
||||
}, null, new Date(2026, 3, 13, 14, 5, 9))).toEqual({
|
||||
source: 'original',
|
||||
app_mode: 'chatflow',
|
||||
time: '04-13-14:05:09',
|
||||
})
|
||||
})
|
||||
|
||||
it('should map agent mode into the canonical app mode bucket', () => {
|
||||
expect(buildCreateAppEventPayload({
|
||||
appMode: AppModeEnum.AGENT_CHAT,
|
||||
}, null, new Date(2026, 3, 13, 9, 8, 7))).toEqual({
|
||||
source: 'original',
|
||||
app_mode: 'agent',
|
||||
time: '04-13-09:08:07',
|
||||
})
|
||||
})
|
||||
|
||||
it('should fold legacy non-agent modes into chatflow', () => {
|
||||
expect(buildCreateAppEventPayload({
|
||||
appMode: AppModeEnum.CHAT,
|
||||
}, null, new Date(2026, 3, 13, 8, 0, 1))).toEqual({
|
||||
source: 'original',
|
||||
app_mode: 'chatflow',
|
||||
time: '04-13-08:00:01',
|
||||
})
|
||||
|
||||
expect(buildCreateAppEventPayload({
|
||||
appMode: AppModeEnum.COMPLETION,
|
||||
}, null, new Date(2026, 3, 13, 8, 0, 2))).toEqual({
|
||||
source: 'original',
|
||||
app_mode: 'chatflow',
|
||||
time: '04-13-08:00:02',
|
||||
})
|
||||
})
|
||||
|
||||
it('should map workflow mode into the workflow bucket', () => {
|
||||
expect(buildCreateAppEventPayload({
|
||||
appMode: AppModeEnum.WORKFLOW,
|
||||
}, null, new Date(2026, 3, 13, 7, 6, 5))).toEqual({
|
||||
source: 'original',
|
||||
app_mode: 'workflow',
|
||||
time: '04-13-07:06:05',
|
||||
})
|
||||
})
|
||||
|
||||
it('should prefer external attribution when present', () => {
|
||||
expect(buildCreateAppEventPayload(
|
||||
{
|
||||
source: 'studio_template_list',
|
||||
templateId: 'template-2',
|
||||
appMode: AppModeEnum.WORKFLOW,
|
||||
},
|
||||
{
|
||||
utmSource: 'linkedin',
|
||||
@ -76,7 +114,7 @@ describe('create-app-tracking', () => {
|
||||
searchParams: new URLSearchParams('utm_source=newsletter&slug=how-to-build-rag-agent'),
|
||||
})
|
||||
|
||||
trackCreateApp({ source: 'studio_blank' })
|
||||
trackCreateApp({ appMode: AppModeEnum.WORKFLOW })
|
||||
|
||||
expect(amplitude.trackEvent).toHaveBeenNthCalledWith(1, 'create_app', {
|
||||
source: 'external',
|
||||
@ -84,10 +122,12 @@ describe('create-app-tracking', () => {
|
||||
utm_campaign: 'how-to-build-rag-agent',
|
||||
})
|
||||
|
||||
trackCreateApp({ source: 'studio_blank' })
|
||||
trackCreateApp({ appMode: AppModeEnum.WORKFLOW })
|
||||
|
||||
expect(amplitude.trackEvent).toHaveBeenNthCalledWith(2, 'create_app', {
|
||||
source: 'studio_blank',
|
||||
source: 'original',
|
||||
app_mode: 'workflow',
|
||||
time: expect.stringMatching(/^\d{2}-\d{2}-\d{2}:\d{2}:\d{2}$/),
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import Cookies from 'js-cookie'
|
||||
import { trackEvent } from '@/app/components/base/amplitude'
|
||||
import { AppModeEnum } from '@/types/app'
|
||||
|
||||
const CREATE_APP_EXTERNAL_ATTRIBUTION_STORAGE_KEY = 'create_app_external_attribution'
|
||||
|
||||
@ -16,13 +17,11 @@ type SearchParamReader = {
|
||||
get: (name: string) => string | null
|
||||
}
|
||||
|
||||
type CreateAppSource = 'external' | 'explore_template_list' | 'explore_template_preview' | 'studio_blank' | 'studio_template_list' | 'studio_template_preview' | 'studio_upload'
|
||||
type OriginalCreateAppMode = 'workflow' | 'chatflow' | 'agent'
|
||||
|
||||
type TemplateCreateAppSource = Extract<CreateAppSource, 'explore_template_list' | 'explore_template_preview' | 'studio_template_list' | 'studio_template_preview'>
|
||||
|
||||
type NonTemplateCreateAppSource = Extract<CreateAppSource, 'studio_blank' | 'studio_upload'>
|
||||
|
||||
type TrackCreateAppParams = { source: TemplateCreateAppSource, templateId: string } | { source: NonTemplateCreateAppSource }
|
||||
type TrackCreateAppParams = {
|
||||
appMode: AppModeEnum
|
||||
}
|
||||
|
||||
type ExternalCreateAppAttribution = {
|
||||
utmSource: typeof EXTERNAL_UTM_SOURCE_MAP[keyof typeof EXTERNAL_UTM_SOURCE_MAP]
|
||||
@ -69,6 +68,22 @@ const mapExternalUtmSource = (value?: string) => {
|
||||
return EXTERNAL_UTM_SOURCE_MAP[normalized as keyof typeof EXTERNAL_UTM_SOURCE_MAP]
|
||||
}
|
||||
|
||||
const padTimeValue = (value: number) => String(value).padStart(2, '0')
|
||||
|
||||
const formatCreateAppTime = (date: Date) => {
|
||||
return `${padTimeValue(date.getMonth() + 1)}-${padTimeValue(date.getDate())}-${padTimeValue(date.getHours())}:${padTimeValue(date.getMinutes())}:${padTimeValue(date.getSeconds())}`
|
||||
}
|
||||
|
||||
const mapOriginalCreateAppMode = (appMode: AppModeEnum): OriginalCreateAppMode => {
|
||||
if (appMode === AppModeEnum.WORKFLOW)
|
||||
return 'workflow'
|
||||
|
||||
if (appMode === AppModeEnum.AGENT_CHAT)
|
||||
return 'agent'
|
||||
|
||||
return 'chatflow'
|
||||
}
|
||||
|
||||
export const extractExternalCreateAppAttribution = ({
|
||||
searchParams,
|
||||
utmInfo,
|
||||
@ -144,6 +159,7 @@ const resolveCurrentExternalCreateAppAttribution = () => {
|
||||
export const buildCreateAppEventPayload = (
|
||||
params: TrackCreateAppParams,
|
||||
externalAttribution?: ExternalCreateAppAttribution | null,
|
||||
currentTime = new Date(),
|
||||
) => {
|
||||
if (externalAttribution) {
|
||||
return {
|
||||
@ -153,15 +169,10 @@ export const buildCreateAppEventPayload = (
|
||||
} satisfies Record<string, string>
|
||||
}
|
||||
|
||||
if ('templateId' in params) {
|
||||
return {
|
||||
source: params.source,
|
||||
template_id: params.templateId,
|
||||
} satisfies Record<string, string>
|
||||
}
|
||||
|
||||
return {
|
||||
source: params.source,
|
||||
source: 'original',
|
||||
app_mode: mapOriginalCreateAppMode(params.appMode),
|
||||
time: formatCreateAppTime(currentTime),
|
||||
} satisfies Record<string, string>
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user