diff --git a/web/app/components/base/prompt-editor/plugins/hitl-input-block/component-ui.tsx b/web/app/components/base/prompt-editor/plugins/hitl-input-block/component-ui.tsx index ace9126841..1426d57451 100644 --- a/web/app/components/base/prompt-editor/plugins/hitl-input-block/component-ui.tsx +++ b/web/app/components/base/prompt-editor/plugins/hitl-input-block/component-ui.tsx @@ -30,6 +30,7 @@ type HITLInputComponentUIProps = { nodeId: string valueSelector: ValueSelector }) => Type + readonly?: boolean } const HITLInputComponentUI: FC = ({ @@ -52,6 +53,7 @@ const HITLInputComponentUI: FC = ({ environmentVariables, conversationVariables, ragVariables, + readonly, }) => { const [isShowEditModal, { setTrue: showEditModal, @@ -97,7 +99,7 @@ const HITLInputComponentUI: FC = ({ return (
@@ -107,36 +109,40 @@ const HITLInputComponentUI: FC = ({
-
- {/* Placeholder Info */} - {isPlaceholderVariable && ( - - )} - {!isPlaceholderVariable && ( -
{formInput.placeholder.value}
- )} +
+
+ {/* Placeholder Info */} + {isPlaceholderVariable && ( + + )} + {!isPlaceholderVariable && ( +
{formInput.placeholder.value}
+ )} +
{/* Actions */} -
-
- - - -
+ {!readonly && ( +
+
+ + + +
-
- - - +
+ + + +
-
+ )}
{isShowEditModal && ( diff --git a/web/app/components/base/prompt-editor/plugins/hitl-input-block/component.tsx b/web/app/components/base/prompt-editor/plugins/hitl-input-block/component.tsx index 9bbac6c075..df4147fc33 100644 --- a/web/app/components/base/prompt-editor/plugins/hitl-input-block/component.tsx +++ b/web/app/components/base/prompt-editor/plugins/hitl-input-block/component.tsx @@ -25,6 +25,7 @@ type HITLInputComponentProps = { nodeId: string valueSelector: ValueSelector }) => Type + readonly?: boolean } const HITLInputComponent: FC = ({ @@ -40,6 +41,7 @@ const HITLInputComponent: FC = ({ environmentVariables, conversationVariables, ragVariables, + readonly, }) => { const [ref] = useSelectOrDelete(nodeKey, DELETE_HITL_INPUT_BLOCK_COMMAND) const payload = formInputs.find(item => item.output_variable_name === varName) @@ -75,6 +77,7 @@ const HITLInputComponent: FC = ({ environmentVariables={environmentVariables} conversationVariables={conversationVariables} ragVariables={ragVariables} + readonly={readonly} />
) diff --git a/web/app/components/base/prompt-editor/plugins/hitl-input-block/hitl-input-block-replacement-block.tsx b/web/app/components/base/prompt-editor/plugins/hitl-input-block/hitl-input-block-replacement-block.tsx index 58c7261586..cd1515c57d 100644 --- a/web/app/components/base/prompt-editor/plugins/hitl-input-block/hitl-input-block-replacement-block.tsx +++ b/web/app/components/base/prompt-editor/plugins/hitl-input-block/hitl-input-block-replacement-block.tsx @@ -25,6 +25,7 @@ const HITLInputReplacementBlock = ({ workflowNodesMap, getVarType, variables, + readonly, }: HITLInputBlockType) => { const [editor] = useLexicalComposerContext() @@ -57,8 +58,9 @@ const HITLInputReplacementBlock = ({ environmentVariables, conversationVariables, ragVariables, + readonly, )) - }, [nodeId, formInputs, onFormInputsChange, onFormInputItemRename, onFormInputItemRemove, workflowNodesMap, getVarType, environmentVariables, conversationVariables, ragVariables]) + }, [nodeId, formInputs, onFormInputsChange, onFormInputItemRename, onFormInputItemRemove, workflowNodesMap, getVarType, environmentVariables, conversationVariables, ragVariables, readonly]) const getMatch = useCallback((text: string) => { const matchArr = REGEX.exec(text) diff --git a/web/app/components/base/prompt-editor/plugins/hitl-input-block/index.tsx b/web/app/components/base/prompt-editor/plugins/hitl-input-block/index.tsx index e17d37257c..9e0187da56 100644 --- a/web/app/components/base/prompt-editor/plugins/hitl-input-block/index.tsx +++ b/web/app/components/base/prompt-editor/plugins/hitl-input-block/index.tsx @@ -31,6 +31,7 @@ const HITLInputBlock = memo(({ onDelete, workflowNodesMap, getVarType, + readonly, }: HITLInputBlockType) => { const [editor] = useLexicalComposerContext() @@ -64,6 +65,10 @@ const HITLInputBlock = memo(({ onFormInputItemRemove, workflowNodesMap, getVarType, + undefined, + undefined, + undefined, + readonly, ) $insertNodes([currentHITLNode]) diff --git a/web/app/components/base/prompt-editor/plugins/hitl-input-block/node.tsx b/web/app/components/base/prompt-editor/plugins/hitl-input-block/node.tsx index 56c28f7bd9..cc76e2e722 100644 --- a/web/app/components/base/prompt-editor/plugins/hitl-input-block/node.tsx +++ b/web/app/components/base/prompt-editor/plugins/hitl-input-block/node.tsx @@ -18,6 +18,7 @@ export type HITLNodeProps = { environmentVariables?: Var[] conversationVariables?: Var[] ragVariables?: Var[] + readonly?: boolean } export type SerializedNode = SerializedLexicalNode & HITLNodeProps @@ -34,6 +35,7 @@ export class HITLInputNode extends DecoratorNode { __environmentVariables?: Var[] __conversationVariables?: Var[] __ragVariables?: Var[] + __readonly?: boolean isIsolated(): boolean { return true // This is necessary for drag-and-drop to work correctly @@ -102,6 +104,11 @@ export class HITLInputNode extends DecoratorNode { return self.__ragVariables || [] } + getReadonly(): boolean { + const self = this.getLatest() + return self.__readonly || false + } + static clone(node: HITLInputNode): HITLInputNode { return new HITLInputNode( node.__variableName, @@ -115,6 +122,7 @@ export class HITLInputNode extends DecoratorNode { node.__environmentVariables, node.__conversationVariables, node.__ragVariables, + node.__readonly, node.__key, ) } @@ -135,6 +143,7 @@ export class HITLInputNode extends DecoratorNode { environmentVariables?: Var[], conversationVariables?: Var[], ragVariables?: Var[], + readonly?: boolean, key?: NodeKey, ) { super(key) @@ -150,6 +159,7 @@ export class HITLInputNode extends DecoratorNode { this.__environmentVariables = environmentVariables this.__conversationVariables = conversationVariables this.__ragVariables = ragVariables + this.__readonly = readonly } createDOM(): HTMLElement { @@ -177,6 +187,7 @@ export class HITLInputNode extends DecoratorNode { environmentVariables={this.getEnvironmentVariables()} conversationVariables={this.getConversationVariables()} ragVariables={this.getRagVariables()} + readonly={this.getReadonly()} /> ) } @@ -194,6 +205,7 @@ export class HITLInputNode extends DecoratorNode { serializedNode.environmentVariables, serializedNode.conversationVariables, serializedNode.ragVariables, + serializedNode.readonly, ) return node @@ -214,6 +226,7 @@ export class HITLInputNode extends DecoratorNode { environmentVariables: this.getEnvironmentVariables(), conversationVariables: this.getConversationVariables(), ragVariables: this.getRagVariables(), + readonly: this.getReadonly(), } } @@ -234,6 +247,7 @@ export function $createHITLInputNode( environmentVariables?: Var[], conversationVariables?: Var[], ragVariables?: Var[], + readonly?: boolean, ): HITLInputNode { return new HITLInputNode( variableName, @@ -247,6 +261,7 @@ export function $createHITLInputNode( environmentVariables, conversationVariables, ragVariables, + readonly, ) } diff --git a/web/app/components/base/prompt-editor/types.ts b/web/app/components/base/prompt-editor/types.ts index 1d5de9818b..99221ffebd 100644 --- a/web/app/components/base/prompt-editor/types.ts +++ b/web/app/components/base/prompt-editor/types.ts @@ -93,6 +93,7 @@ export type HITLInputBlockType = { onFormInputItemRename: (payload: FormInputItem, oldName: string) => void onInsert?: () => void onDelete?: () => void + readonly?: boolean } export type MenuTextMatch = { diff --git a/web/app/components/workflow/nodes/human-input/components/button-style-dropdown.tsx b/web/app/components/workflow/nodes/human-input/components/button-style-dropdown.tsx index d5032bf139..d3896049b5 100644 --- a/web/app/components/workflow/nodes/human-input/components/button-style-dropdown.tsx +++ b/web/app/components/workflow/nodes/human-input/components/button-style-dropdown.tsx @@ -20,12 +20,14 @@ type Props = { text: string data: UserActionButtonType onChange: (state: UserActionButtonType) => void + readonly?: boolean } const ButtonStyleDropdown: FC = ({ text = 'Button Text', data, onChange, + readonly, }) => { const { t } = useTranslation() const [open, setOpen] = useState(false) @@ -44,7 +46,7 @@ const ButtonStyleDropdown: FC = ({ return ( = ({ crossAxis: 44, }} > - setOpen(v => !v)}> -
+ !readonly && setOpen(v => !v)}> +
diff --git a/web/app/components/workflow/nodes/human-input/components/delivery-method/index.tsx b/web/app/components/workflow/nodes/human-input/components/delivery-method/index.tsx index 381d0971f5..3ce723bb07 100644 --- a/web/app/components/workflow/nodes/human-input/components/delivery-method/index.tsx +++ b/web/app/components/workflow/nodes/human-input/components/delivery-method/index.tsx @@ -19,6 +19,7 @@ type Props = { availableNodes?: Node[] formContent?: string onChange: (value: DeliveryMethod[]) => void + readonly?: boolean } const DeliveryMethodForm: React.FC = ({ @@ -28,6 +29,7 @@ const DeliveryMethodForm: React.FC = ({ availableNodes, formContent, onChange, + readonly, }) => { const { t } = useTranslation() @@ -59,12 +61,14 @@ const DeliveryMethodForm: React.FC = ({ popupContent={t(`${i18nPrefix}.deliveryMethod.tooltip`, { ns: 'workflow' })} />
-
- -
+ {!readonly && ( +
+ +
+ )}
{!value.length && (
{t(`${i18nPrefix}.deliveryMethod.emptyTip`, { ns: 'workflow' })}
@@ -81,6 +85,7 @@ const DeliveryMethodForm: React.FC = ({ nodesOutputVars={nodesOutputVars} availableNodes={availableNodes} formContent={formContent} + readonly={readonly} /> ))}
diff --git a/web/app/components/workflow/nodes/human-input/components/delivery-method/method-item.tsx b/web/app/components/workflow/nodes/human-input/components/delivery-method/method-item.tsx index d7e758dabc..def66c5b70 100644 --- a/web/app/components/workflow/nodes/human-input/components/delivery-method/method-item.tsx +++ b/web/app/components/workflow/nodes/human-input/components/delivery-method/method-item.tsx @@ -32,6 +32,7 @@ type Props = { formContent?: string onChange: (method: DeliveryMethod) => void onDelete: (type: DeliveryMethodType) => void + readonly?: boolean } const DeliveryMethodItem: React.FC = ({ @@ -42,6 +43,7 @@ const DeliveryMethodItem: React.FC = ({ formContent, onChange, onDelete, + readonly, }) => { const { t } = useTranslation() const [isHovering, setIsHovering] = React.useState(false) @@ -82,33 +84,36 @@ const DeliveryMethodItem: React.FC = ({ {method.type === DeliveryMethodType.Email && (method.config as EmailConfig)?.debug_mode && DEBUG}
-
- {method.type === DeliveryMethodType.Email && method.config && ( - <> - setShowTestEmailModal(true)}> - - - setShowEmailModal(true)}> - - - - )} -
setIsHovering(true)} - onMouseLeave={() => setIsHovering(false)} - > - onDelete(method.type)} + {!readonly && ( +
+ {method.type === DeliveryMethodType.Email && method.config && ( + <> + setShowTestEmailModal(true)}> + + + setShowEmailModal(true)}> + + + + )} +
setIsHovering(true)} + onMouseLeave={() => setIsHovering(false)} > - - + onDelete(method.type)} + > + + +
-
+ )} {(method.config || method.type === DeliveryMethodType.WebApp) && ( )} {method.type === DeliveryMethodType.Email && !method.config && ( @@ -116,6 +121,7 @@ const DeliveryMethodItem: React.FC = ({ className="-mr-1" size="small" onClick={() => setShowEmailModal(true)} + disabled={readonly} > {t(`${i18nPrefix}.deliveryMethod.notConfigured`, { ns: 'workflow' })} diff --git a/web/app/components/workflow/nodes/human-input/components/form-content.tsx b/web/app/components/workflow/nodes/human-input/components/form-content.tsx index 1e0517b003..3a1c4bc25d 100644 --- a/web/app/components/workflow/nodes/human-input/components/form-content.tsx +++ b/web/app/components/workflow/nodes/human-input/components/form-content.tsx @@ -27,6 +27,7 @@ type FormContentProps = { isExpand: boolean availableVars: NodeOutPutVar[] availableNodes: Node[] + readonly?: boolean } const Key: FC<{ children: React.ReactNode, className?: string }> = ({ children, className }) => { @@ -49,6 +50,7 @@ const FormContent: FC = ({ isExpand, availableVars, availableNodes, + readonly, }) => { const { t } = useTranslation() @@ -122,6 +124,7 @@ const FormContent: FC = ({ variables: availableVars || [], workflowNodesMap, getVarType, + readonly, }} workflowVariableBlock={{ show: true, @@ -129,17 +132,19 @@ const FormContent: FC = ({ getVarType: getVarType as any, workflowNodesMap, }} - editable - shortcutPopups={[{ - hotkey: ['mod', '/'], - Popup: ({ onClose, onInsert }) => ( - - ), - }]} + editable={!readonly} + shortcutPopups={readonly + ? [] + : [{ + hotkey: ['mod', '/'], + Popup: ({ onClose, onInsert }) => ( + + ), + }]} /> {isFocus && (
diff --git a/web/app/components/workflow/nodes/human-input/components/timeout.tsx b/web/app/components/workflow/nodes/human-input/components/timeout.tsx index 87c7e69810..a5ccf9556f 100644 --- a/web/app/components/workflow/nodes/human-input/components/timeout.tsx +++ b/web/app/components/workflow/nodes/human-input/components/timeout.tsx @@ -10,12 +10,14 @@ type Props = { timeout: number unit: 'day' | 'hour' onChange: (state: { timeout: number, unit: 'day' | 'hour' }) => void + readonly?: boolean } const TimeoutInput: FC = ({ timeout, unit, onChange, + readonly, }) => { const { t } = useTranslation() @@ -34,23 +36,28 @@ const TimeoutInput: FC = ({ value={timeout} min={1} onChange={handleValueChange} + disabled={readonly} />
onChange({ timeout, unit: 'day' })} + onClick={() => !readonly && onChange({ timeout, unit: 'day' })} >
{t(`${i18nPrefix}.timeout.days`, { ns: 'workflow' })}
onChange({ timeout, unit: 'hour' })} + onClick={() => !readonly && onChange({ timeout, unit: 'hour' })} >
{t(`${i18nPrefix}.timeout.hours`, { ns: 'workflow' })}
diff --git a/web/app/components/workflow/nodes/human-input/components/user-action.tsx b/web/app/components/workflow/nodes/human-input/components/user-action.tsx index e14040f66e..b109d6653e 100644 --- a/web/app/components/workflow/nodes/human-input/components/user-action.tsx +++ b/web/app/components/workflow/nodes/human-input/components/user-action.tsx @@ -16,12 +16,14 @@ type UserActionItemProps = { data: UserAction onChange: (state: UserAction) => void onDelete: (id: string) => void + readonly?: boolean } const UserActionItem: FC = ({ data, onChange, onDelete, + readonly, }) => { const { t } = useTranslation() @@ -47,6 +49,7 @@ const UserActionItem: FC = ({ value={data.id} placeholder={t(`${i18nPrefix}.userActions.actionNamePlaceholder`, { ns: 'workflow' })} onChange={handleIDChange} + disabled={readonly} />
@@ -54,20 +57,24 @@ const UserActionItem: FC = ({ value={data.title} placeholder={t(`${i18nPrefix}.userActions.buttonTextPlaceholder`, { ns: 'workflow' })} onChange={handleTextChange} + disabled={readonly} />
onChange({ ...data, button_style: type })} + readonly={readonly} /> - + {!readonly && ( + + )}
) } diff --git a/web/app/components/workflow/nodes/human-input/panel.tsx b/web/app/components/workflow/nodes/human-input/panel.tsx index 1a40dcaaec..81d923fafe 100644 --- a/web/app/components/workflow/nodes/human-input/panel.tsx +++ b/web/app/components/workflow/nodes/human-input/panel.tsx @@ -40,6 +40,7 @@ const Panel: FC> = ({ }) => { const { t } = useTranslation() const { + readOnly, inputs, handleDeliveryMethodChange, handleUserActionAdd, @@ -82,6 +83,7 @@ const Panel: FC> = ({ nodesOutputVars={availableVars} availableNodes={availableNodesWithParent} onChange={handleDeliveryMethodChange} + readonly={readOnly} />
@@ -95,35 +97,37 @@ const Panel: FC> = ({ popupContent={t(`${i18nPrefix}.formContent.tooltip`, { ns: 'workflow' })} />
-
- -
-
-
{ - copy(inputs.form_content) - Toast.notify({ type: 'success', message: t('actionMsg.copySuccessfully', { ns: 'common' }) }) - }} + {!readOnly && ( +
+
-
- {isExpandFormContent ? : } + +
{t(`${i18nPrefix}.formContent.preview`, { ns: 'workflow' })}
+ +
+
+
{ + copy(inputs.form_content) + Toast.notify({ type: 'success', message: t('actionMsg.copySuccessfully', { ns: 'common' }) }) + }} + > + +
+
+ {isExpandFormContent ? : } +
-
+ )}
> = ({ isExpand={isExpandFormContent} availableVars={availableVars} availableNodes={availableNodesWithParent} + readonly={readOnly} />
{/* user actions */} @@ -148,19 +153,21 @@ const Panel: FC> = ({ popupContent={t(`${i18nPrefix}.userActions.tooltip`, { ns: 'workflow' })} />
-
- { - handleUserActionAdd({ - id: genActionId(), - title: 'Button Text', - button_style: UserActionButtonType.Default, - }) - }} - > - - -
+ {!readOnly && ( +
+ { + handleUserActionAdd({ + id: genActionId(), + title: 'Button Text', + button_style: UserActionButtonType.Default, + }) + }} + > + + +
+ )}
{!inputs.user_actions.length && (
{t(`${i18nPrefix}.userActions.emptyTip`, { ns: 'workflow' })}
@@ -173,6 +180,7 @@ const Panel: FC> = ({ data={action} onChange={data => handleUserActionChange(index, data)} onDelete={handleUserActionDelete} + readonly={readOnly} /> ))} @@ -188,6 +196,7 @@ const Panel: FC> = ({ timeout={inputs.timeout} unit={inputs.timeout_unit} onChange={handleTimeoutChange} + readonly={readOnly} /> {/* output vars */}