mirror of
https://github.com/langgenius/dify.git
synced 2026-01-31 17:07:01 +08:00
Compare commits
70 Commits
feat/ampli
...
feat/data-
| Author | SHA1 | Date | |
|---|---|---|---|
| dacd480c6f | |||
| d960d3ee3e | |||
| 898e65d645 | |||
| 818966e53f | |||
| e285917e37 | |||
| d18b2c0e82 | |||
| d205b4c10e | |||
| 4bd114a90a | |||
| 84a9ddc2d8 | |||
| e658a6a80d | |||
| 6f93e2f780 | |||
| 37fc386af2 | |||
| 9aa9c87e0d | |||
| 56e9129efb | |||
| 1e2311128c | |||
| 08edf20672 | |||
| 28626590d1 | |||
| 8dc5d98174 | |||
| 9c10731494 | |||
| eaed72a40c | |||
| 168a1524b2 | |||
| 8e01eb4561 | |||
| 96865ebc8c | |||
| 7ca5e8812e | |||
| 201fa723a5 | |||
| 32b5ae3b71 | |||
| f3bfccbd67 | |||
| a4e3a39dd2 | |||
| 9e753b031a | |||
| 15f3d68bc5 | |||
| b9202d1e0a | |||
| a6e9da1d89 | |||
| 125f37b562 | |||
| eea3f14777 | |||
| 0e43f5ad4d | |||
| e3f85c1658 | |||
| 10571fcf7c | |||
| 244bd08db2 | |||
| 73ef99c25a | |||
| d5a30c667b | |||
| 9648020ab4 | |||
| 76be5c054b | |||
| c76f370f97 | |||
| 853f5ff09e | |||
| 2ee55d8bc8 | |||
| 57a7e3c20f | |||
| 3160242fca | |||
| 001e4f8c69 | |||
| 48c95f4ccf | |||
| 1418512f24 | |||
| f834f8a160 | |||
| feaad67531 | |||
| 9592b72aa3 | |||
| 6325ed9cd3 | |||
| ab39f39db0 | |||
| becabd84a9 | |||
| 62de0e97e5 | |||
| aa0fdbf759 | |||
| c3b48cca11 | |||
| 874ee69f2b | |||
| 8f499d9894 | |||
| f16a42ee52 | |||
| 9b43b9f1e9 | |||
| f8e01d7df8 | |||
| ead5a78faa | |||
| fd2ff963a9 | |||
| 7492b39ff0 | |||
| 8b5533e1a4 | |||
| fa7a0fd3d1 | |||
| 2a20a96123 |
@ -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/amplitude'
|
||||
import AmplitudeProvider from '@/app/components/base/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/amplitude'
|
||||
import AmplitudeProvider from '@/app/components/base/amplitude'
|
||||
import HeaderWrapper from '@/app/components/header/header-wrapper'
|
||||
import { EventEmitterContextProvider } from '@/context/event-emitter'
|
||||
import { ProviderContextProvider } from '@/context/provider-context'
|
||||
|
||||
@ -49,7 +49,6 @@ 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]: {
|
||||
@ -183,12 +182,6 @@ 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,6 +28,7 @@ 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
|
||||
@ -141,6 +142,16 @@ 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,6 +30,7 @@ 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
|
||||
@ -82,6 +83,14 @@ 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,6 +28,7 @@ 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
|
||||
@ -112,6 +113,13 @@ 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,7 +42,6 @@ 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
|
||||
@ -780,17 +779,15 @@ function DetailPanel({ detail, onFeedback }: IDetailPanel) {
|
||||
}
|
||||
</div>
|
||||
{showMessageLogModal && (
|
||||
<WorkflowContextProvider>
|
||||
<MessageLogModal
|
||||
width={width}
|
||||
currentLogItem={currentLogItem}
|
||||
onCancel={() => {
|
||||
setCurrentLogItem()
|
||||
setShowMessageLogModal(false)
|
||||
}}
|
||||
defaultTab={currentLogModalActiveTab}
|
||||
/>
|
||||
</WorkflowContextProvider>
|
||||
<MessageLogModal
|
||||
width={width}
|
||||
currentLogItem={currentLogItem}
|
||||
onCancel={() => {
|
||||
setCurrentLogItem()
|
||||
setShowMessageLogModal(false)
|
||||
}}
|
||||
defaultTab={currentLogModalActiveTab}
|
||||
/>
|
||||
)}
|
||||
{!isChatMode && showPromptLogModal && (
|
||||
<PromptLogModal
|
||||
|
||||
@ -8,6 +8,7 @@ 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()
|
||||
@ -37,6 +38,9 @@ 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, RiDiscussLine, RiGithubFill } from '@remixicon/react'
|
||||
import { RiDiscordFill, RiGithubFill } from '@remixicon/react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
|
||||
type CustomLinkProps = {
|
||||
@ -38,9 +38,6 @@ 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>
|
||||
)
|
||||
|
||||
@ -7,11 +7,12 @@ import { sessionReplayPlugin } from '@amplitude/plugin-session-replay-browser'
|
||||
|
||||
export type IAmplitudeProps = {
|
||||
apiKey?: string
|
||||
enableSessionReplay?: boolean
|
||||
sessionReplaySampleRate?: number
|
||||
}
|
||||
|
||||
const AmplitudeProvider: FC<IAmplitudeProps> = ({
|
||||
apiKey = '702e89332ab88a7f14e665f417244e9d',
|
||||
sessionReplaySampleRate = 1,
|
||||
}) => {
|
||||
useEffect(() => {
|
||||
// // Only enable in non-CE edition
|
||||
@ -20,12 +21,7 @@ const AmplitudeProvider: FC<IAmplitudeProps> = ({
|
||||
// return
|
||||
// }
|
||||
|
||||
const sessionReplay = sessionReplayPlugin({
|
||||
sampleRate: 0.1,
|
||||
})
|
||||
|
||||
amplitude.add(sessionReplay)
|
||||
|
||||
// Initialize Amplitude
|
||||
amplitude.init(apiKey, {
|
||||
defaultTracking: {
|
||||
sessions: true,
|
||||
@ -33,10 +29,18 @@ 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
|
||||
}
|
||||
|
||||
@ -6,7 +6,6 @@ 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',
|
||||
@ -144,12 +143,10 @@ const MessageLogPreview = (props: MessageLogModalProps) => {
|
||||
|
||||
return (
|
||||
<div className="relative min-h-[640px] w-full bg-background-default-subtle p-6">
|
||||
<WorkflowContextProvider>
|
||||
<MessageLogModal
|
||||
{...props}
|
||||
currentLogItem={mockCurrentLogItem}
|
||||
/>
|
||||
</WorkflowContextProvider>
|
||||
<MessageLogModal
|
||||
{...props}
|
||||
currentLogItem={mockCurrentLogItem}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@ -5,7 +5,6 @@ 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()
|
||||
@ -23,9 +22,6 @@ const CreateCard = () => {
|
||||
type: 'success',
|
||||
message: t('datasetPipeline.creation.successTip'),
|
||||
})
|
||||
trackEvent('create_datasets_from_scratch', {
|
||||
name: data.name,
|
||||
})
|
||||
invalidDatasetList()
|
||||
push(`/datasets/${id}/pipeline`)
|
||||
}
|
||||
|
||||
@ -19,7 +19,6 @@ 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
|
||||
@ -64,13 +63,6 @@ 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)
|
||||
@ -83,7 +75,7 @@ const TemplateCard = ({
|
||||
})
|
||||
},
|
||||
})
|
||||
}, [getPipelineTemplateInfo, createDataset, t, handleCheckPluginDependencies, push, invalidDatasetList, pipeline, type])
|
||||
}, [getPipelineTemplateInfo, createDataset, t, handleCheckPluginDependencies, push, invalidDatasetList])
|
||||
|
||||
const handleShowTemplateDetails = useCallback(() => {
|
||||
setShowDetailModal(true)
|
||||
|
||||
@ -12,7 +12,6 @@ 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
|
||||
@ -42,9 +41,6 @@ const EmptyDatasetCreationModal = ({
|
||||
const dataset = await createEmptyDataset({ name: inputValue })
|
||||
invalidDatasetList()
|
||||
onHide()
|
||||
trackEvent('create_empty_datasets', {
|
||||
name: inputValue,
|
||||
})
|
||||
router.push(`/datasets/${dataset.id}/documents`)
|
||||
}
|
||||
catch {
|
||||
|
||||
@ -63,7 +63,6 @@ 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>
|
||||
@ -572,12 +571,6 @@ 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,
|
||||
})
|
||||
},
|
||||
},
|
||||
)
|
||||
@ -588,13 +581,6 @@ 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,7 +6,6 @@ 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()
|
||||
@ -18,9 +17,6 @@ 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,7 +44,6 @@ 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'
|
||||
|
||||
@ -200,14 +199,6 @@ 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,7 +30,6 @@ 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
|
||||
@ -78,10 +77,6 @@ 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,7 +9,6 @@ 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
|
||||
@ -54,9 +53,6 @@ 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,7 +11,6 @@ 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}/`))
|
||||
@ -68,13 +67,6 @@ 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,7 +12,6 @@ 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
|
||||
@ -68,11 +67,6 @@ 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,7 +2,6 @@ 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()
|
||||
@ -19,12 +18,6 @@ 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,6 +11,7 @@ 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()
|
||||
@ -43,6 +44,13 @@ 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,6 +12,7 @@ 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
|
||||
@ -63,6 +64,13 @@ 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,7 +42,6 @@ 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,6 +9,7 @@ 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()
|
||||
@ -54,6 +55,12 @@ 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,7 +160,9 @@ 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({
|
||||
@ -169,9 +171,10 @@ export const AppContextProvider: FC<AppContextProviderProps> = ({ children }) =>
|
||||
has_password: userProfile.is_password_set,
|
||||
})
|
||||
}
|
||||
}, [userProfile])
|
||||
}, [userProfile?.id, userProfile?.email, userProfile?.name, userProfile?.is_password_set])
|
||||
|
||||
useEffect(() => {
|
||||
// Report workspace info to Amplitude when loaded
|
||||
if (currentWorkspace?.id && userProfile?.id) {
|
||||
setUserProperties({
|
||||
workspace_id: currentWorkspace.id,
|
||||
@ -181,7 +184,8 @@ export const AppContextProvider: FC<AppContextProviderProps> = ({ children }) =>
|
||||
workspace_role: currentWorkspace.role,
|
||||
})
|
||||
}
|
||||
}, [currentWorkspace])
|
||||
}, [currentWorkspace?.id, currentWorkspace?.name, currentWorkspace?.plan, currentWorkspace?.status, currentWorkspace?.role, userProfile?.id])
|
||||
// #endregion Amplitude user tracking
|
||||
|
||||
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'
|
||||
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 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.30.1",
|
||||
"@amplitude/plugin-session-replay-browser": "^1.23.2",
|
||||
"@amplitude/analytics-browser": "^2.31.3",
|
||||
"@amplitude/plugin-session-replay-browser": "^1.23.6",
|
||||
"@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