mirror of
https://github.com/langgenius/dify.git
synced 2026-05-04 01:18:05 +08:00
feat: enhance user action validation in human input form by adding checks for duplicate IDs, empty IDs, and empty titles; update translations accordingly
This commit is contained in:
@ -32,7 +32,7 @@ const RunMode = ({
|
||||
handleWorkflowRunAllTriggersInWorkflow,
|
||||
} = useWorkflowStartRun()
|
||||
const { handleStopRun } = useWorkflowRun()
|
||||
const { validateBeforeRun, warningNodes } = useWorkflowRunValidation()
|
||||
const { warningNodes } = useWorkflowRunValidation()
|
||||
const workflowRunningData = useStore(s => s.workflowRunningData)
|
||||
const isListening = useStore(s => s.isListening)
|
||||
|
||||
@ -98,14 +98,7 @@ const RunMode = ({
|
||||
// Placeholder for trigger-specific execution logic for schedule, webhook, plugin types
|
||||
console.log('TODO: Handle trigger execution for type:', option.type, 'nodeId:', option.nodeId)
|
||||
}
|
||||
}, [
|
||||
validateBeforeRun,
|
||||
handleWorkflowStartRunInWorkflow,
|
||||
handleWorkflowTriggerScheduleRunInWorkflow,
|
||||
handleWorkflowTriggerWebhookRunInWorkflow,
|
||||
handleWorkflowTriggerPluginRunInWorkflow,
|
||||
handleWorkflowRunAllTriggersInWorkflow,
|
||||
])
|
||||
}, [warningNodes, notify, t, handleWorkflowStartRunInWorkflow, handleWorkflowTriggerScheduleRunInWorkflow, handleWorkflowTriggerWebhookRunInWorkflow, handleWorkflowTriggerPluginRunInWorkflow, handleWorkflowRunAllTriggersInWorkflow])
|
||||
|
||||
const { eventEmitter } = useEventEmitterContextContext()
|
||||
eventEmitter?.useSubscription((v: any) => {
|
||||
|
||||
@ -316,20 +316,7 @@ const useOneStepRun = <T>({
|
||||
invalidateSysVarValues()
|
||||
invalidateConversationVarValues() // loop, iteration, variable assigner node can update the conversation variables, but to simple the logic(some nodes may also can update in the future), all nodes refresh.
|
||||
}
|
||||
}, [
|
||||
isRunAfterSingleRun,
|
||||
runningStatus,
|
||||
flowId,
|
||||
id,
|
||||
store,
|
||||
appendNodeInspectVars,
|
||||
updateNodeInspectRunningState,
|
||||
invalidLastRun,
|
||||
isStartNode,
|
||||
isTriggerNode,
|
||||
invalidateSysVarValues,
|
||||
invalidateConversationVarValues,
|
||||
])
|
||||
}, [isRunAfterSingleRun, runningStatus, flowType, flowId, id, store, appendNodeInspectVars, updateNodeInspectRunningState, invalidLastRun, isStartNode, isTriggerNode, invalidateSysVarValues, invalidateConversationVarValues])
|
||||
|
||||
const { handleNodeDataUpdate }: { handleNodeDataUpdate: (data: any) => void } = useNodeDataUpdate()
|
||||
const setNodeRunning = () => {
|
||||
|
||||
@ -7,10 +7,12 @@ import * as React from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import Button from '@/app/components/base/button'
|
||||
import Input from '@/app/components/base/input'
|
||||
import { genActionId } from '../utils'
|
||||
import Toast from '@/app/components/base/toast'
|
||||
import ButtonStyleDropdown from './button-style-dropdown'
|
||||
|
||||
const i18nPrefix = 'nodes.humanInput'
|
||||
const ACTION_ID_MAX_LENGTH = 20
|
||||
const BUTTON_TEXT_MAX_LENGTH = 40
|
||||
|
||||
type UserActionItemProps = {
|
||||
data: UserAction
|
||||
@ -28,17 +30,42 @@ const UserActionItem: FC<UserActionItemProps> = ({
|
||||
const { t } = useTranslation()
|
||||
|
||||
const handleIDChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
if (!e.target.value.trim())
|
||||
onChange({ ...data, id: genActionId() })
|
||||
else
|
||||
onChange({ ...data, id: e.target.value })
|
||||
const value = e.target.value
|
||||
if (!value.trim()) {
|
||||
onChange({ ...data, id: '' })
|
||||
return
|
||||
}
|
||||
// Convert spaces to underscores, then only allow characters matching /^[A-Za-z_][A-Za-z0-9_]*$/
|
||||
const withUnderscores = value.replace(/ /g, '_')
|
||||
let sanitized = withUnderscores
|
||||
.split('')
|
||||
.filter((char, index) => {
|
||||
if (index === 0)
|
||||
return /^[a-z_]$/i.test(char)
|
||||
return /^\w$/.test(char)
|
||||
})
|
||||
.join('')
|
||||
|
||||
if (sanitized !== withUnderscores)
|
||||
Toast.notify({ type: 'error', message: t(`${i18nPrefix}.userActions.invalidActionIdFormat`, { ns: 'workflow' }) })
|
||||
|
||||
// Limit to 20 characters
|
||||
if (sanitized.length > ACTION_ID_MAX_LENGTH) {
|
||||
sanitized = sanitized.slice(0, ACTION_ID_MAX_LENGTH)
|
||||
Toast.notify({ type: 'error', message: t(`${i18nPrefix}.userActions.actionIdTooLong`, { ns: 'workflow' }) })
|
||||
}
|
||||
|
||||
if (sanitized)
|
||||
onChange({ ...data, id: sanitized })
|
||||
}
|
||||
|
||||
const handleTextChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
if (!e.target.value.trim())
|
||||
onChange({ ...data, title: 'Button Text' })
|
||||
else
|
||||
onChange({ ...data, title: e.target.value })
|
||||
let value = e.target.value
|
||||
if (value.length > BUTTON_TEXT_MAX_LENGTH) {
|
||||
value = value.slice(0, BUTTON_TEXT_MAX_LENGTH)
|
||||
Toast.notify({ type: 'error', message: t(`${i18nPrefix}.userActions.buttonTextTooLong`, { ns: 'workflow' }) })
|
||||
}
|
||||
onChange({ ...data, title: value })
|
||||
}
|
||||
|
||||
return (
|
||||
|
||||
@ -42,6 +42,25 @@ const nodeDefault: NodeDefault<HumanInputNodeType> = {
|
||||
if (!errorMessages && !payload.user_actions.length)
|
||||
errorMessages = t(`${i18nPrefix}.noUserActions`, { ns: 'workflow' })
|
||||
|
||||
if (!errorMessages && payload.user_actions.length > 0) {
|
||||
const actionIds = payload.user_actions.map(action => action.id)
|
||||
const hasDuplicateIds = actionIds.length !== new Set(actionIds).size
|
||||
if (hasDuplicateIds)
|
||||
errorMessages = t(`${i18nPrefix}.duplicateActionId`, { ns: 'workflow' })
|
||||
}
|
||||
|
||||
if (!errorMessages && payload.user_actions.length > 0) {
|
||||
const hasEmptyId = payload.user_actions.some(action => !action.id?.trim())
|
||||
if (hasEmptyId)
|
||||
errorMessages = t(`${i18nPrefix}.emptyActionId`, { ns: 'workflow' })
|
||||
}
|
||||
|
||||
if (!errorMessages && payload.user_actions.length > 0) {
|
||||
const hasEmptyTitle = payload.user_actions.some(action => !action.title?.trim())
|
||||
if (hasEmptyTitle)
|
||||
errorMessages = t(`${i18nPrefix}.emptyActionTitle`, { ns: 'workflow' })
|
||||
}
|
||||
|
||||
return {
|
||||
isValid: !errorMessages,
|
||||
errorMessage: errorMessages,
|
||||
|
||||
Reference in New Issue
Block a user