mirror of
https://github.com/langgenius/dify.git
synced 2026-05-11 23:18:39 +08:00
feat(hitl-input): add readonly prop to HITL input components for enhanced user interaction control
This commit is contained in:
parent
a280df2c07
commit
b6c6d52725
@ -30,6 +30,7 @@ type HITLInputComponentUIProps = {
|
||||
nodeId: string
|
||||
valueSelector: ValueSelector
|
||||
}) => Type
|
||||
readonly?: boolean
|
||||
}
|
||||
|
||||
const HITLInputComponentUI: FC<HITLInputComponentUIProps> = ({
|
||||
@ -52,6 +53,7 @@ const HITLInputComponentUI: FC<HITLInputComponentUIProps> = ({
|
||||
environmentVariables,
|
||||
conversationVariables,
|
||||
ragVariables,
|
||||
readonly,
|
||||
}) => {
|
||||
const [isShowEditModal, {
|
||||
setTrue: showEditModal,
|
||||
@ -97,7 +99,7 @@ const HITLInputComponentUI: FC<HITLInputComponentUIProps> = ({
|
||||
|
||||
return (
|
||||
<div
|
||||
className="relative flex h-8 w-full select-none items-center rounded-[8px] border-[1.5px] border-components-input-border-active bg-background-default-hover pl-1.5 pr-0.5"
|
||||
className="group relative flex h-8 w-full select-none items-center rounded-[8px] border-[1.5px] border-components-input-border-active bg-background-default-hover pl-1.5 pr-0.5"
|
||||
>
|
||||
<div className="absolute left-2.5 top-[-12px]">
|
||||
<div className="absolute bottom-1 h-[1.5px] w-full bg-background-default-subtle"></div>
|
||||
@ -107,36 +109,40 @@ const HITLInputComponentUI: FC<HITLInputComponentUIProps> = ({
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex w-full items-center justify-between">
|
||||
{/* Placeholder Info */}
|
||||
{isPlaceholderVariable && (
|
||||
<VariableBlock
|
||||
variables={formInput.placeholder.selector}
|
||||
workflowNodesMap={workflowNodesMap}
|
||||
getVarType={getVarType}
|
||||
environmentVariables={environmentVariables}
|
||||
conversationVariables={conversationVariables}
|
||||
ragVariables={ragVariables}
|
||||
/>
|
||||
)}
|
||||
{!isPlaceholderVariable && (
|
||||
<div className="system-xs-medium text-text-quaternary">{formInput.placeholder.value}</div>
|
||||
)}
|
||||
<div className="flex w-full items-center gap-x-0.5">
|
||||
<div className="grow">
|
||||
{/* Placeholder Info */}
|
||||
{isPlaceholderVariable && (
|
||||
<VariableBlock
|
||||
variables={formInput.placeholder.selector}
|
||||
workflowNodesMap={workflowNodesMap}
|
||||
getVarType={getVarType}
|
||||
environmentVariables={environmentVariables}
|
||||
conversationVariables={conversationVariables}
|
||||
ragVariables={ragVariables}
|
||||
/>
|
||||
)}
|
||||
{!isPlaceholderVariable && (
|
||||
<div className="system-xs-medium text-text-quaternary">{formInput.placeholder.value}</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Actions */}
|
||||
<div className="flex h-full items-center space-x-1 pr-[24px]">
|
||||
<div className="flex h-full items-center" ref={editBtnRef}>
|
||||
<ActionButton size="s">
|
||||
<RiEditLine className="size-4 text-text-tertiary" />
|
||||
</ActionButton>
|
||||
</div>
|
||||
{!readonly && (
|
||||
<div className="hidden h-full shrink-0 items-center space-x-1 pr-[24px] group-hover:flex">
|
||||
<div className="flex h-full items-center" ref={editBtnRef}>
|
||||
<ActionButton size="s">
|
||||
<RiEditLine className="size-4 text-text-tertiary" />
|
||||
</ActionButton>
|
||||
</div>
|
||||
|
||||
<div className="flex h-full items-center" ref={removeBtnRef}>
|
||||
<ActionButton size="s">
|
||||
<RiDeleteBinLine className="size-4 text-text-tertiary" />
|
||||
</ActionButton>
|
||||
<div className="flex h-full items-center" ref={removeBtnRef}>
|
||||
<ActionButton size="s">
|
||||
<RiDeleteBinLine className="size-4 text-text-tertiary" />
|
||||
</ActionButton>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{isShowEditModal && (
|
||||
|
||||
@ -25,6 +25,7 @@ type HITLInputComponentProps = {
|
||||
nodeId: string
|
||||
valueSelector: ValueSelector
|
||||
}) => Type
|
||||
readonly?: boolean
|
||||
}
|
||||
|
||||
const HITLInputComponent: FC<HITLInputComponentProps> = ({
|
||||
@ -40,6 +41,7 @@ const HITLInputComponent: FC<HITLInputComponentProps> = ({
|
||||
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<HITLInputComponentProps> = ({
|
||||
environmentVariables={environmentVariables}
|
||||
conversationVariables={conversationVariables}
|
||||
ragVariables={ragVariables}
|
||||
readonly={readonly}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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])
|
||||
|
||||
@ -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<React.JSX.Element> {
|
||||
__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<React.JSX.Element> {
|
||||
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<React.JSX.Element> {
|
||||
node.__environmentVariables,
|
||||
node.__conversationVariables,
|
||||
node.__ragVariables,
|
||||
node.__readonly,
|
||||
node.__key,
|
||||
)
|
||||
}
|
||||
@ -135,6 +143,7 @@ export class HITLInputNode extends DecoratorNode<React.JSX.Element> {
|
||||
environmentVariables?: Var[],
|
||||
conversationVariables?: Var[],
|
||||
ragVariables?: Var[],
|
||||
readonly?: boolean,
|
||||
key?: NodeKey,
|
||||
) {
|
||||
super(key)
|
||||
@ -150,6 +159,7 @@ export class HITLInputNode extends DecoratorNode<React.JSX.Element> {
|
||||
this.__environmentVariables = environmentVariables
|
||||
this.__conversationVariables = conversationVariables
|
||||
this.__ragVariables = ragVariables
|
||||
this.__readonly = readonly
|
||||
}
|
||||
|
||||
createDOM(): HTMLElement {
|
||||
@ -177,6 +187,7 @@ export class HITLInputNode extends DecoratorNode<React.JSX.Element> {
|
||||
environmentVariables={this.getEnvironmentVariables()}
|
||||
conversationVariables={this.getConversationVariables()}
|
||||
ragVariables={this.getRagVariables()}
|
||||
readonly={this.getReadonly()}
|
||||
/>
|
||||
)
|
||||
}
|
||||
@ -194,6 +205,7 @@ export class HITLInputNode extends DecoratorNode<React.JSX.Element> {
|
||||
serializedNode.environmentVariables,
|
||||
serializedNode.conversationVariables,
|
||||
serializedNode.ragVariables,
|
||||
serializedNode.readonly,
|
||||
)
|
||||
|
||||
return node
|
||||
@ -214,6 +226,7 @@ export class HITLInputNode extends DecoratorNode<React.JSX.Element> {
|
||||
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,
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@ -93,6 +93,7 @@ export type HITLInputBlockType = {
|
||||
onFormInputItemRename: (payload: FormInputItem, oldName: string) => void
|
||||
onInsert?: () => void
|
||||
onDelete?: () => void
|
||||
readonly?: boolean
|
||||
}
|
||||
|
||||
export type MenuTextMatch = {
|
||||
|
||||
@ -20,12 +20,14 @@ type Props = {
|
||||
text: string
|
||||
data: UserActionButtonType
|
||||
onChange: (state: UserActionButtonType) => void
|
||||
readonly?: boolean
|
||||
}
|
||||
|
||||
const ButtonStyleDropdown: FC<Props> = ({
|
||||
text = 'Button Text',
|
||||
data,
|
||||
onChange,
|
||||
readonly,
|
||||
}) => {
|
||||
const { t } = useTranslation()
|
||||
const [open, setOpen] = useState(false)
|
||||
@ -44,7 +46,7 @@ const ButtonStyleDropdown: FC<Props> = ({
|
||||
|
||||
return (
|
||||
<PortalToFollowElem
|
||||
open={open}
|
||||
open={open && !readonly}
|
||||
onOpenChange={setOpen}
|
||||
placement="bottom-end"
|
||||
offset={{
|
||||
@ -52,8 +54,8 @@ const ButtonStyleDropdown: FC<Props> = ({
|
||||
crossAxis: 44,
|
||||
}}
|
||||
>
|
||||
<PortalToFollowElemTrigger onClick={() => setOpen(v => !v)}>
|
||||
<div className={cn('flex cursor-pointer items-center justify-center rounded-lg bg-components-button-tertiary-bg p-1 hover:bg-components-button-tertiary-bg-hover', open && 'bg-components-button-tertiary-bg-hover')}>
|
||||
<PortalToFollowElemTrigger onClick={() => !readonly && setOpen(v => !v)}>
|
||||
<div className={cn('flex items-center justify-center rounded-lg bg-components-button-tertiary-bg p-1', !readonly && 'cursor-pointer hover:bg-components-button-tertiary-bg-hover', open && 'bg-components-button-tertiary-bg-hover')}>
|
||||
<Button size="small" className="pointer-events-none px-1" variant={currentStyle}>
|
||||
<RiFontSize className="h-4 w-4" />
|
||||
</Button>
|
||||
|
||||
@ -19,6 +19,7 @@ type Props = {
|
||||
availableNodes?: Node[]
|
||||
formContent?: string
|
||||
onChange: (value: DeliveryMethod[]) => void
|
||||
readonly?: boolean
|
||||
}
|
||||
|
||||
const DeliveryMethodForm: React.FC<Props> = ({
|
||||
@ -28,6 +29,7 @@ const DeliveryMethodForm: React.FC<Props> = ({
|
||||
availableNodes,
|
||||
formContent,
|
||||
onChange,
|
||||
readonly,
|
||||
}) => {
|
||||
const { t } = useTranslation()
|
||||
|
||||
@ -59,12 +61,14 @@ const DeliveryMethodForm: React.FC<Props> = ({
|
||||
popupContent={t(`${i18nPrefix}.deliveryMethod.tooltip`, { ns: 'workflow' })}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex items-center px-1">
|
||||
<MethodSelector
|
||||
data={value}
|
||||
onAdd={handleMethodAdd}
|
||||
/>
|
||||
</div>
|
||||
{!readonly && (
|
||||
<div className="flex items-center px-1">
|
||||
<MethodSelector
|
||||
data={value}
|
||||
onAdd={handleMethodAdd}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
{!value.length && (
|
||||
<div className="system-xs-regular flex items-center justify-center rounded-[10px] bg-background-section p-3 text-text-tertiary">{t(`${i18nPrefix}.deliveryMethod.emptyTip`, { ns: 'workflow' })}</div>
|
||||
@ -81,6 +85,7 @@ const DeliveryMethodForm: React.FC<Props> = ({
|
||||
nodesOutputVars={nodesOutputVars}
|
||||
availableNodes={availableNodes}
|
||||
formContent={formContent}
|
||||
readonly={readonly}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
|
||||
@ -32,6 +32,7 @@ type Props = {
|
||||
formContent?: string
|
||||
onChange: (method: DeliveryMethod) => void
|
||||
onDelete: (type: DeliveryMethodType) => void
|
||||
readonly?: boolean
|
||||
}
|
||||
|
||||
const DeliveryMethodItem: React.FC<Props> = ({
|
||||
@ -42,6 +43,7 @@ const DeliveryMethodItem: React.FC<Props> = ({
|
||||
formContent,
|
||||
onChange,
|
||||
onDelete,
|
||||
readonly,
|
||||
}) => {
|
||||
const { t } = useTranslation()
|
||||
const [isHovering, setIsHovering] = React.useState(false)
|
||||
@ -82,33 +84,36 @@ const DeliveryMethodItem: React.FC<Props> = ({
|
||||
{method.type === DeliveryMethodType.Email && (method.config as EmailConfig)?.debug_mode && <Badge size="s" className="!px-1 !py-0.5">DEBUG</Badge>}
|
||||
</div>
|
||||
<div className="flex items-center gap-1">
|
||||
<div className="hidden items-end gap-1 group-hover:flex">
|
||||
{method.type === DeliveryMethodType.Email && method.config && (
|
||||
<>
|
||||
<ActionButton onClick={() => setShowTestEmailModal(true)}>
|
||||
<RiSendPlane2Line className="h-4 w-4" />
|
||||
</ActionButton>
|
||||
<ActionButton onClick={() => setShowEmailModal(true)}>
|
||||
<RiEqualizer2Line className="h-4 w-4" />
|
||||
</ActionButton>
|
||||
</>
|
||||
)}
|
||||
<div
|
||||
onMouseEnter={() => setIsHovering(true)}
|
||||
onMouseLeave={() => setIsHovering(false)}
|
||||
>
|
||||
<ActionButton
|
||||
state={isHovering ? ActionButtonState.Destructive : ActionButtonState.Default}
|
||||
onClick={() => onDelete(method.type)}
|
||||
{!readonly && (
|
||||
<div className="hidden items-end gap-1 group-hover:flex">
|
||||
{method.type === DeliveryMethodType.Email && method.config && (
|
||||
<>
|
||||
<ActionButton onClick={() => setShowTestEmailModal(true)}>
|
||||
<RiSendPlane2Line className="h-4 w-4" />
|
||||
</ActionButton>
|
||||
<ActionButton onClick={() => setShowEmailModal(true)}>
|
||||
<RiEqualizer2Line className="h-4 w-4" />
|
||||
</ActionButton>
|
||||
</>
|
||||
)}
|
||||
<div
|
||||
onMouseEnter={() => setIsHovering(true)}
|
||||
onMouseLeave={() => setIsHovering(false)}
|
||||
>
|
||||
<RiDeleteBinLine className="h-4 w-4" />
|
||||
</ActionButton>
|
||||
<ActionButton
|
||||
state={isHovering ? ActionButtonState.Destructive : ActionButtonState.Default}
|
||||
onClick={() => onDelete(method.type)}
|
||||
>
|
||||
<RiDeleteBinLine className="h-4 w-4" />
|
||||
</ActionButton>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{(method.config || method.type === DeliveryMethodType.WebApp) && (
|
||||
<Switch
|
||||
defaultValue={method.enabled}
|
||||
onChange={handleEnableStatusChange}
|
||||
disabled={readonly}
|
||||
/>
|
||||
)}
|
||||
{method.type === DeliveryMethodType.Email && !method.config && (
|
||||
@ -116,6 +121,7 @@ const DeliveryMethodItem: React.FC<Props> = ({
|
||||
className="-mr-1"
|
||||
size="small"
|
||||
onClick={() => setShowEmailModal(true)}
|
||||
disabled={readonly}
|
||||
>
|
||||
{t(`${i18nPrefix}.deliveryMethod.notConfigured`, { ns: 'workflow' })}
|
||||
<Indicator color="orange" className="ml-1" />
|
||||
|
||||
@ -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<FormContentProps> = ({
|
||||
isExpand,
|
||||
availableVars,
|
||||
availableNodes,
|
||||
readonly,
|
||||
}) => {
|
||||
const { t } = useTranslation()
|
||||
|
||||
@ -122,6 +124,7 @@ const FormContent: FC<FormContentProps> = ({
|
||||
variables: availableVars || [],
|
||||
workflowNodesMap,
|
||||
getVarType,
|
||||
readonly,
|
||||
}}
|
||||
workflowVariableBlock={{
|
||||
show: true,
|
||||
@ -129,17 +132,19 @@ const FormContent: FC<FormContentProps> = ({
|
||||
getVarType: getVarType as any,
|
||||
workflowNodesMap,
|
||||
}}
|
||||
editable
|
||||
shortcutPopups={[{
|
||||
hotkey: ['mod', '/'],
|
||||
Popup: ({ onClose, onInsert }) => (
|
||||
<AddInputField
|
||||
nodeId={nodeId}
|
||||
onSave={handleInsertHITLNode(onInsert!)}
|
||||
onCancel={onClose}
|
||||
/>
|
||||
),
|
||||
}]}
|
||||
editable={!readonly}
|
||||
shortcutPopups={readonly
|
||||
? []
|
||||
: [{
|
||||
hotkey: ['mod', '/'],
|
||||
Popup: ({ onClose, onInsert }) => (
|
||||
<AddInputField
|
||||
nodeId={nodeId}
|
||||
onSave={handleInsertHITLNode(onInsert!)}
|
||||
onCancel={onClose}
|
||||
/>
|
||||
),
|
||||
}]}
|
||||
/>
|
||||
{isFocus && (
|
||||
<div className="system-xs-regular flex h-8 shrink-0 items-center px-3 text-components-input-text-placeholder">
|
||||
|
||||
@ -10,12 +10,14 @@ type Props = {
|
||||
timeout: number
|
||||
unit: 'day' | 'hour'
|
||||
onChange: (state: { timeout: number, unit: 'day' | 'hour' }) => void
|
||||
readonly?: boolean
|
||||
}
|
||||
|
||||
const TimeoutInput: FC<Props> = ({
|
||||
timeout,
|
||||
unit,
|
||||
onChange,
|
||||
readonly,
|
||||
}) => {
|
||||
const { t } = useTranslation()
|
||||
|
||||
@ -34,23 +36,28 @@ const TimeoutInput: FC<Props> = ({
|
||||
value={timeout}
|
||||
min={1}
|
||||
onChange={handleValueChange}
|
||||
disabled={readonly}
|
||||
/>
|
||||
<div className="flex items-center gap-0.5 rounded-[10px] bg-components-segmented-control-bg-normal p-0.5">
|
||||
<div
|
||||
className={cn(
|
||||
'cursor-pointer rounded-lg px-2 py-1 text-text-tertiary hover:bg-state-base-hover hover:text-text-secondary',
|
||||
unit === 'day' && 'bg-components-segmented-control-item-active-bg text-text-accent-light-mode-only shadow-sm hover:bg-components-segmented-control-item-active-bg hover:text-text-accent-light-mode-only',
|
||||
'rounded-lg px-2 py-1 text-text-tertiary',
|
||||
!readonly && 'cursor-pointer hover:bg-state-base-hover hover:text-text-secondary',
|
||||
unit === 'day' && 'bg-components-segmented-control-item-active-bg text-text-accent-light-mode-only shadow-sm',
|
||||
!readonly && unit === 'day' && 'hover:bg-components-segmented-control-item-active-bg hover:text-text-accent-light-mode-only',
|
||||
)}
|
||||
onClick={() => onChange({ timeout, unit: 'day' })}
|
||||
onClick={() => !readonly && onChange({ timeout, unit: 'day' })}
|
||||
>
|
||||
<div className="system-sm-medium p-0.5">{t(`${i18nPrefix}.timeout.days`, { ns: 'workflow' })}</div>
|
||||
</div>
|
||||
<div
|
||||
className={cn(
|
||||
'cursor-pointer rounded-lg px-2 py-1 text-text-tertiary hover:bg-state-base-hover hover:text-text-secondary',
|
||||
unit === 'hour' && 'bg-components-segmented-control-item-active-bg text-text-accent-light-mode-only shadow-sm hover:bg-components-segmented-control-item-active-bg hover:text-text-accent-light-mode-only',
|
||||
'rounded-lg px-2 py-1 text-text-tertiary',
|
||||
!readonly && 'cursor-pointer hover:bg-state-base-hover hover:text-text-secondary',
|
||||
unit === 'hour' && 'bg-components-segmented-control-item-active-bg text-text-accent-light-mode-only shadow-sm',
|
||||
!readonly && unit === 'hour' && 'hover:bg-components-segmented-control-item-active-bg hover:text-text-accent-light-mode-only',
|
||||
)}
|
||||
onClick={() => onChange({ timeout, unit: 'hour' })}
|
||||
onClick={() => !readonly && onChange({ timeout, unit: 'hour' })}
|
||||
>
|
||||
<div className="system-sm-medium p-0.5">{t(`${i18nPrefix}.timeout.hours`, { ns: 'workflow' })}</div>
|
||||
</div>
|
||||
|
||||
@ -16,12 +16,14 @@ type UserActionItemProps = {
|
||||
data: UserAction
|
||||
onChange: (state: UserAction) => void
|
||||
onDelete: (id: string) => void
|
||||
readonly?: boolean
|
||||
}
|
||||
|
||||
const UserActionItem: FC<UserActionItemProps> = ({
|
||||
data,
|
||||
onChange,
|
||||
onDelete,
|
||||
readonly,
|
||||
}) => {
|
||||
const { t } = useTranslation()
|
||||
|
||||
@ -47,6 +49,7 @@ const UserActionItem: FC<UserActionItemProps> = ({
|
||||
value={data.id}
|
||||
placeholder={t(`${i18nPrefix}.userActions.actionNamePlaceholder`, { ns: 'workflow' })}
|
||||
onChange={handleIDChange}
|
||||
disabled={readonly}
|
||||
/>
|
||||
</div>
|
||||
<div className="grow">
|
||||
@ -54,20 +57,24 @@ const UserActionItem: FC<UserActionItemProps> = ({
|
||||
value={data.title}
|
||||
placeholder={t(`${i18nPrefix}.userActions.buttonTextPlaceholder`, { ns: 'workflow' })}
|
||||
onChange={handleTextChange}
|
||||
disabled={readonly}
|
||||
/>
|
||||
</div>
|
||||
<ButtonStyleDropdown
|
||||
text={data.title}
|
||||
data={data.button_style}
|
||||
onChange={type => onChange({ ...data, button_style: type })}
|
||||
readonly={readonly}
|
||||
/>
|
||||
<Button
|
||||
className="px-2"
|
||||
variant="tertiary"
|
||||
onClick={() => onDelete(data.id)}
|
||||
>
|
||||
<RiDeleteBinLine className="h-4 w-4" />
|
||||
</Button>
|
||||
{!readonly && (
|
||||
<Button
|
||||
className="px-2"
|
||||
variant="tertiary"
|
||||
onClick={() => onDelete(data.id)}
|
||||
>
|
||||
<RiDeleteBinLine className="h-4 w-4" />
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@ -40,6 +40,7 @@ const Panel: FC<NodePanelProps<HumanInputNodeType>> = ({
|
||||
}) => {
|
||||
const { t } = useTranslation()
|
||||
const {
|
||||
readOnly,
|
||||
inputs,
|
||||
handleDeliveryMethodChange,
|
||||
handleUserActionAdd,
|
||||
@ -82,6 +83,7 @@ const Panel: FC<NodePanelProps<HumanInputNodeType>> = ({
|
||||
nodesOutputVars={availableVars}
|
||||
availableNodes={availableNodesWithParent}
|
||||
onChange={handleDeliveryMethodChange}
|
||||
readonly={readOnly}
|
||||
/>
|
||||
<div className="px-4 py-2">
|
||||
<Divider className="!my-0 !h-px !bg-divider-subtle" />
|
||||
@ -95,35 +97,37 @@ const Panel: FC<NodePanelProps<HumanInputNodeType>> = ({
|
||||
popupContent={t(`${i18nPrefix}.formContent.tooltip`, { ns: 'workflow' })}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex items-center ">
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="small"
|
||||
className={cn(
|
||||
'flex items-center space-x-1 px-2',
|
||||
isPreview && 'bg-state-accent-active text-text-accent',
|
||||
)}
|
||||
onClick={togglePreview}
|
||||
>
|
||||
<RiEyeLine className="size-3.5" />
|
||||
<div className="system-xs-medium">{t(`${i18nPrefix}.formContent.preview`, { ns: 'workflow' })}</div>
|
||||
</Button>
|
||||
<div className="mx-2 h-3 w-px bg-divider-regular"></div>
|
||||
<div className="flex items-center space-x-1">
|
||||
<div
|
||||
className="flex size-6 cursor-pointer items-center justify-center rounded-md hover:bg-components-button-ghost-bg-hover"
|
||||
onClick={() => {
|
||||
copy(inputs.form_content)
|
||||
Toast.notify({ type: 'success', message: t('actionMsg.copySuccessfully', { ns: 'common' }) })
|
||||
}}
|
||||
{!readOnly && (
|
||||
<div className="flex items-center ">
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="small"
|
||||
className={cn(
|
||||
'flex items-center space-x-1 px-2',
|
||||
isPreview && 'bg-state-accent-active text-text-accent',
|
||||
)}
|
||||
onClick={togglePreview}
|
||||
>
|
||||
<RiClipboardLine className="h-4 w-4 text-text-secondary" />
|
||||
</div>
|
||||
<div className={cn('flex size-6 cursor-pointer items-center justify-center rounded-md text-text-secondary hover:bg-components-button-ghost-bg-hover', isExpandFormContent && 'bg-state-accent-active text-text-accent')} onClick={toggleExpandFormContent}>
|
||||
{isExpandFormContent ? <RiCollapseDiagonalLine className="h-4 w-4" /> : <RiExpandDiagonalLine className="h-4 w-4" />}
|
||||
<RiEyeLine className="size-3.5" />
|
||||
<div className="system-xs-medium">{t(`${i18nPrefix}.formContent.preview`, { ns: 'workflow' })}</div>
|
||||
</Button>
|
||||
<div className="mx-2 h-3 w-px bg-divider-regular"></div>
|
||||
<div className="flex items-center space-x-1">
|
||||
<div
|
||||
className="flex size-6 cursor-pointer items-center justify-center rounded-md hover:bg-components-button-ghost-bg-hover"
|
||||
onClick={() => {
|
||||
copy(inputs.form_content)
|
||||
Toast.notify({ type: 'success', message: t('actionMsg.copySuccessfully', { ns: 'common' }) })
|
||||
}}
|
||||
>
|
||||
<RiClipboardLine className="h-4 w-4 text-text-secondary" />
|
||||
</div>
|
||||
<div className={cn('flex size-6 cursor-pointer items-center justify-center rounded-md text-text-secondary hover:bg-components-button-ghost-bg-hover', isExpandFormContent && 'bg-state-accent-active text-text-accent')} onClick={toggleExpandFormContent}>
|
||||
{isExpandFormContent ? <RiCollapseDiagonalLine className="h-4 w-4" /> : <RiExpandDiagonalLine className="h-4 w-4" />}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<FormContent
|
||||
editorKey={editorKey}
|
||||
@ -137,6 +141,7 @@ const Panel: FC<NodePanelProps<HumanInputNodeType>> = ({
|
||||
isExpand={isExpandFormContent}
|
||||
availableVars={availableVars}
|
||||
availableNodes={availableNodesWithParent}
|
||||
readonly={readOnly}
|
||||
/>
|
||||
</div>
|
||||
{/* user actions */}
|
||||
@ -148,19 +153,21 @@ const Panel: FC<NodePanelProps<HumanInputNodeType>> = ({
|
||||
popupContent={t(`${i18nPrefix}.userActions.tooltip`, { ns: 'workflow' })}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex items-center px-1">
|
||||
<ActionButton
|
||||
onClick={() => {
|
||||
handleUserActionAdd({
|
||||
id: genActionId(),
|
||||
title: 'Button Text',
|
||||
button_style: UserActionButtonType.Default,
|
||||
})
|
||||
}}
|
||||
>
|
||||
<RiAddLine className="h-4 w-4" />
|
||||
</ActionButton>
|
||||
</div>
|
||||
{!readOnly && (
|
||||
<div className="flex items-center px-1">
|
||||
<ActionButton
|
||||
onClick={() => {
|
||||
handleUserActionAdd({
|
||||
id: genActionId(),
|
||||
title: 'Button Text',
|
||||
button_style: UserActionButtonType.Default,
|
||||
})
|
||||
}}
|
||||
>
|
||||
<RiAddLine className="h-4 w-4" />
|
||||
</ActionButton>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
{!inputs.user_actions.length && (
|
||||
<div className="system-xs-regular flex items-center justify-center rounded-[10px] bg-background-section p-3 text-text-tertiary">{t(`${i18nPrefix}.userActions.emptyTip`, { ns: 'workflow' })}</div>
|
||||
@ -173,6 +180,7 @@ const Panel: FC<NodePanelProps<HumanInputNodeType>> = ({
|
||||
data={action}
|
||||
onChange={data => handleUserActionChange(index, data)}
|
||||
onDelete={handleUserActionDelete}
|
||||
readonly={readOnly}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
@ -188,6 +196,7 @@ const Panel: FC<NodePanelProps<HumanInputNodeType>> = ({
|
||||
timeout={inputs.timeout}
|
||||
unit={inputs.timeout_unit}
|
||||
onChange={handleTimeoutChange}
|
||||
readonly={readOnly}
|
||||
/>
|
||||
</div>
|
||||
{/* output vars */}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user