diff --git a/api/core/tools/workflow_as_tool/provider.py b/api/core/tools/workflow_as_tool/provider.py
index 2bd973f831..5422f5250b 100644
--- a/api/core/tools/workflow_as_tool/provider.py
+++ b/api/core/tools/workflow_as_tool/provider.py
@@ -54,7 +54,6 @@ class WorkflowToolProviderController(ToolProviderController):
raise ValueError("app not found")
user = session.get(Account, db_provider.user_id) if db_provider.user_id else None
-
controller = WorkflowToolProviderController(
entity=ToolProviderEntity(
identity=ToolProviderIdentity(
@@ -67,7 +66,7 @@ class WorkflowToolProviderController(ToolProviderController):
credentials_schema=[],
plugin_id=None,
),
- provider_id="",
+ provider_id=db_provider.id,
)
controller.tools = [
diff --git a/web/__tests__/workflow-parallel-limit.test.tsx b/web/__tests__/workflow-parallel-limit.test.tsx
index 18657f4bd2..ba3840ac3e 100644
--- a/web/__tests__/workflow-parallel-limit.test.tsx
+++ b/web/__tests__/workflow-parallel-limit.test.tsx
@@ -64,7 +64,6 @@ vi.mock('i18next', () => ({
// Mock the useConfig hook
vi.mock('@/app/components/workflow/nodes/iteration/use-config', () => ({
- __esModule: true,
default: () => ({
inputs: {
is_parallel: true,
diff --git a/web/app/components/app-initializer.tsx b/web/app/components/app-initializer.tsx
index 0f710abf39..e30646eb3f 100644
--- a/web/app/components/app-initializer.tsx
+++ b/web/app/components/app-initializer.tsx
@@ -1,14 +1,18 @@
'use client'
import type { ReactNode } from 'react'
+import Cookies from 'js-cookie'
import { usePathname, useRouter, useSearchParams } from 'next/navigation'
+import { parseAsString, useQueryState } from 'nuqs'
import { useCallback, useEffect, useState } from 'react'
import {
EDUCATION_VERIFY_URL_SEARCHPARAMS_ACTION,
EDUCATION_VERIFYING_LOCALSTORAGE_ITEM,
} from '@/app/education-apply/constants'
import { fetchSetupStatus } from '@/service/common'
+import { sendGAEvent } from '@/utils/gtag'
import { resolvePostLoginRedirect } from '../signin/utils/post-login-redirect'
+import { trackEvent } from './base/amplitude'
type AppInitializerProps = {
children: ReactNode
@@ -22,6 +26,10 @@ export const AppInitializer = ({
// Tokens are now stored in cookies, no need to check localStorage
const pathname = usePathname()
const [init, setInit] = useState(false)
+ const [oauthNewUser, setOauthNewUser] = useQueryState(
+ 'oauth_new_user',
+ parseAsString.withOptions({ history: 'replace' }),
+ )
const isSetupFinished = useCallback(async () => {
try {
@@ -45,6 +53,34 @@ export const AppInitializer = ({
(async () => {
const action = searchParams.get('action')
+ if (oauthNewUser === 'true') {
+ let utmInfo = null
+ const utmInfoStr = Cookies.get('utm_info')
+ if (utmInfoStr) {
+ try {
+ utmInfo = JSON.parse(utmInfoStr)
+ }
+ catch (e) {
+ console.error('Failed to parse utm_info cookie:', e)
+ }
+ }
+
+ // Track registration event with UTM params
+ trackEvent(utmInfo ? 'user_registration_success_with_utm' : 'user_registration_success', {
+ method: 'oauth',
+ ...utmInfo,
+ })
+
+ sendGAEvent(utmInfo ? 'user_registration_success_with_utm' : 'user_registration_success', {
+ method: 'oauth',
+ ...utmInfo,
+ })
+
+ // Clean up: remove utm_info cookie and URL params
+ Cookies.remove('utm_info')
+ setOauthNewUser(null)
+ }
+
if (action === EDUCATION_VERIFY_URL_SEARCHPARAMS_ACTION)
localStorage.setItem(EDUCATION_VERIFYING_LOCALSTORAGE_ITEM, 'yes')
@@ -67,7 +103,7 @@ export const AppInitializer = ({
router.replace('/signin')
}
})()
- }, [isSetupFinished, router, pathname, searchParams])
+ }, [isSetupFinished, router, pathname, searchParams, oauthNewUser, setOauthNewUser])
return init ? children : null
}
diff --git a/web/app/components/app-sidebar/dataset-info/index.spec.tsx b/web/app/components/app-sidebar/dataset-info/index.spec.tsx
index da7eb6d7ff..9996ef2b4d 100644
--- a/web/app/components/app-sidebar/dataset-info/index.spec.tsx
+++ b/web/app/components/app-sidebar/dataset-info/index.spec.tsx
@@ -132,7 +132,6 @@ vi.mock('@/hooks/use-knowledge', () => ({
}))
vi.mock('@/app/components/datasets/rename-modal', () => ({
- __esModule: true,
default: ({
show,
onClose,
diff --git a/web/app/components/app-sidebar/text-squeeze-fix-verification.spec.tsx b/web/app/components/app-sidebar/text-squeeze-fix-verification.spec.tsx
index 7c0c8b3aca..f7e91b3dea 100644
--- a/web/app/components/app-sidebar/text-squeeze-fix-verification.spec.tsx
+++ b/web/app/components/app-sidebar/text-squeeze-fix-verification.spec.tsx
@@ -13,7 +13,6 @@ vi.mock('next/navigation', () => ({
// Mock classnames utility
vi.mock('@/utils/classnames', () => ({
- __esModule: true,
default: (...classes: any[]) => classes.filter(Boolean).join(' '),
}))
diff --git a/web/app/components/app/annotation/add-annotation-modal/index.spec.tsx b/web/app/components/app/annotation/add-annotation-modal/index.spec.tsx
index 6837516b3c..bad3ceefdf 100644
--- a/web/app/components/app/annotation/add-annotation-modal/index.spec.tsx
+++ b/web/app/components/app/annotation/add-annotation-modal/index.spec.tsx
@@ -10,7 +10,6 @@ vi.mock('@/context/provider-context', () => ({
const mockToastNotify = vi.fn()
vi.mock('@/app/components/base/toast', () => ({
- __esModule: true,
default: {
notify: vi.fn(args => mockToastNotify(args)),
},
diff --git a/web/app/components/app/annotation/batch-add-annotation-modal/index.spec.tsx b/web/app/components/app/annotation/batch-add-annotation-modal/index.spec.tsx
index d7458d6b90..7fdb99fbab 100644
--- a/web/app/components/app/annotation/batch-add-annotation-modal/index.spec.tsx
+++ b/web/app/components/app/annotation/batch-add-annotation-modal/index.spec.tsx
@@ -8,7 +8,6 @@ import { annotationBatchImport, checkAnnotationBatchImportProgress } from '@/ser
import BatchModal, { ProcessStatus } from './index'
vi.mock('@/app/components/base/toast', () => ({
- __esModule: true,
default: {
notify: vi.fn(),
},
@@ -24,14 +23,12 @@ vi.mock('@/context/provider-context', () => ({
}))
vi.mock('./csv-downloader', () => ({
- __esModule: true,
default: () =>
,
}))
let lastUploadedFile: File | undefined
vi.mock('./csv-uploader', () => ({
- __esModule: true,
default: ({ file, updateFile }: { file?: File, updateFile: (file?: File) => void }) => (