mirror of
https://github.com/langgenius/dify.git
synced 2026-02-02 18:06:38 +08:00
Compare commits
68 Commits
feat/data-
...
feat/ampli
| Author | SHA1 | Date | |
|---|---|---|---|
| 3f01c06451 | |||
| 6b95723f1c | |||
| 4a89403566 | |||
| e0c05b2123 | |||
| 85b99580ea | |||
| 15fbedfcad | |||
| 1e6d0de48b | |||
| cad751c00c | |||
| a47276ac24 | |||
| 20403c69b2 | |||
| ffc04f2a9b | |||
| d1580791e4 | |||
| c74eb4fcf3 | |||
| a798534337 | |||
| 470883858e | |||
| 4f4911686d | |||
| 6d479dcdbb | |||
| 24348c40a6 | |||
| a39b50adbb | |||
| 81832c14ee | |||
| b86022c64a | |||
| 45e816a9f6 | |||
| 667b1c37a3 | |||
| b75d533f9b | |||
| aece55d82f | |||
| c432b398f4 | |||
| 9cb2645793 | |||
| 6ac61bd585 | |||
| b02165ffe6 | |||
| 6c576e2c66 | |||
| b0e7e7752f | |||
| 2799b79e8c | |||
| 805a1479f9 | |||
| fe6538b08d | |||
| 1bbb9d6644 | |||
| 5c06e285ec | |||
| 19c92fd670 | |||
| 6026bd873b | |||
| 1369119a0c | |||
| b76e17b25d | |||
| ca7794305b | |||
| fd255e81e1 | |||
| 09d31d1263 | |||
| 47dc26f011 | |||
| 123bb3ec08 | |||
| 90f77282e3 | |||
| 5208867ccc | |||
| edc7ccc795 | |||
| c9798f6425 | |||
| 20ecf7f1d0 | |||
| 9dcb780fcb | |||
| 1cb7b09933 | |||
| 2c62a77cf4 | |||
| b9bc48d8dd | |||
| ed234e311b | |||
| 9843fec393 | |||
| aa4cabdeb5 | |||
| eea713b668 | |||
| fc62538a94 | |||
| 7994144df7 | |||
| e153c483b6 | |||
| 422bb4d4bb | |||
| 87a80d7613 | |||
| e91105ca87 | |||
| 37903722fe | |||
| f4c82d0010 | |||
| fe50093c18 | |||
| 4317af1e90 |
@ -3,7 +3,7 @@ import type { ReactNode } from 'react'
|
||||
import SwrInitializer from '@/app/components/swr-initializer'
|
||||
import { AppContextProvider } from '@/context/app-context'
|
||||
import GA, { GaType } from '@/app/components/base/ga'
|
||||
import AmplitudeProvider from '@/app/components/base/amplitude'
|
||||
import AmplitudeProvider from '@/app/components/amplitude'
|
||||
import HeaderWrapper from '@/app/components/header/header-wrapper'
|
||||
import Header from '@/app/components/header'
|
||||
import { EventEmitterContextProvider } from '@/context/event-emitter'
|
||||
|
||||
@ -4,7 +4,7 @@ import Header from './header'
|
||||
import SwrInitor from '@/app/components/swr-initializer'
|
||||
import { AppContextProvider } from '@/context/app-context'
|
||||
import GA, { GaType } from '@/app/components/base/ga'
|
||||
import AmplitudeProvider from '@/app/components/base/amplitude'
|
||||
import AmplitudeProvider from '@/app/components/amplitude'
|
||||
import HeaderWrapper from '@/app/components/header/header-wrapper'
|
||||
import { EventEmitterContextProvider } from '@/context/event-emitter'
|
||||
import { ProviderContextProvider } from '@/context/provider-context'
|
||||
|
||||
@ -7,12 +7,11 @@ import { sessionReplayPlugin } from '@amplitude/plugin-session-replay-browser'
|
||||
|
||||
export type IAmplitudeProps = {
|
||||
apiKey?: string
|
||||
sessionReplaySampleRate?: number
|
||||
enableSessionReplay?: boolean
|
||||
}
|
||||
|
||||
const AmplitudeProvider: FC<IAmplitudeProps> = ({
|
||||
apiKey = '702e89332ab88a7f14e665f417244e9d',
|
||||
sessionReplaySampleRate = 1,
|
||||
}) => {
|
||||
useEffect(() => {
|
||||
// // Only enable in non-CE edition
|
||||
@ -21,7 +20,12 @@ const AmplitudeProvider: FC<IAmplitudeProps> = ({
|
||||
// return
|
||||
// }
|
||||
|
||||
// Initialize Amplitude
|
||||
const sessionReplay = sessionReplayPlugin({
|
||||
sampleRate: 0.1,
|
||||
})
|
||||
|
||||
amplitude.add(sessionReplay)
|
||||
|
||||
amplitude.init(apiKey, {
|
||||
defaultTracking: {
|
||||
sessions: true,
|
||||
@ -29,18 +33,10 @@ const AmplitudeProvider: FC<IAmplitudeProps> = ({
|
||||
formInteractions: true,
|
||||
fileDownloads: true,
|
||||
},
|
||||
// Enable debug logs in development environment
|
||||
logLevel: amplitude.Types.LogLevel.Warn,
|
||||
})
|
||||
}, [apiKey])
|
||||
|
||||
// Add Session Replay plugin
|
||||
const sessionReplay = sessionReplayPlugin({
|
||||
sampleRate: sessionReplaySampleRate,
|
||||
})
|
||||
amplitude.add(sessionReplay)
|
||||
}, [apiKey, sessionReplaySampleRate])
|
||||
|
||||
// This is a client component that renders nothing
|
||||
return null
|
||||
}
|
||||
|
||||
@ -49,6 +49,7 @@ import { fetchInstalledAppList } from '@/service/explore'
|
||||
import { AppModeEnum } from '@/types/app'
|
||||
import type { PublishWorkflowParams } from '@/types/workflow'
|
||||
import { basePath } from '@/utils/var'
|
||||
import { trackEvent } from '../../amplitude'
|
||||
|
||||
const ACCESS_MODE_MAP: Record<AccessMode, { label: string, icon: React.ElementType }> = {
|
||||
[AccessMode.ORGANIZATION]: {
|
||||
@ -182,6 +183,12 @@ const AppPublisher = ({
|
||||
try {
|
||||
await onPublish?.(params)
|
||||
setPublished(true)
|
||||
trackEvent('app·_published_time', {
|
||||
app_mode: appDetail?.mode,
|
||||
app_id: appDetail?.id,
|
||||
app_name: appDetail?.name,
|
||||
time: new Date().toLocaleString('zh-CN', { timeZone: 'Asia/Shanghai' }),
|
||||
})
|
||||
}
|
||||
catch {
|
||||
setPublished(false)
|
||||
|
||||
@ -28,7 +28,6 @@ import Input from '@/app/components/base/input'
|
||||
import { AppModeEnum } from '@/types/app'
|
||||
import { DSLImportMode } from '@/models/app'
|
||||
import { usePluginDependencies } from '@/app/components/workflow/plugin-dependency/hooks'
|
||||
import { trackEvent } from '@/app/components/base/amplitude'
|
||||
|
||||
type AppsProps = {
|
||||
onSuccess?: () => void
|
||||
@ -142,16 +141,6 @@ const Apps = ({
|
||||
icon_background,
|
||||
description,
|
||||
})
|
||||
|
||||
// Track app creation from template
|
||||
trackEvent('create_app_with_template', {
|
||||
app_mode: mode,
|
||||
template_id: currApp?.app.id,
|
||||
template_name: currApp?.app.name,
|
||||
time: new Date().toLocaleString('zh-CN', { timeZone: 'Asia/Shanghai' }),
|
||||
has_description: description,
|
||||
})
|
||||
|
||||
setIsShowCreateModal(false)
|
||||
Toast.notify({
|
||||
type: 'success',
|
||||
|
||||
@ -30,7 +30,6 @@ import { getRedirection } from '@/utils/app-redirection'
|
||||
import FullScreenModal from '@/app/components/base/fullscreen-modal'
|
||||
import useTheme from '@/hooks/use-theme'
|
||||
import { useDocLink } from '@/context/i18n'
|
||||
import { trackEvent } from '@/app/components/base/amplitude'
|
||||
|
||||
type CreateAppProps = {
|
||||
onSuccess: () => void
|
||||
@ -83,14 +82,6 @@ function CreateApp({ onClose, onSuccess, onCreateFromTemplate, defaultAppMode }:
|
||||
icon_background: appIcon.type === 'emoji' ? appIcon.background : undefined,
|
||||
mode: appMode,
|
||||
})
|
||||
|
||||
// Track app creation success
|
||||
trackEvent('create_app', {
|
||||
app_mode: appMode,
|
||||
time: new Date().toLocaleString('zh-CN', { timeZone: 'Asia/Shanghai' }),
|
||||
description,
|
||||
})
|
||||
|
||||
notify({ type: 'success', message: t('app.newApp.appCreated') })
|
||||
onSuccess()
|
||||
onClose()
|
||||
|
||||
@ -28,7 +28,6 @@ import { getRedirection } from '@/utils/app-redirection'
|
||||
import cn from '@/utils/classnames'
|
||||
import { usePluginDependencies } from '@/app/components/workflow/plugin-dependency/hooks'
|
||||
import { noop } from 'lodash-es'
|
||||
import { trackEvent } from '@/app/components/base/amplitude'
|
||||
|
||||
type CreateFromDSLModalProps = {
|
||||
show: boolean
|
||||
@ -113,13 +112,6 @@ 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) {
|
||||
// Track app creation from DSL import
|
||||
trackEvent('create_app_with_dsl', {
|
||||
app_mode,
|
||||
creation_method: currentTab === CreateFromDSLModalTab.FROM_FILE ? 'dsl_file' : 'dsl_url',
|
||||
has_warnings: status === DSLImportStatus.COMPLETED_WITH_WARNINGS,
|
||||
})
|
||||
|
||||
if (onSuccess)
|
||||
onSuccess()
|
||||
if (onClose)
|
||||
|
||||
@ -42,6 +42,7 @@ import { getProcessedFilesFromResponse } from '@/app/components/base/file-upload
|
||||
import cn from '@/utils/classnames'
|
||||
import { noop } from 'lodash-es'
|
||||
import PromptLogModal from '../../base/prompt-log-modal'
|
||||
import { WorkflowContextProvider } from '@/app/components/workflow/context'
|
||||
|
||||
type AppStoreState = ReturnType<typeof useAppStore.getState>
|
||||
type ConversationListItem = ChatConversationGeneralDetail | CompletionConversationGeneralDetail
|
||||
@ -779,15 +780,17 @@ function DetailPanel({ detail, onFeedback }: IDetailPanel) {
|
||||
}
|
||||
</div>
|
||||
{showMessageLogModal && (
|
||||
<MessageLogModal
|
||||
width={width}
|
||||
currentLogItem={currentLogItem}
|
||||
onCancel={() => {
|
||||
setCurrentLogItem()
|
||||
setShowMessageLogModal(false)
|
||||
}}
|
||||
defaultTab={currentLogModalActiveTab}
|
||||
/>
|
||||
<WorkflowContextProvider>
|
||||
<MessageLogModal
|
||||
width={width}
|
||||
currentLogItem={currentLogItem}
|
||||
onCancel={() => {
|
||||
setCurrentLogItem()
|
||||
setShowMessageLogModal(false)
|
||||
}}
|
||||
defaultTab={currentLogModalActiveTab}
|
||||
/>
|
||||
</WorkflowContextProvider>
|
||||
)}
|
||||
{!isChatMode && showPromptLogModal && (
|
||||
<PromptLogModal
|
||||
|
||||
@ -8,7 +8,6 @@ import quarterOfYear from 'dayjs/plugin/quarterOfYear'
|
||||
import type { QueryParam } from './index'
|
||||
import Chip from '@/app/components/base/chip'
|
||||
import Input from '@/app/components/base/input'
|
||||
import { trackEvent } from '../../base/amplitude/utils'
|
||||
dayjs.extend(quarterOfYear)
|
||||
|
||||
const today = dayjs()
|
||||
@ -38,9 +37,6 @@ const Filter: FC<IFilterProps> = ({ queryParams, setQueryParams }: IFilterProps)
|
||||
value={queryParams.status || 'all'}
|
||||
onSelect={(item) => {
|
||||
setQueryParams({ ...queryParams, status: item.value as string })
|
||||
trackEvent('workflow_log_filter_status_selected', {
|
||||
workflow_log_filter_status: item.value as string,
|
||||
})
|
||||
}}
|
||||
onClear={() => setQueryParams({ ...queryParams, status: 'all' })}
|
||||
items={[{ value: 'all', name: 'All' },
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import React from 'react'
|
||||
import Link from 'next/link'
|
||||
import { RiDiscordFill, RiGithubFill } from '@remixicon/react'
|
||||
import { RiDiscordFill, RiDiscussLine, RiGithubFill } from '@remixicon/react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
|
||||
type CustomLinkProps = {
|
||||
@ -38,6 +38,9 @@ const Footer = () => {
|
||||
<CustomLink href='https://discord.gg/FngNHpbcY7'>
|
||||
<RiDiscordFill className='h-5 w-5 text-text-tertiary' />
|
||||
</CustomLink>
|
||||
<CustomLink href='https://forum.dify.ai'>
|
||||
<RiDiscussLine className='h-5 w-5 text-text-tertiary' />
|
||||
</CustomLink>
|
||||
</div>
|
||||
</footer>
|
||||
)
|
||||
|
||||
@ -6,6 +6,7 @@ import { useStore } from '@/app/components/app/store'
|
||||
import type { WorkflowRunDetailResponse } from '@/models/log'
|
||||
import type { NodeTracing, NodeTracingListResponse } from '@/types/workflow'
|
||||
import { BlockEnum } from '@/app/components/workflow/types'
|
||||
import { WorkflowContextProvider } from '@/app/components/workflow/context'
|
||||
|
||||
const SAMPLE_APP_DETAIL = {
|
||||
id: 'app-demo-1',
|
||||
@ -143,10 +144,12 @@ const MessageLogPreview = (props: MessageLogModalProps) => {
|
||||
|
||||
return (
|
||||
<div className="relative min-h-[640px] w-full bg-background-default-subtle p-6">
|
||||
<MessageLogModal
|
||||
{...props}
|
||||
currentLogItem={mockCurrentLogItem}
|
||||
/>
|
||||
<WorkflowContextProvider>
|
||||
<MessageLogModal
|
||||
{...props}
|
||||
currentLogItem={mockCurrentLogItem}
|
||||
/>
|
||||
</WorkflowContextProvider>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@ -5,6 +5,7 @@ import { useCreatePipelineDataset } from '@/service/knowledge/use-create-dataset
|
||||
import { useInvalidDatasetList } from '@/service/knowledge/use-dataset'
|
||||
import Toast from '@/app/components/base/toast'
|
||||
import { useRouter } from 'next/navigation'
|
||||
import { trackEvent } from '@/app/components/amplitude'
|
||||
|
||||
const CreateCard = () => {
|
||||
const { t } = useTranslation()
|
||||
@ -22,6 +23,9 @@ const CreateCard = () => {
|
||||
type: 'success',
|
||||
message: t('datasetPipeline.creation.successTip'),
|
||||
})
|
||||
trackEvent('create_datasets_from_scratch', {
|
||||
name: data.name,
|
||||
})
|
||||
invalidDatasetList()
|
||||
push(`/datasets/${id}/pipeline`)
|
||||
}
|
||||
|
||||
@ -19,6 +19,7 @@ import Content from './content'
|
||||
import Actions from './actions'
|
||||
import { useCreatePipelineDatasetFromCustomized } from '@/service/knowledge/use-create-dataset'
|
||||
import { useInvalidDatasetList } from '@/service/knowledge/use-dataset'
|
||||
import { trackEvent } from '@/app/components/amplitude'
|
||||
|
||||
type TemplateCardProps = {
|
||||
pipeline: PipelineTemplate
|
||||
@ -63,6 +64,13 @@ const TemplateCard = ({
|
||||
type: 'success',
|
||||
message: t('datasetPipeline.creation.successTip'),
|
||||
})
|
||||
|
||||
trackEvent('create_datasets_with_pipeline', {
|
||||
template_type: type,
|
||||
template_name: pipeline.name,
|
||||
chunk_structure: pipeline.chunk_structure,
|
||||
})
|
||||
|
||||
invalidDatasetList()
|
||||
if (newDataset.pipeline_id)
|
||||
await handleCheckPluginDependencies(newDataset.pipeline_id, true)
|
||||
@ -75,7 +83,7 @@ const TemplateCard = ({
|
||||
})
|
||||
},
|
||||
})
|
||||
}, [getPipelineTemplateInfo, createDataset, t, handleCheckPluginDependencies, push, invalidDatasetList])
|
||||
}, [getPipelineTemplateInfo, createDataset, t, handleCheckPluginDependencies, push, invalidDatasetList, pipeline, type])
|
||||
|
||||
const handleShowTemplateDetails = useCallback(() => {
|
||||
setShowDetailModal(true)
|
||||
|
||||
@ -12,6 +12,7 @@ import Button from '@/app/components/base/button'
|
||||
import { ToastContext } from '@/app/components/base/toast'
|
||||
import { createEmptyDataset } from '@/service/datasets'
|
||||
import { useInvalidDatasetList } from '@/service/knowledge/use-dataset'
|
||||
import { trackEvent } from '@/app/components/amplitude'
|
||||
|
||||
type IProps = {
|
||||
show: boolean
|
||||
@ -41,6 +42,9 @@ const EmptyDatasetCreationModal = ({
|
||||
const dataset = await createEmptyDataset({ name: inputValue })
|
||||
invalidDatasetList()
|
||||
onHide()
|
||||
trackEvent('create_empty_datasets', {
|
||||
name: inputValue,
|
||||
})
|
||||
router.push(`/datasets/${dataset.id}/documents`)
|
||||
}
|
||||
catch {
|
||||
|
||||
@ -63,6 +63,7 @@ import { AlertTriangle } from '@/app/components/base/icons/src/vender/solid/aler
|
||||
import { noop } from 'lodash-es'
|
||||
import { useDocLink } from '@/context/i18n'
|
||||
import { useInvalidDatasetList } from '@/service/knowledge/use-dataset'
|
||||
import { trackEvent } from '@/app/components/amplitude'
|
||||
|
||||
const TextLabel: FC<PropsWithChildren> = (props) => {
|
||||
return <label className='system-sm-semibold text-text-secondary'>{props.children}</label>
|
||||
@ -571,6 +572,12 @@ const StepTwo = ({
|
||||
updateIndexingTypeCache?.(indexType as string)
|
||||
updateResultCache?.(data)
|
||||
updateRetrievalMethodCache?.(retrievalConfig.search_method as string)
|
||||
|
||||
trackEvent('create_datasets', {
|
||||
data_source_type: dataSourceType,
|
||||
indexing_technique: indexType,
|
||||
doc_form: currentDocForm,
|
||||
})
|
||||
},
|
||||
},
|
||||
)
|
||||
@ -581,6 +588,13 @@ const StepTwo = ({
|
||||
updateIndexingTypeCache?.(indexType as string)
|
||||
updateResultCache?.(data)
|
||||
updateRetrievalMethodCache?.(retrievalConfig.search_method as string)
|
||||
|
||||
// Track document addition to existing dataset
|
||||
trackEvent('dataset_document_added', {
|
||||
data_source_type: dataSourceType,
|
||||
indexing_technique: indexType,
|
||||
doc_form: currentDocForm,
|
||||
})
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
@ -6,6 +6,7 @@ import { useToastContext } from '@/app/components/base/toast'
|
||||
import ExternalKnowledgeBaseCreate from '@/app/components/datasets/external-knowledge-base/create'
|
||||
import type { CreateKnowledgeBaseReq } from '@/app/components/datasets/external-knowledge-base/create/declarations'
|
||||
import { createExternalKnowledgeBase } from '@/service/datasets'
|
||||
import { trackEvent } from '@/app/components/amplitude'
|
||||
|
||||
const ExternalKnowledgeBaseConnector = () => {
|
||||
const { notify } = useToastContext()
|
||||
@ -17,6 +18,9 @@ const ExternalKnowledgeBaseConnector = () => {
|
||||
setLoading(true)
|
||||
const result = await createExternalKnowledgeBase({ body: formValue })
|
||||
if (result && result.id) {
|
||||
trackEvent('create_external_knowledge_base', {
|
||||
value: formValue,
|
||||
})
|
||||
notify({ type: 'success', message: 'External Knowledge Base Connected Successfully' })
|
||||
router.back()
|
||||
}
|
||||
|
||||
@ -44,6 +44,7 @@ import { AUTO_UPDATE_MODE } from '../reference-setting-modal/auto-update-setting
|
||||
import { convertUTCDaySecondsToLocalSeconds, timeOfDayToDayjs } from '../reference-setting-modal/auto-update-setting/utils'
|
||||
import type { PluginDetail } from '../types'
|
||||
import { PluginCategoryEnum, PluginSource } from '../types'
|
||||
import { trackEvent } from '../../amplitude'
|
||||
|
||||
const i18nPrefix = 'plugin.action'
|
||||
|
||||
@ -199,6 +200,14 @@ const DetailHeader = ({
|
||||
const handleDelete = useCallback(async () => {
|
||||
showDeleting()
|
||||
const res = await uninstallPlugin(id)
|
||||
|
||||
trackEvent('plugin_deleted', {
|
||||
plugin_id: id,
|
||||
plugin_name: label[locale],
|
||||
plugin_category: category,
|
||||
plugin_source: source,
|
||||
plugin_version: version,
|
||||
})
|
||||
hideDeleting()
|
||||
if (res.success) {
|
||||
hideDeleteConfirm()
|
||||
|
||||
@ -30,6 +30,7 @@ import { useCategories } from '../hooks'
|
||||
import { usePluginPageContext } from '../plugin-page/context'
|
||||
import { PluginCategoryEnum, type PluginDetail, PluginSource } from '../types'
|
||||
import Action from './action'
|
||||
import { trackEvent } from '../../amplitude'
|
||||
|
||||
type Props = {
|
||||
className?: string
|
||||
@ -77,6 +78,10 @@ const PluginItem: FC<Props> = ({
|
||||
}, [status, deprecated_reason])
|
||||
|
||||
const handleDelete = useCallback(() => {
|
||||
trackEvent('plugin_deleted', {
|
||||
plugin_id,
|
||||
plugin_name: name,
|
||||
})
|
||||
refreshPluginList({ category } as any)
|
||||
}, [category, refreshPluginList])
|
||||
|
||||
|
||||
@ -9,6 +9,7 @@ import { getKeyboardKeyNameBySystem } from '@/app/components/workflow/utils'
|
||||
import cn from '@/utils/classnames'
|
||||
import { RiCloseLine, RiDatabase2Line, RiLoader2Line, RiPlayLargeLine } from '@remixicon/react'
|
||||
import { StopCircle } from '@/app/components/base/icons/src/vender/line/mediaAndDevices'
|
||||
import { trackEvent } from '@/app/components/amplitude'
|
||||
|
||||
type RunModeProps = {
|
||||
text?: string
|
||||
@ -53,6 +54,9 @@ const RunMode = ({
|
||||
isDisabled ? 'rounded-l-md' : 'rounded-md',
|
||||
)}
|
||||
onClick={() => {
|
||||
trackEvent('pipeline_start_action_time', {
|
||||
time: new Date().toLocaleString('zh-CN', { timeZone: 'Asia/Shanghai' }),
|
||||
})
|
||||
handleWorkflowStartRunInWorkflow()
|
||||
}}
|
||||
disabled={isDisabled}
|
||||
|
||||
@ -11,6 +11,7 @@ import BlockIcon from '../../block-icon'
|
||||
import cn from '@/utils/classnames'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { basePath } from '@/utils/var'
|
||||
import { trackEvent } from '@/app/components/amplitude'
|
||||
|
||||
const normalizeProviderIcon = (icon: ToolWithProvider['icon']) => {
|
||||
if (typeof icon === 'string' && basePath && icon.startsWith('/') && !icon.startsWith(`${basePath}/`))
|
||||
@ -67,6 +68,13 @@ const ToolItem: FC<Props> = ({
|
||||
params[item.name] = ''
|
||||
})
|
||||
}
|
||||
trackEvent('tool_selected', {
|
||||
tool_name: payload.name,
|
||||
tool_parameters: payload.parameters,
|
||||
tool_params: params,
|
||||
plugin_id: provider.plugin_id,
|
||||
plugin_unique_identifier: provider.plugin_unique_identifier,
|
||||
})
|
||||
onSelect(BlockEnum.Tool, {
|
||||
provider_id: provider.id,
|
||||
provider_type: provider.type,
|
||||
|
||||
@ -12,6 +12,7 @@ import { StopCircle } from '@/app/components/base/icons/src/vender/line/mediaAnd
|
||||
import { useDynamicTestRunOptions } from '../hooks/use-dynamic-test-run-options'
|
||||
import TestRunMenu, { type TestRunMenuRef, type TriggerOption, TriggerType } from './test-run-menu'
|
||||
import { useToastContext } from '@/app/components/base/toast'
|
||||
import { trackEvent } from '../../amplitude'
|
||||
|
||||
type RunModeProps = {
|
||||
text?: string
|
||||
@ -67,6 +68,11 @@ const RunMode = ({
|
||||
return
|
||||
}
|
||||
|
||||
trackEvent('app_start_action_time', {
|
||||
time: new Date().toLocaleString('zh-CN', { timeZone: 'Asia/Shanghai' }),
|
||||
action_type: option.type,
|
||||
})
|
||||
|
||||
if (option.type === TriggerType.UserInput) {
|
||||
handleWorkflowStartRunInWorkflow()
|
||||
}
|
||||
|
||||
@ -2,6 +2,7 @@ import { useCallback } from 'react'
|
||||
import { produce } from 'immer'
|
||||
import { useWorkflowStore } from '@/app/components/workflow/store'
|
||||
import { WorkflowRunningStatus } from '@/app/components/workflow/types'
|
||||
import { trackEvent } from '@/app/components/amplitude'
|
||||
|
||||
export const useWorkflowFailed = () => {
|
||||
const workflowStore = useWorkflowStore()
|
||||
@ -18,6 +19,12 @@ export const useWorkflowFailed = () => {
|
||||
status: WorkflowRunningStatus.Failed,
|
||||
}
|
||||
}))
|
||||
|
||||
trackEvent('workflow_run_failed', {
|
||||
workflow_id: workflowRunningData?.task_id,
|
||||
error: workflowRunningData?.result.error,
|
||||
data: workflowRunningData?.result,
|
||||
})
|
||||
}, [workflowStore])
|
||||
|
||||
return {
|
||||
|
||||
@ -11,7 +11,6 @@ import Toast from '@/app/components/base/toast'
|
||||
import { emailLoginWithCode, sendEMailLoginCode } from '@/service/common'
|
||||
import I18NContext from '@/context/i18n'
|
||||
import { resolvePostLoginRedirect } from '../utils/post-login-redirect'
|
||||
import { trackEvent } from '@/app/components/base/amplitude'
|
||||
|
||||
export default function CheckCode() {
|
||||
const { t, i18n } = useTranslation()
|
||||
@ -44,13 +43,6 @@ export default function CheckCode() {
|
||||
setIsLoading(true)
|
||||
const ret = await emailLoginWithCode({ email, code, token, language })
|
||||
if (ret.result === 'success') {
|
||||
// Track login success event
|
||||
trackEvent('user_login_success', {
|
||||
method: 'email_code',
|
||||
time: new Date().toLocaleString('zh-CN', { timeZone: 'Asia/Shanghai' }),
|
||||
is_invite: !!invite_token,
|
||||
})
|
||||
|
||||
if (invite_token) {
|
||||
router.replace(`/signin/invite-settings?${searchParams.toString()}`)
|
||||
}
|
||||
|
||||
@ -12,7 +12,6 @@ import I18NContext from '@/context/i18n'
|
||||
import { noop } from 'lodash-es'
|
||||
import { resolvePostLoginRedirect } from '../utils/post-login-redirect'
|
||||
import type { ResponseError } from '@/service/fetch'
|
||||
import { trackEvent } from '@/app/components/base/amplitude'
|
||||
|
||||
type MailAndPasswordAuthProps = {
|
||||
isInvite: boolean
|
||||
@ -64,13 +63,6 @@ export default function MailAndPasswordAuth({ isInvite, isEmailSetup, allowRegis
|
||||
body: loginData,
|
||||
})
|
||||
if (res.result === 'success') {
|
||||
// Track login success event
|
||||
trackEvent('user_login_success', {
|
||||
method: 'email_password',
|
||||
time: new Date().toLocaleString('zh-CN', { timeZone: 'Asia/Shanghai' }),
|
||||
is_invite: isInvite,
|
||||
})
|
||||
|
||||
if (isInvite) {
|
||||
router.replace(`/signin/invite-settings?${searchParams.toString()}`)
|
||||
}
|
||||
|
||||
@ -42,6 +42,7 @@ export default function CheckCode() {
|
||||
}
|
||||
setIsLoading(true)
|
||||
const res = await verifyCode({ email, code, token })
|
||||
console.log(res)
|
||||
if ((res as MailValidityResponse).is_valid) {
|
||||
const params = new URLSearchParams(searchParams)
|
||||
params.set('token', encodeURIComponent((res as MailValidityResponse).token))
|
||||
|
||||
@ -9,7 +9,6 @@ import Input from '@/app/components/base/input'
|
||||
import { validPassword } from '@/config'
|
||||
import type { MailRegisterResponse } from '@/service/use-common'
|
||||
import { useMailRegister } from '@/service/use-common'
|
||||
import { trackEvent } from '@/app/components/base/amplitude'
|
||||
|
||||
const ChangePasswordForm = () => {
|
||||
const { t } = useTranslation()
|
||||
@ -55,12 +54,6 @@ const ChangePasswordForm = () => {
|
||||
})
|
||||
const { result } = res as MailRegisterResponse
|
||||
if (result === 'success') {
|
||||
// Track registration success event
|
||||
trackEvent('user_registration_success', {
|
||||
method: 'email',
|
||||
time: new Date().toLocaleString('zh-CN', { timeZone: 'Asia/Shanghai' }),
|
||||
})
|
||||
|
||||
Toast.notify({
|
||||
type: 'success',
|
||||
message: t('common.api.actionSuccess'),
|
||||
|
||||
@ -10,8 +10,8 @@ import MaintenanceNotice from '@/app/components/header/maintenance-notice'
|
||||
import { noop } from 'lodash-es'
|
||||
import { setZendeskConversationFields } from '@/app/components/base/zendesk/utils'
|
||||
import { ZENDESK_FIELD_IDS } from '@/config'
|
||||
import { setUserId, setUserProperties } from '@/app/components/base/amplitude'
|
||||
import { useGlobalPublicStore } from './global-public-context'
|
||||
import { setUserId, setUserProperties } from '@/app/components/amplitude'
|
||||
|
||||
export type AppContextValue = {
|
||||
userProfile: UserProfileResponse
|
||||
@ -160,9 +160,7 @@ export const AppContextProvider: FC<AppContextProviderProps> = ({ children }) =>
|
||||
}, [currentWorkspace?.id])
|
||||
// #endregion Zendesk conversation fields
|
||||
|
||||
// #region Amplitude user tracking
|
||||
useEffect(() => {
|
||||
// Report user info to Amplitude when loaded
|
||||
if (userProfile?.id) {
|
||||
setUserId(userProfile.email)
|
||||
setUserProperties({
|
||||
@ -171,10 +169,9 @@ export const AppContextProvider: FC<AppContextProviderProps> = ({ children }) =>
|
||||
has_password: userProfile.is_password_set,
|
||||
})
|
||||
}
|
||||
}, [userProfile?.id, userProfile?.email, userProfile?.name, userProfile?.is_password_set])
|
||||
}, [userProfile])
|
||||
|
||||
useEffect(() => {
|
||||
// Report workspace info to Amplitude when loaded
|
||||
if (currentWorkspace?.id && userProfile?.id) {
|
||||
setUserProperties({
|
||||
workspace_id: currentWorkspace.id,
|
||||
@ -184,8 +181,7 @@ export const AppContextProvider: FC<AppContextProviderProps> = ({ children }) =>
|
||||
workspace_role: currentWorkspace.role,
|
||||
})
|
||||
}
|
||||
}, [currentWorkspace?.id, currentWorkspace?.name, currentWorkspace?.plan, currentWorkspace?.status, currentWorkspace?.role, userProfile?.id])
|
||||
// #endregion Amplitude user tracking
|
||||
}, [currentWorkspace])
|
||||
|
||||
return (
|
||||
<AppContext.Provider value={{
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import type { NextRequest } from 'next/server'
|
||||
import { NextResponse } from 'next/server'
|
||||
|
||||
const NECESSARY_DOMAIN = '*.sentry.io http://localhost:* http://127.0.0.1:* https://analytics.google.com googletagmanager.com *.googletagmanager.com https://www.google-analytics.com https://api.github.com https://api2.amplitude.com *.amplitude.com'
|
||||
const NECESSARY_DOMAIN = '*.sentry.io http://localhost:* http://127.0.0.1:* https://analytics.google.com googletagmanager.com *.googletagmanager.com https://www.google-analytics.com https://api.github.com'
|
||||
|
||||
const wrapResponseWithXFrameOptions = (response: NextResponse, pathname: string) => {
|
||||
// prevent clickjacking: https://owasp.org/www-community/attacks/Clickjacking
|
||||
|
||||
@ -44,8 +44,8 @@
|
||||
"knip": "knip"
|
||||
},
|
||||
"dependencies": {
|
||||
"@amplitude/analytics-browser": "^2.31.3",
|
||||
"@amplitude/plugin-session-replay-browser": "^1.23.6",
|
||||
"@amplitude/analytics-browser": "^2.30.1",
|
||||
"@amplitude/plugin-session-replay-browser": "^1.23.2",
|
||||
"@emoji-mart/data": "^1.2.1",
|
||||
"@floating-ui/react": "^0.26.28",
|
||||
"@formatjs/intl-localematcher": "^0.5.10",
|
||||
|
||||
1075
web/pnpm-lock.yaml
generated
1075
web/pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user