mirror of https://github.com/langgenius/dify.git
block icon
This commit is contained in:
parent
202492e5ac
commit
a89287bf20
|
|
@ -1,3 +1,5 @@
|
|||
import type { TransferMethod } from '@/types/app'
|
||||
|
||||
export type EnabledOrDisabled = {
|
||||
enabled: boolean
|
||||
}
|
||||
|
|
@ -26,7 +28,7 @@ export type SensitiveWordAvoidance = EnabledOrDisabled & {
|
|||
export type FileUpload = {
|
||||
image: EnabledOrDisabled & {
|
||||
number_limits: number
|
||||
transfer_methods: string[]
|
||||
transfer_methods: TransferMethod[]
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
import type { FC } from 'react'
|
||||
import { memo } from 'react'
|
||||
import { BlockEnum } from './types'
|
||||
import { useStore } from './store'
|
||||
import {
|
||||
Answer,
|
||||
Code,
|
||||
|
|
@ -21,7 +20,7 @@ type BlockIconProps = {
|
|||
type: BlockEnum
|
||||
size?: string
|
||||
className?: string
|
||||
toolProviderId?: string
|
||||
toolIcon?: string | { content: string; background: string }
|
||||
}
|
||||
const ICON_CONTAINER_CLASSNAME_SIZE_MAP: Record<string, string> = {
|
||||
sm: 'w-5 h-5 rounded-md shadow-xs',
|
||||
|
|
@ -60,17 +59,14 @@ const BlockIcon: FC<BlockIconProps> = ({
|
|||
type,
|
||||
size = 'sm',
|
||||
className,
|
||||
toolProviderId,
|
||||
toolIcon,
|
||||
}) => {
|
||||
const toolsets = useStore(s => s.toolsets)
|
||||
const icon = toolsets.find(toolset => toolset.id === toolProviderId)?.icon
|
||||
|
||||
return (
|
||||
<div className={`
|
||||
flex items-center justify-center border-[0.5px] border-white/[0.02] text-white
|
||||
${ICON_CONTAINER_CLASSNAME_SIZE_MAP[size]}
|
||||
${ICON_CONTAINER_BG_COLOR_MAP[type]}
|
||||
${icon && '!shadow-none'}
|
||||
${toolIcon && '!shadow-none'}
|
||||
${className}
|
||||
`}
|
||||
>
|
||||
|
|
@ -80,15 +76,15 @@ const BlockIcon: FC<BlockIconProps> = ({
|
|||
)
|
||||
}
|
||||
{
|
||||
type === BlockEnum.Tool && icon && (
|
||||
type === BlockEnum.Tool && toolIcon && (
|
||||
<>
|
||||
{
|
||||
typeof icon === 'string'
|
||||
typeof toolIcon === 'string'
|
||||
? (
|
||||
<div
|
||||
className='shrink-0 w-full h-full bg-cover bg-center rounded-md'
|
||||
style={{
|
||||
backgroundImage: `url(${icon})`,
|
||||
backgroundImage: `url(${toolIcon})`,
|
||||
}}
|
||||
></div>
|
||||
)
|
||||
|
|
@ -96,8 +92,8 @@ const BlockIcon: FC<BlockIconProps> = ({
|
|||
<AppIcon
|
||||
className='shrink-0 !w-full !h-full'
|
||||
size='tiny'
|
||||
icon={icon?.content}
|
||||
background={icon?.background}
|
||||
icon={toolIcon?.content}
|
||||
background={toolIcon?.background}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,8 +8,9 @@ import CodeEditor from '../editor/code-editor'
|
|||
import { CodeLanguage } from '../../../code/types'
|
||||
import Select from '@/app/components/base/select'
|
||||
import TextGenerationImageUploader from '@/app/components/base/image-uploader/text-generation-image-uploader'
|
||||
import { Resolution, TransferMethod } from '@/types/app'
|
||||
import { Resolution } from '@/types/app'
|
||||
import { Trash03 } from '@/app/components/base/icons/src/vender/line/general'
|
||||
import { useFeatures } from '@/app/components/base/features/hooks'
|
||||
|
||||
type Props = {
|
||||
payload: InputVar
|
||||
|
|
@ -25,6 +26,7 @@ const FormItem: FC<Props> = ({
|
|||
className,
|
||||
}) => {
|
||||
const { type } = payload
|
||||
const fileSettings = useFeatures(s => s.features.file)
|
||||
const handleContextItemChange = useCallback((index: number) => {
|
||||
return (newValue: any) => {
|
||||
const newValues = produce(value, (draft: any) => {
|
||||
|
|
@ -105,10 +107,8 @@ const FormItem: FC<Props> = ({
|
|||
type === InputVarType.files && (
|
||||
<TextGenerationImageUploader
|
||||
settings={{
|
||||
enabled: true,
|
||||
number_limits: 3,
|
||||
...fileSettings.image,
|
||||
detail: Resolution.high,
|
||||
transfer_methods: [TransferMethod.local_file, TransferMethod.remote_url],
|
||||
}}
|
||||
onFilesChange={files => onChange(files.filter(file => file.progress !== -1).map(fileItem => ({
|
||||
type: 'image',
|
||||
|
|
|
|||
|
|
@ -1,4 +1,7 @@
|
|||
import { memo } from 'react'
|
||||
import {
|
||||
memo,
|
||||
useMemo,
|
||||
} from 'react'
|
||||
import {
|
||||
getConnectedEdges,
|
||||
getOutgoers,
|
||||
|
|
@ -6,6 +9,7 @@ import {
|
|||
useStoreApi,
|
||||
} from 'reactflow'
|
||||
import BlockIcon from '../../../../block-icon'
|
||||
import { useStore } from '../../../../store'
|
||||
import type {
|
||||
Branch,
|
||||
Node,
|
||||
|
|
@ -21,9 +25,15 @@ type NextStepProps = {
|
|||
const NextStep = ({
|
||||
selectedNode,
|
||||
}: NextStepProps) => {
|
||||
const data = selectedNode.data
|
||||
const toolsets = useStore(s => s.toolsets)
|
||||
const toolIcon = useMemo(() => {
|
||||
if (data.type === BlockEnum.Tool)
|
||||
return toolsets.find(toolset => toolset.id === data.provider_id)?.icon
|
||||
}, [data, toolsets])
|
||||
const store = useStoreApi()
|
||||
const branches = selectedNode.data._targetBranches || []
|
||||
const nodeWithBranches = selectedNode.data.type === BlockEnum.IfElse || selectedNode.data.type === BlockEnum.QuestionClassifier
|
||||
const branches = data._targetBranches || []
|
||||
const nodeWithBranches = data.type === BlockEnum.IfElse || data.type === BlockEnum.QuestionClassifier
|
||||
const edges = useEdges()
|
||||
const outgoers = getOutgoers(selectedNode as Node, store.getState().getNodes(), edges)
|
||||
const connectedEdges = getConnectedEdges([selectedNode] as Node[], edges).filter(edge => edge.source === selectedNode!.id)
|
||||
|
|
@ -33,7 +43,7 @@ const NextStep = ({
|
|||
<div className='shrink-0 relative flex items-center justify-center w-9 h-9 bg-white rounded-lg border-[0.5px] border-gray-200 shadow-xs'>
|
||||
<BlockIcon
|
||||
type={selectedNode!.data.type}
|
||||
toolProviderId={selectedNode!.data.provider_id}
|
||||
toolIcon={toolIcon}
|
||||
/>
|
||||
</div>
|
||||
<Line linesNumber={nodeWithBranches ? branches.length : 1} />
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import {
|
||||
memo,
|
||||
useCallback,
|
||||
useMemo,
|
||||
} from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { union } from 'lodash-es'
|
||||
|
|
@ -15,6 +16,8 @@ import {
|
|||
useNodesInteractions,
|
||||
} from '@/app/components/workflow/hooks'
|
||||
import Button from '@/app/components/base/button'
|
||||
import { useStore } from '@/app/components/workflow/store'
|
||||
import { BlockEnum } from '@/app/components/workflow/types'
|
||||
|
||||
type ItemProps = {
|
||||
nodeId: string
|
||||
|
|
@ -31,6 +34,11 @@ const Item = ({
|
|||
const { t } = useTranslation()
|
||||
const { handleNodeChange } = useNodesInteractions()
|
||||
const nodesExtraData = useNodesExtraData()
|
||||
const toolsets = useStore(s => s.toolsets)
|
||||
const toolIcon = useMemo(() => {
|
||||
if (data.type === BlockEnum.Tool)
|
||||
return toolsets.find(toolset => toolset.id === data.provider_id)?.icon
|
||||
}, [data, toolsets])
|
||||
const availablePrevNodes = nodesExtraData[data.type].availablePrevNodes
|
||||
const availableNextNodes = nodesExtraData[data.type].availableNextNodes
|
||||
const handleSelect = useCallback<OnSelectBlock>((type, toolDefaultValue) => {
|
||||
|
|
@ -65,7 +73,7 @@ const Item = ({
|
|||
}
|
||||
<BlockIcon
|
||||
type={data.type}
|
||||
toolProviderId={data.provider_id}
|
||||
toolIcon={toolIcon}
|
||||
className='shrink-0 mr-1.5'
|
||||
/>
|
||||
<div className='grow'>{data.title}</div>
|
||||
|
|
|
|||
|
|
@ -5,12 +5,14 @@ import type {
|
|||
import {
|
||||
cloneElement,
|
||||
memo,
|
||||
useMemo,
|
||||
} from 'react'
|
||||
import type { NodeProps } from '../../types'
|
||||
import {
|
||||
BlockEnum,
|
||||
NodeRunningStatus,
|
||||
} from '../../types'
|
||||
import { useStore } from '../../store'
|
||||
import {
|
||||
NodeSourceHandle,
|
||||
NodeTargetHandle,
|
||||
|
|
@ -32,6 +34,12 @@ const BaseNode: FC<BaseNodeProps> = ({
|
|||
data,
|
||||
children,
|
||||
}) => {
|
||||
const toolsets = useStore(s => s.toolsets)
|
||||
const toolIcon = useMemo(() => {
|
||||
if (data.type === BlockEnum.Tool)
|
||||
return toolsets.find(toolset => toolset.id === data.provider_id)?.icon
|
||||
}, [data, toolsets])
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`
|
||||
|
|
@ -84,7 +92,7 @@ const BaseNode: FC<BaseNodeProps> = ({
|
|||
className='shrink-0 mr-2'
|
||||
type={data.type}
|
||||
size='md'
|
||||
toolProviderId={data.provider_id}
|
||||
toolIcon={toolIcon}
|
||||
/>
|
||||
<div
|
||||
title={data.title}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import {
|
|||
cloneElement,
|
||||
memo,
|
||||
useCallback,
|
||||
useMemo,
|
||||
} from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import NextStep from './components/next-step'
|
||||
|
|
@ -23,11 +24,13 @@ import {
|
|||
useNodesExtraData,
|
||||
useNodesInteractions,
|
||||
} from '@/app/components/workflow/hooks'
|
||||
import { useStore } from '@/app/components/workflow/store'
|
||||
import { canRunBySingle } from '@/app/components/workflow/utils'
|
||||
import { GitBranch01 } from '@/app/components/base/icons/src/vender/line/development'
|
||||
import { Play } from '@/app/components/base/icons/src/vender/line/mediaAndDevices'
|
||||
import TooltipPlus from '@/app/components/base/tooltip-plus'
|
||||
import type { Node } from '@/app/components/workflow/types'
|
||||
import { BlockEnum } from '@/app/components/workflow/types'
|
||||
|
||||
type BasePanelProps = {
|
||||
children: ReactElement
|
||||
|
|
@ -43,6 +46,12 @@ const BasePanel: FC<BasePanelProps> = ({
|
|||
const nodesExtraData = useNodesExtraData()
|
||||
const availableNextNodes = nodesExtraData[data.type].availableNextNodes
|
||||
|
||||
const toolsets = useStore(s => s.toolsets)
|
||||
const toolIcon = useMemo(() => {
|
||||
if (data.type === BlockEnum.Tool)
|
||||
return toolsets.find(toolset => toolset.id === data.provider_id)?.icon
|
||||
}, [data, toolsets])
|
||||
|
||||
const {
|
||||
handleNodeDataUpdate,
|
||||
handleNodeDataUpdateWithSyncDraft,
|
||||
|
|
@ -62,7 +71,7 @@ const BasePanel: FC<BasePanelProps> = ({
|
|||
<BlockIcon
|
||||
className='shrink-0 mr-1'
|
||||
type={data.type}
|
||||
toolProviderId={data.provider_id}
|
||||
toolIcon={toolIcon}
|
||||
size='md'
|
||||
/>
|
||||
<TitleInput
|
||||
|
|
|
|||
|
|
@ -1,11 +1,15 @@
|
|||
import {
|
||||
memo,
|
||||
useCallback,
|
||||
useMemo,
|
||||
} from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useNodes } from 'reactflow'
|
||||
import FormItem from '../nodes/_base/components/before-run-form/form-item'
|
||||
import { BlockEnum } from '../types'
|
||||
import {
|
||||
BlockEnum,
|
||||
InputVarType,
|
||||
} from '../types'
|
||||
import {
|
||||
useStore,
|
||||
useWorkflowStore,
|
||||
|
|
@ -13,24 +17,51 @@ import {
|
|||
import { useWorkflowRun } from '../hooks'
|
||||
import type { StartNodeType } from '../nodes/start/types'
|
||||
import Button from '@/app/components/base/button'
|
||||
import { useFeatures } from '@/app/components/base/features/hooks'
|
||||
|
||||
const InputsPanel = () => {
|
||||
const { t } = useTranslation()
|
||||
const workflowStore = useWorkflowStore()
|
||||
const fileSettings = useFeatures(s => s.features.file)
|
||||
const nodes = useNodes<StartNodeType>()
|
||||
const inputs = useStore(s => s.inputs)
|
||||
const files = useStore(s => s.files)
|
||||
const {
|
||||
handleRun,
|
||||
handleRunSetting,
|
||||
} = useWorkflowRun()
|
||||
const startNode = nodes.find(node => node.data.type === BlockEnum.Start)
|
||||
const variables = startNode?.data.variables || []
|
||||
const startVariables = startNode?.data.variables
|
||||
|
||||
const handleValueChange = (variable: string, v: string) => {
|
||||
workflowStore.getState().setInputs({
|
||||
...inputs,
|
||||
[variable]: v,
|
||||
})
|
||||
const variables = useMemo(() => {
|
||||
const data = startVariables || []
|
||||
if (fileSettings.image.enabled) {
|
||||
return [
|
||||
...data,
|
||||
{
|
||||
type: InputVarType.files,
|
||||
variable: '__image',
|
||||
required: true,
|
||||
label: 'files',
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
return data
|
||||
}, [fileSettings.image.enabled, startVariables])
|
||||
|
||||
const handleValueChange = (variable: string, v: any) => {
|
||||
if (variable === '__image') {
|
||||
workflowStore.setState({
|
||||
files: v,
|
||||
})
|
||||
}
|
||||
else {
|
||||
workflowStore.getState().setInputs({
|
||||
...inputs,
|
||||
[variable]: v,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const handleCancel = useCallback(() => {
|
||||
|
|
@ -40,7 +71,7 @@ const InputsPanel = () => {
|
|||
const doRun = () => {
|
||||
handleCancel()
|
||||
handleRunSetting()
|
||||
handleRun({ inputs })
|
||||
handleRun({ inputs, files })
|
||||
}
|
||||
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ import type {
|
|||
import type {
|
||||
Edge,
|
||||
Node,
|
||||
RunFile,
|
||||
WorkflowRunningStatus,
|
||||
} from './types'
|
||||
import { WorkflowContext } from './context'
|
||||
|
|
@ -36,6 +37,7 @@ type State = {
|
|||
runningStatus?: WorkflowRunningStatus
|
||||
showInputsPanel: boolean
|
||||
inputs: Record<string, string>
|
||||
files: RunFile[]
|
||||
backupDraft?: {
|
||||
nodes: Node[]
|
||||
edges: Edge[]
|
||||
|
|
@ -63,6 +65,7 @@ type Action = {
|
|||
setRunningStatus: (runningStatus?: WorkflowRunningStatus) => void
|
||||
setShowInputsPanel: (showInputsPanel: boolean) => void
|
||||
setInputs: (inputs: Record<string, string>) => void
|
||||
setFiles: (files: RunFile[]) => void
|
||||
setBackupDraft: (backupDraft?: State['backupDraft']) => void
|
||||
setNotInitialWorkflow: (notInitialWorkflow: boolean) => void
|
||||
setNodesDefaultConfigs: (nodesDefaultConfigs: Record<string, any>) => void
|
||||
|
|
@ -102,6 +105,8 @@ export const createWorkflowStore = () => {
|
|||
setShowInputsPanel: showInputsPanel => set(() => ({ showInputsPanel })),
|
||||
inputs: {},
|
||||
setInputs: inputs => set(() => ({ inputs })),
|
||||
files: [],
|
||||
setFiles: files => set(() => ({ files })),
|
||||
backupDraft: undefined,
|
||||
setBackupDraft: backupDraft => set(() => ({ backupDraft })),
|
||||
notInitialWorkflow: false,
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import type {
|
|||
Edge as ReactFlowEdge,
|
||||
Node as ReactFlowNode,
|
||||
} from 'reactflow'
|
||||
import type { TransferMethod } from '@/types/app'
|
||||
import type { ToolDefaultValue } from '@/app/components/workflow/block-selector/types'
|
||||
import type { VarType as VarKindType } from '@/app/components/workflow/nodes/tool/types'
|
||||
|
||||
|
|
@ -211,3 +212,10 @@ export type CheckValidRes = {
|
|||
isValid: boolean
|
||||
errorMessage?: string
|
||||
}
|
||||
|
||||
export type RunFile = {
|
||||
type: string
|
||||
transfer_method: TransferMethod[]
|
||||
url?: string
|
||||
upload_file_id?: string
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue