diff --git a/web/app/components/base/form/components/field/mixed-variable-text-input/index.tsx b/web/app/components/base/form/components/field/mixed-variable-text-input/index.tsx
new file mode 100644
index 0000000000..4bb562ba3a
--- /dev/null
+++ b/web/app/components/base/form/components/field/mixed-variable-text-input/index.tsx
@@ -0,0 +1,39 @@
+import {
+  memo,
+} from 'react'
+import PromptEditor from '@/app/components/base/prompt-editor'
+import cn from '@/utils/classnames'
+import Placeholder from './placeholder'
+
+type MixedVariableTextInputProps = {
+  editable?: boolean
+  value?: string
+  onChange?: (text: string) => void
+}
+const MixedVariableTextInput = ({
+  editable = true,
+  value = '',
+  onChange,
+}: MixedVariableTextInputProps) => {
+  return (
+    }
+      onChange={onChange}
+    />
+  )
+}
+
+export default memo(MixedVariableTextInput)
diff --git a/web/app/components/base/form/components/field/mixed-variable-text-input/placeholder.tsx b/web/app/components/base/form/components/field/mixed-variable-text-input/placeholder.tsx
new file mode 100644
index 0000000000..e84ffbeb28
--- /dev/null
+++ b/web/app/components/base/form/components/field/mixed-variable-text-input/placeholder.tsx
@@ -0,0 +1,49 @@
+import { useCallback } from 'react'
+import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext'
+import { FOCUS_COMMAND } from 'lexical'
+import { $insertNodes } from 'lexical'
+import { CustomTextNode } from '@/app/components/base/prompt-editor/plugins/custom-text/node'
+import Badge from '@/app/components/base/badge'
+
+const Placeholder = () => {
+  const [editor] = useLexicalComposerContext()
+
+  const handleInsert = useCallback((text: string) => {
+    editor.update(() => {
+      const textNode = new CustomTextNode(text)
+      $insertNodes([textNode])
+    })
+    editor.dispatchCommand(FOCUS_COMMAND, undefined as any)
+  }, [editor])
+
+  return (
+    
 {
+        e.stopPropagation()
+        handleInsert('')
+      }}
+    >
+      
+        Type or press
+        
/
+        
 {
+            e.stopPropagation()
+            handleInsert('/')
+          })}
+        >
+          insert variable
+        
+      
+      
+    
 
+  )
+}
+
+export default Placeholder
diff --git a/web/app/components/base/prompt-editor/index.tsx b/web/app/components/base/prompt-editor/index.tsx
index 94a65e4b62..a87a51cd50 100644
--- a/web/app/components/base/prompt-editor/index.tsx
+++ b/web/app/components/base/prompt-editor/index.tsx
@@ -64,8 +64,9 @@ import cn from '@/utils/classnames'
 export type PromptEditorProps = {
   instanceId?: string
   compact?: boolean
+  wrapperClassName?: string
   className?: string
-  placeholder?: string
+  placeholder?: string | JSX.Element
   placeholderClassName?: string
   style?: React.CSSProperties
   value?: string
@@ -85,6 +86,7 @@ export type PromptEditorProps = {
 const PromptEditor: FC = ({
   instanceId,
   compact,
+  wrapperClassName,
   className,
   placeholder,
   placeholderClassName,
@@ -147,10 +149,25 @@ const PromptEditor: FC = ({
 
   return (
     
-      
+      
         }
-          placeholder={
}
+          contentEditable={
+            
+          }
+          placeholder={
+            
+          }
           ErrorBoundary={LexicalErrorBoundary}
         />
         
 {
   const { t } = useTranslation()
 
   return (
     
       {value || t('common.promptEditor.placeholder')}
     
diff --git a/web/app/components/rag-pipeline/hooks/use-pipeline-config.ts b/web/app/components/rag-pipeline/hooks/use-pipeline-config.ts
new file mode 100644
index 0000000000..f16cd03938
--- /dev/null
+++ b/web/app/components/rag-pipeline/hooks/use-pipeline-config.ts
@@ -0,0 +1,53 @@
+import { useCallback } from 'react'
+import {
+  useStore,
+  useWorkflowStore,
+} from '@/app/components/workflow/store'
+import { useWorkflowConfig } from '@/service/use-workflow'
+import type { ToolWithProvider } from '@/app/components/workflow/types'
+import type { FetchWorkflowDraftResponse } from '@/types/workflow'
+
+export const usePipelineConfig = () => {
+  const pipelineId = useStore(s => s.pipelineId)
+  const workflowStore = useWorkflowStore()
+
+  const handleUpdateWorkflowConfig = useCallback((config: Record) => {
+    const { setWorkflowConfig } = workflowStore.getState()
+
+    setWorkflowConfig(config)
+  }, [workflowStore])
+  useWorkflowConfig(
+    pipelineId ? `/rag/pipeline/${pipelineId}/workflows/draft/config` : '',
+    handleUpdateWorkflowConfig,
+  )
+
+  const handleUpdateDataSourceList = useCallback((dataSourceList: ToolWithProvider[]) => {
+    const { setDataSourceList } = workflowStore.getState()
+
+    setDataSourceList!(dataSourceList)
+  }, [workflowStore])
+  useWorkflowConfig(
+    '/rag/pipelines/datasource-plugins',
+    handleUpdateDataSourceList,
+  )
+
+  const handleUpdateNodesDefaultConfigs = useCallback((nodesDefaultConfigs: Record) => {
+    const { setNodesDefaultConfigs } = workflowStore.getState()
+
+    setNodesDefaultConfigs!(nodesDefaultConfigs)
+  }, [workflowStore])
+  useWorkflowConfig(
+    pipelineId ? `/rag/pipeline/${pipelineId}/workflows/default-workflow-block-configs` : '',
+    handleUpdateNodesDefaultConfigs,
+  )
+
+  const handleUpdatePublishedAt = useCallback((publishedWorkflow: FetchWorkflowDraftResponse) => {
+    const { setPublishedAt } = workflowStore.getState()
+
+    setPublishedAt(publishedWorkflow?.created_at)
+  }, [workflowStore])
+  useWorkflowConfig(
+    pipelineId ? `/rag/pipeline/${pipelineId}/workflows/publish` : '',
+    handleUpdatePublishedAt,
+  )
+}
diff --git a/web/app/components/rag-pipeline/hooks/use-pipeline-init.ts b/web/app/components/rag-pipeline/hooks/use-pipeline-init.ts
index 7d7bdcb531..ab1ee1ea59 100644
--- a/web/app/components/rag-pipeline/hooks/use-pipeline-init.ts
+++ b/web/app/components/rag-pipeline/hooks/use-pipeline-init.ts
@@ -5,18 +5,15 @@ import {
 } from 'react'
 import { useParams } from 'next/navigation'
 import {
-  useStore,
   useWorkflowStore,
 } from '@/app/components/workflow/store'
 import { usePipelineTemplate } from './use-pipeline-template'
 import {
-  fetchNodesDefaultConfigs,
-  fetchPublishedWorkflow,
   fetchWorkflowDraft,
   syncWorkflowDraft,
 } from '@/service/workflow'
 import type { FetchWorkflowDraftResponse } from '@/types/workflow'
-// import { useWorkflowConfig } from '@/service/use-workflow'
+import { usePipelineConfig } from './use-pipeline-config'
 
 export const usePipelineInit = () => {
   const { datasetId } = useParams()
@@ -25,31 +22,33 @@ export const usePipelineInit = () => {
     nodes: nodesTemplate,
     edges: edgesTemplate,
   } = usePipelineTemplate()
-  const setSyncWorkflowDraftHash = useStore(s => s.setSyncWorkflowDraftHash)
   const [data, setData] = useState()
   const [isLoading, setIsLoading] = useState(true)
+
   useEffect(() => {
-    // workflowStore.setState({ pipelineId: datasetId as string })
+    workflowStore.setState({ pipelineId: datasetId as string })
   }, [datasetId, workflowStore])
 
-  const handleUpdateWorkflowConfig = useCallback((config: Record) => {
-    const { setWorkflowConfig } = workflowStore.getState()
-
-    setWorkflowConfig(config)
-  }, [workflowStore])
-  // useWorkflowConfig(`/rag/pipeline/${datasetId}/workflows/draft/config`, handleUpdateWorkflowConfig)
+  usePipelineConfig()
 
   const handleGetInitialWorkflowData = useCallback(async () => {
+    const {
+      setEnvSecrets,
+      setEnvironmentVariables,
+      setSyncWorkflowDraftHash,
+      setDraftUpdatedAt,
+      setToolPublished,
+    } = workflowStore.getState()
     try {
       const res = await fetchWorkflowDraft(`/rag/pipeline/${datasetId}/workflows/draft`)
       setData(res)
-      workflowStore.setState({
-        envSecrets: (res.environment_variables || []).filter(env => env.value_type === 'secret').reduce((acc, env) => {
+      setDraftUpdatedAt(res.updated_at)
+      setToolPublished(res.tool_published)
+      setEnvSecrets((res.environment_variables || []).filter(env => env.value_type === 'secret').reduce((acc, env) => {
           acc[env.id] = env.value
           return acc
-        }, {} as Record),
-        environmentVariables: res.environment_variables?.map(env => env.value_type === 'secret' ? { ...env, value: '[__HIDDEN__]' } : env) || [],
-      })
+        }, {} as Record))
+      setEnvironmentVariables(res.environment_variables?.map(env => env.value_type === 'secret' ? { ...env, value: '[__HIDDEN__]' } : env) || [])
       setSyncWorkflowDraftHash(res.hash)
       setIsLoading(false)
     }
@@ -68,49 +67,21 @@ export const usePipelineInit = () => {
                 environment_variables: [],
               },
             }).then((res) => {
-              workflowStore.getState().setDraftUpdatedAt(res.updated_at)
+              const { setDraftUpdatedAt } = workflowStore.getState()
+              setDraftUpdatedAt(res.updated_at)
               handleGetInitialWorkflowData()
             })
           }
         })
       }
     }
-  }, [nodesTemplate, edgesTemplate, workflowStore, setSyncWorkflowDraftHash, datasetId])
+  }, [nodesTemplate, edgesTemplate, workflowStore, datasetId])
 
   useEffect(() => {
-    // handleGetInitialWorkflowData()
-
+    handleGetInitialWorkflowData()
+  // eslint-disable-next-line react-hooks/exhaustive-deps
   }, [])
 
-  const handleFetchPreloadData = useCallback(async () => {
-    try {
-      const nodesDefaultConfigsData = await fetchNodesDefaultConfigs(`/rag/pipeline/${datasetId}/workflows/default-workflow-block-configs`)
-      const publishedWorkflow = await fetchPublishedWorkflow(`/rag/pipeline/${datasetId}/workflows/publish`)
-      workflowStore.setState({
-        nodesDefaultConfigs: nodesDefaultConfigsData.reduce((acc, block) => {
-          if (!acc[block.type])
-            acc[block.type] = { ...block.config }
-          return acc
-        }, {} as Record),
-      })
-      workflowStore.getState().setPublishedAt(publishedWorkflow?.created_at)
-    }
-    catch (e) {
-      console.error(e)
-    }
-  }, [workflowStore, datasetId])
-
-  useEffect(() => {
-    // handleFetchPreloadData()
-  }, [handleFetchPreloadData])
-
-  useEffect(() => {
-    if (data) {
-      workflowStore.getState().setDraftUpdatedAt(data.updated_at)
-      workflowStore.getState().setToolPublished(data.tool_published)
-    }
-  }, [data, workflowStore])
-
   return {
     data,
     isLoading,
diff --git a/web/app/components/rag-pipeline/store/index.ts b/web/app/components/rag-pipeline/store/index.ts
index 769d7f69f2..5d06543e22 100644
--- a/web/app/components/rag-pipeline/store/index.ts
+++ b/web/app/components/rag-pipeline/store/index.ts
@@ -1,5 +1,6 @@
 import type { RAGPipelineVariables } from '@/models/pipeline'
 import type { StateCreator } from 'zustand'
+import type { ToolWithProvider } from '../../workflow/types'
 import { InputVarType } from '../../workflow/types'
 
 export type RagPipelineSliceShape = {
@@ -10,6 +11,8 @@ export type RagPipelineSliceShape = {
   setNodesDefaultConfigs: (nodesDefaultConfigs: Record) => void
   ragPipelineVariables: RAGPipelineVariables
   setRagPipelineVariables: (ragPipelineVariables: RAGPipelineVariables) => void
+  dataSourceList: ToolWithProvider[]
+  setDataSourceList: (dataSourceList: ToolWithProvider[]) => void
 }
 
 export type CreateRagPipelineSliceSlice = StateCreator
@@ -50,4 +53,6 @@ export const createRagPipelineSliceSlice: StateCreator =
       }],
     }],
   setRagPipelineVariables: (ragPipelineVariables: RAGPipelineVariables) => set(() => ({ ragPipelineVariables })),
+  dataSourceList: [],
+  setDataSourceList: (dataSourceList: ToolWithProvider[]) => set(() => ({ dataSourceList })),
 })
diff --git a/web/app/components/tools/types.ts b/web/app/components/tools/types.ts
index 32c468cde8..4a66ac3063 100644
--- a/web/app/components/tools/types.ts
+++ b/web/app/components/tools/types.ts
@@ -29,6 +29,7 @@ export enum CollectionType {
   custom = 'api',
   model = 'model',
   workflow = 'workflow',
+  datasource = 'datasource',
 }
 
 export type Emoji = {
diff --git a/web/app/components/workflow/block-selector/data-sources.tsx b/web/app/components/workflow/block-selector/data-sources.tsx
new file mode 100644
index 0000000000..f54c113b83
--- /dev/null
+++ b/web/app/components/workflow/block-selector/data-sources.tsx
@@ -0,0 +1,51 @@
+import {
+  useRef,
+} from 'react'
+import type {
+  OnSelectBlock,
+  ToolWithProvider,
+} from '../types'
+import Tools from './tools'
+import { ViewType } from './view-type-select'
+import cn from '@/utils/classnames'
+import type { ListRef } from '@/app/components/workflow/block-selector/market-place-plugin/list'
+
+type AllToolsProps = {
+  className?: string
+  toolContentClassName?: string
+  searchText: string
+  onSelect: OnSelectBlock
+  dataSources: ToolWithProvider[]
+}
+
+const DataSources = ({
+  className,
+  toolContentClassName,
+  searchText,
+  onSelect,
+  dataSources,
+}: AllToolsProps) => {
+  const pluginRef = useRef(null)
+  const wrapElemRef = useRef(null)
+
+  return (
+    
+  )
+}
+
+export default DataSources
diff --git a/web/app/components/workflow/block-selector/hooks.ts b/web/app/components/workflow/block-selector/hooks.ts
index 5f435a76c2..208a44dff6 100644
--- a/web/app/components/workflow/block-selector/hooks.ts
+++ b/web/app/components/workflow/block-selector/hooks.ts
@@ -8,7 +8,7 @@ import {
   ToolTypeEnum,
 } from './types'
 
-export const useTabs = (noBlocks?: boolean) => {
+export const useTabs = (noBlocks?: boolean, noSources?: boolean) => {
   const { t } = useTranslation()
   const tabs = useMemo(() => {
     return [
@@ -22,16 +22,22 @@ export const useTabs = (noBlocks?: boolean) => {
               },
             ]
       ),
-      {
-        key: TabsEnum.Sources,
-        name: t('workflow.tabs.sources'),
-      },
+      ...(
+        noSources
+          ? []
+          : [
+            {
+              key: TabsEnum.Sources,
+              name: t('workflow.tabs.sources'),
+            },
+          ]
+      ),
       {
         key: TabsEnum.Tools,
         name: t('workflow.tabs.tools'),
       },
     ]
-  }, [t, noBlocks])
+  }, [t, noBlocks, noSources])
   const initialTab = useMemo(() => {
     if (noBlocks)
       return TabsEnum.Sources
diff --git a/web/app/components/workflow/block-selector/index.tsx b/web/app/components/workflow/block-selector/index.tsx
index b2d11288b6..949567886d 100644
--- a/web/app/components/workflow/block-selector/index.tsx
+++ b/web/app/components/workflow/block-selector/index.tsx
@@ -3,6 +3,7 @@ import type { NodeSelectorProps } from './main'
 import NodeSelector from './main'
 import { useHooksStore } from '@/app/components/workflow/hooks-store/store'
 import { BlockEnum } from '@/app/components/workflow/types'
+import { useStore } from '@/app/components/workflow/store'
 
 const NodeSelectorWrapper = (props: NodeSelectorProps) => {
   const availableNodesMetaData = useHooksStore(s => s.availableNodesMetaData)
@@ -27,10 +28,13 @@ const NodeSelectorWrapper = (props: NodeSelectorProps) => {
     })
   }, [availableNodesMetaData?.nodes])
 
+  const dataSourceList = useStore(s => s.dataSourceList)
+
   return (
     
   )
 }
diff --git a/web/app/components/workflow/block-selector/main.tsx b/web/app/components/workflow/block-selector/main.tsx
index 254045e231..e1bcd84c24 100644
--- a/web/app/components/workflow/block-selector/main.tsx
+++ b/web/app/components/workflow/block-selector/main.tsx
@@ -17,6 +17,7 @@ import type {
   BlockEnum,
   NodeDefault,
   OnSelectBlock,
+  ToolWithProvider,
 } from '../types'
 import Tabs from './tabs'
 import { TabsEnum } from './types'
@@ -49,6 +50,7 @@ export type NodeSelectorProps = {
   availableBlocksTypes?: BlockEnum[]
   disabled?: boolean
   blocks?: NodeDefault[]
+  dataSources?: ToolWithProvider[]
 }
 const NodeSelector: FC = ({
   open: openFromProps,
@@ -65,6 +67,7 @@ const NodeSelector: FC = ({
   availableBlocksTypes,
   disabled,
   blocks = [],
+  dataSources = [],
 }) => {
   const { t } = useTranslation()
   const [searchText, setSearchText] = useState('')
@@ -95,7 +98,7 @@ const NodeSelector: FC = ({
     activeTab,
     setActiveTab,
     tabs,
-  } = useTabs(!blocks.length)
+  } = useTabs(!blocks.length, !dataSources.length)
 
   const searchPlaceholder = useMemo(() => {
     if (activeTab === TabsEnum.Blocks)
@@ -193,6 +196,7 @@ const NodeSelector: FC = ({
             tags={tags}
             availableBlocksTypes={availableBlocksTypes}
             blocks={blocks}
+            dataSources={dataSources}
           />
          
       
diff --git a/web/app/components/workflow/block-selector/tabs.tsx b/web/app/components/workflow/block-selector/tabs.tsx
index bad9481c21..c4dc4532cf 100644
--- a/web/app/components/workflow/block-selector/tabs.tsx
+++ b/web/app/components/workflow/block-selector/tabs.tsx
@@ -4,11 +4,13 @@ import { useAllBuiltInTools, useAllCustomTools, useAllWorkflowTools } from '@/se
 import type {
   BlockEnum,
   NodeDefault,
+  ToolWithProvider,
 } from '../types'
 import type { ToolDefaultValue } from './types'
 import { TabsEnum } from './types'
 import Blocks from './blocks'
 import AllTools from './all-tools'
+import DataSources from './data-sources'
 
 export type TabsProps = {
   activeTab: TabsEnum
@@ -17,6 +19,7 @@ export type TabsProps = {
   onSelect: (type: BlockEnum, tool?: ToolDefaultValue) => void
   availableBlocksTypes?: BlockEnum[]
   blocks: NodeDefault[]
+  dataSources?: ToolWithProvider[]
 }
 const Tabs: FC
 = ({
   activeTab,
@@ -25,6 +28,7 @@ const Tabs: FC = ({
   onSelect,
   availableBlocksTypes,
   blocks,
+  dataSources = [],
 }) => {
   const { data: buildInTools } = useAllBuiltInTools()
   const { data: customTools } = useAllCustomTools()
@@ -42,6 +46,15 @@ const Tabs: FC = ({
           />
         )
       }
+      {
+        activeTab === TabsEnum.Sources && !!dataSources.length && (
+          
+        )
+      }
       {
         activeTab === TabsEnum.Tools && (
            {
   })
 }
 
-export const useWorkflowConfig = (url: string, onSuccess: (v: WorkflowConfigResponse) => void) => {
+export const useWorkflowConfig = (url: string, onSuccess: (v: T) => void) => {
   return useQuery({
+    enabled: !!url,
     queryKey: [NAME_SPACE, 'config', url],
     queryFn: async () => {
-      const data = await get(url)
+      const data = await get(url)
       onSuccess(data)
       return data
     },