mirror of
https://github.com/langgenius/dify.git
synced 2026-05-04 01:18:05 +08:00
chore(web): new lint setup (#30020)
Co-authored-by: yyh <yuanyouhuilyz@gmail.com>
This commit is contained in:
@ -1,17 +1,17 @@
|
||||
import type { EdgeProps } from 'reactflow'
|
||||
import {
|
||||
memo,
|
||||
useMemo,
|
||||
} from 'react'
|
||||
import type { EdgeProps } from 'reactflow'
|
||||
import {
|
||||
BaseEdge,
|
||||
Position,
|
||||
getBezierPath,
|
||||
Position,
|
||||
} from 'reactflow'
|
||||
import { NodeRunningStatus } from '@/app/components/workflow/types'
|
||||
import { getEdgeColor } from '@/app/components/workflow/utils'
|
||||
import CustomEdgeLinearGradientRender from '@/app/components/workflow/custom-edge-linear-gradient-render'
|
||||
import { ErrorHandleTypeEnum } from '@/app/components/workflow/nodes/_base/components/error-handle/types'
|
||||
import { NodeRunningStatus } from '@/app/components/workflow/types'
|
||||
import { getEdgeColor } from '@/app/components/workflow/utils'
|
||||
|
||||
const CustomEdge = ({
|
||||
id,
|
||||
@ -51,8 +51,9 @@ const CustomEdge = ({
|
||||
|| _targetRunningStatus === NodeRunningStatus.Exception
|
||||
|| _targetRunningStatus === NodeRunningStatus.Running
|
||||
)
|
||||
)
|
||||
) {
|
||||
return id
|
||||
}
|
||||
}, [_sourceRunningStatus, _targetRunningStatus, id])
|
||||
|
||||
const stroke = useMemo(() => {
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
import type { Node } from '@/app/components/workflow/types'
|
||||
import { useEffect } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useUpdateNodeInternals } from 'reactflow'
|
||||
import { NodeSourceHandle } from './node-handle'
|
||||
import { ErrorHandleTypeEnum } from '@/app/components/workflow/nodes/_base/components/error-handle/types'
|
||||
import type { Node } from '@/app/components/workflow/types'
|
||||
import { NodeRunningStatus } from '@/app/components/workflow/types'
|
||||
import { cn } from '@/utils/classnames'
|
||||
import { NodeSourceHandle } from './node-handle'
|
||||
|
||||
type ErrorHandleOnNodeProps = Pick<Node, 'id' | 'data'>
|
||||
const ErrorHandleOnNode = ({
|
||||
@ -25,18 +25,20 @@ const ErrorHandleOnNode = ({
|
||||
return null
|
||||
|
||||
return (
|
||||
<div className='relative px-3 pb-2 pt-1'>
|
||||
<div className="relative px-3 pb-2 pt-1">
|
||||
<div className={cn(
|
||||
'relative flex h-6 items-center justify-between rounded-md bg-workflow-block-parma-bg px-[5px]',
|
||||
data._runningStatus === NodeRunningStatus.Exception && 'border-[0.5px] border-components-badge-status-light-warning-halo bg-state-warning-hover',
|
||||
)}>
|
||||
<div className='system-xs-medium-uppercase text-text-tertiary'>
|
||||
)}
|
||||
>
|
||||
<div className="system-xs-medium-uppercase text-text-tertiary">
|
||||
{t('workflow.common.onFailure')}
|
||||
</div>
|
||||
<div className={cn(
|
||||
'system-xs-medium text-text-secondary',
|
||||
data._runningStatus === NodeRunningStatus.Exception && 'text-text-warning',
|
||||
)}>
|
||||
)}
|
||||
>
|
||||
{
|
||||
error_strategy === ErrorHandleTypeEnum.defaultValue && (
|
||||
t('workflow.nodes.common.errorHandle.defaultValue.output')
|
||||
@ -54,7 +56,7 @@ const ErrorHandleOnNode = ({
|
||||
id={id}
|
||||
data={data}
|
||||
handleId={ErrorHandleTypeEnum.failBranch}
|
||||
handleClassName='!top-1/2 !-right-[21px] !-translate-y-1/2 after:!bg-workflow-link-line-failure-button-bg'
|
||||
handleClassName="!top-1/2 !-right-[21px] !-translate-y-1/2 after:!bg-workflow-link-line-failure-button-bg"
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import type { Node } from '@/app/components/workflow/types'
|
||||
import {
|
||||
memo,
|
||||
} from 'react'
|
||||
@ -8,7 +9,6 @@ import {
|
||||
import {
|
||||
BlockEnum,
|
||||
} from '@/app/components/workflow/types'
|
||||
import type { Node } from '@/app/components/workflow/types'
|
||||
import { cn } from '@/utils/classnames'
|
||||
|
||||
type NodeHandleProps = {
|
||||
@ -27,7 +27,7 @@ export const NodeTargetHandle = memo(({
|
||||
<>
|
||||
<Handle
|
||||
id={handleId}
|
||||
type='target'
|
||||
type="target"
|
||||
position={Position.Left}
|
||||
className={cn(
|
||||
'z-[1] !h-4 !w-4 !rounded-none !border-none !bg-transparent !outline-none',
|
||||
@ -35,9 +35,9 @@ export const NodeTargetHandle = memo(({
|
||||
'transition-all hover:scale-125',
|
||||
!connected && 'after:opacity-0',
|
||||
(data.type === BlockEnum.Start
|
||||
|| data.type === BlockEnum.TriggerWebhook
|
||||
|| data.type === BlockEnum.TriggerSchedule
|
||||
|| data.type === BlockEnum.TriggerPlugin) && 'opacity-0',
|
||||
|| data.type === BlockEnum.TriggerWebhook
|
||||
|| data.type === BlockEnum.TriggerSchedule
|
||||
|| data.type === BlockEnum.TriggerPlugin) && 'opacity-0',
|
||||
handleClassName,
|
||||
)}
|
||||
>
|
||||
@ -57,7 +57,7 @@ export const NodeSourceHandle = memo(({
|
||||
return (
|
||||
<Handle
|
||||
id={handleId}
|
||||
type='source'
|
||||
type="source"
|
||||
position={Position.Right}
|
||||
className={cn(
|
||||
'group/handle z-[1] !h-4 !w-4 !rounded-none !border-none !bg-transparent !outline-none',
|
||||
|
||||
@ -1,27 +1,27 @@
|
||||
import type {
|
||||
ReactElement,
|
||||
} from 'react'
|
||||
import type { IterationNodeType } from '@/app/components/workflow/nodes/iteration/types'
|
||||
import type {
|
||||
NodeProps,
|
||||
} from '@/app/components/workflow/types'
|
||||
import {
|
||||
cloneElement,
|
||||
memo,
|
||||
} from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { cn } from '@/utils/classnames'
|
||||
import Tooltip from '@/app/components/base/tooltip'
|
||||
import BlockIcon from '@/app/components/workflow/block-icon'
|
||||
import type {
|
||||
NodeProps,
|
||||
} from '@/app/components/workflow/types'
|
||||
import {
|
||||
BlockEnum,
|
||||
} from '@/app/components/workflow/types'
|
||||
import { hasErrorHandleNode } from '@/app/components/workflow/utils'
|
||||
import Tooltip from '@/app/components/base/tooltip'
|
||||
import type { IterationNodeType } from '@/app/components/workflow/nodes/iteration/types'
|
||||
import { cn } from '@/utils/classnames'
|
||||
import ErrorHandleOnNode from '../error-handle-on-node'
|
||||
import {
|
||||
NodeSourceHandle,
|
||||
NodeTargetHandle,
|
||||
} from '../node-handle'
|
||||
import ErrorHandleOnNode from '../error-handle-on-node'
|
||||
|
||||
type NodeChildElement = ReactElement<Partial<NodeProps>>
|
||||
|
||||
@ -59,46 +59,48 @@ const BaseCard = ({
|
||||
>
|
||||
<div className={cn(
|
||||
'flex items-center rounded-t-2xl px-3 pb-2 pt-3',
|
||||
)}>
|
||||
)}
|
||||
>
|
||||
<NodeTargetHandle
|
||||
id={id}
|
||||
data={data}
|
||||
handleClassName='!top-4 !-left-[9px] !translate-y-0'
|
||||
handleId='target'
|
||||
handleClassName="!top-4 !-left-[9px] !translate-y-0"
|
||||
handleId="target"
|
||||
/>
|
||||
{
|
||||
data.type !== BlockEnum.IfElse && data.type !== BlockEnum.QuestionClassifier && (
|
||||
<NodeSourceHandle
|
||||
id={id}
|
||||
data={data}
|
||||
handleClassName='!top-4 !-right-[9px] !translate-y-0'
|
||||
handleId='source'
|
||||
handleClassName="!top-4 !-right-[9px] !translate-y-0"
|
||||
handleId="source"
|
||||
/>
|
||||
)
|
||||
}
|
||||
<BlockIcon
|
||||
className='mr-2 shrink-0'
|
||||
className="mr-2 shrink-0"
|
||||
type={data.type}
|
||||
size='md'
|
||||
size="md"
|
||||
/>
|
||||
<div
|
||||
title={data.title}
|
||||
className='system-sm-semibold-uppercase mr-1 flex grow items-center truncate text-text-primary'
|
||||
className="system-sm-semibold-uppercase mr-1 flex grow items-center truncate text-text-primary"
|
||||
>
|
||||
<div>
|
||||
{data.title}
|
||||
</div>
|
||||
{
|
||||
data.type === BlockEnum.Iteration && (data as IterationNodeType).is_parallel && (
|
||||
<Tooltip popupContent={
|
||||
<div className='w-[180px]'>
|
||||
<div className='font-extrabold'>
|
||||
<Tooltip popupContent={(
|
||||
<div className="w-[180px]">
|
||||
<div className="font-extrabold">
|
||||
{t('workflow.nodes.iteration.parallelModeEnableTitle')}
|
||||
</div>
|
||||
{t('workflow.nodes.iteration.parallelModeEnableDesc')}
|
||||
</div>}
|
||||
</div>
|
||||
)}
|
||||
>
|
||||
<div className='system-2xs-medium-uppercase ml-1 flex items-center justify-center rounded-[5px] border-[1px] border-text-warning px-[5px] py-[3px] text-text-warning '>
|
||||
<div className="system-2xs-medium-uppercase ml-1 flex items-center justify-center rounded-[5px] border-[1px] border-text-warning px-[5px] py-[3px] text-text-warning ">
|
||||
{t('workflow.nodes.iteration.parallelModeUpper')}
|
||||
</div>
|
||||
</Tooltip>
|
||||
@ -113,7 +115,7 @@ const BaseCard = ({
|
||||
}
|
||||
{
|
||||
(data.type === BlockEnum.Iteration || data.type === BlockEnum.Loop) && children && (
|
||||
<div className='h-[calc(100%-42px)] w-full grow pb-1 pl-1 pr-1'>
|
||||
<div className="h-[calc(100%-42px)] w-full grow pb-1 pl-1 pr-1">
|
||||
{cloneElement(children, { id, data })}
|
||||
</div>
|
||||
)
|
||||
@ -128,7 +130,7 @@ const BaseCard = ({
|
||||
}
|
||||
{
|
||||
data.desc && data.type !== BlockEnum.Iteration && data.type !== BlockEnum.Loop && (
|
||||
<div className='system-xs-regular whitespace-pre-line break-words px-3 pb-2 pt-1 text-text-tertiary'>
|
||||
<div className="system-xs-regular whitespace-pre-line break-words px-3 pb-2 pt-1 text-text-tertiary">
|
||||
{data.desc}
|
||||
</div>
|
||||
)
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
import { BlockEnum } from '@/app/components/workflow/types'
|
||||
import QuestionClassifierNode from './question-classifier/node'
|
||||
import IfElseNode from './if-else/node'
|
||||
import IterationNode from './iteration/node'
|
||||
import LoopNode from './loop/node'
|
||||
import QuestionClassifierNode from './question-classifier/node'
|
||||
|
||||
export const NodeComponentMap: Record<string, any> = {
|
||||
[BlockEnum.QuestionClassifier]: QuestionClassifierNode,
|
||||
|
||||
@ -1,12 +1,13 @@
|
||||
import type { FC } from 'react'
|
||||
import type { NodeProps } from 'reactflow'
|
||||
import type { Condition, IfElseNodeType } from '@/app/components/workflow/nodes/if-else/types'
|
||||
import React, { useCallback } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import type { NodeProps } from 'reactflow'
|
||||
import { NodeSourceHandle } from '../../node-handle'
|
||||
import { isEmptyRelatedOperator } from '@/app/components/workflow/nodes/if-else/utils'
|
||||
import type { Condition, IfElseNodeType } from '@/app/components/workflow/nodes/if-else/types'
|
||||
import ConditionValue from '@/app/components/workflow/nodes/if-else/components/condition-value'
|
||||
import ConditionFilesListValue from '@/app/components/workflow/nodes/if-else/components/condition-files-list-value'
|
||||
import ConditionValue from '@/app/components/workflow/nodes/if-else/components/condition-value'
|
||||
import { isEmptyRelatedOperator } from '@/app/components/workflow/nodes/if-else/utils'
|
||||
import { NodeSourceHandle } from '../../node-handle'
|
||||
|
||||
const i18nPrefix = 'workflow.nodes.ifElse'
|
||||
|
||||
const IfElseNode: FC<NodeProps<IfElseNodeType>> = (props) => {
|
||||
@ -37,50 +38,53 @@ const IfElseNode: FC<NodeProps<IfElseNodeType>> = (props) => {
|
||||
return !!condition.value
|
||||
}
|
||||
}, [])
|
||||
const conditionNotSet = (<div className='flex h-6 items-center space-x-1 rounded-md bg-workflow-block-parma-bg px-1 text-xs font-normal text-text-secondary'>
|
||||
{t(`${i18nPrefix}.conditionNotSetup`)}
|
||||
</div>)
|
||||
const conditionNotSet = (
|
||||
<div className="flex h-6 items-center space-x-1 rounded-md bg-workflow-block-parma-bg px-1 text-xs font-normal text-text-secondary">
|
||||
{t(`${i18nPrefix}.conditionNotSetup`)}
|
||||
</div>
|
||||
)
|
||||
|
||||
return (
|
||||
<div className='px-3'>
|
||||
<div className="px-3">
|
||||
{
|
||||
cases.map((caseItem, index) => (
|
||||
<div key={caseItem.case_id}>
|
||||
<div className='relative flex h-6 items-center px-1'>
|
||||
<div className='flex w-full items-center justify-between'>
|
||||
<div className='text-[10px] font-semibold text-text-tertiary'>
|
||||
<div className="relative flex h-6 items-center px-1">
|
||||
<div className="flex w-full items-center justify-between">
|
||||
<div className="text-[10px] font-semibold text-text-tertiary">
|
||||
{casesLength > 1 && `CASE ${index + 1}`}
|
||||
</div>
|
||||
<div className='text-[12px] font-semibold text-text-secondary'>{index === 0 ? 'IF' : 'ELIF'}</div>
|
||||
<div className="text-[12px] font-semibold text-text-secondary">{index === 0 ? 'IF' : 'ELIF'}</div>
|
||||
</div>
|
||||
<NodeSourceHandle
|
||||
{...props}
|
||||
handleId={caseItem.case_id}
|
||||
handleClassName='!top-1/2 !-right-[21px] !-translate-y-1/2'
|
||||
handleClassName="!top-1/2 !-right-[21px] !-translate-y-1/2"
|
||||
/>
|
||||
</div>
|
||||
<div className='space-y-0.5'>
|
||||
<div className="space-y-0.5">
|
||||
{caseItem.conditions.map((condition, i) => (
|
||||
<div key={condition.id} className='relative'>
|
||||
<div key={condition.id} className="relative">
|
||||
{
|
||||
checkIsConditionSet(condition)
|
||||
? (
|
||||
(!isEmptyRelatedOperator(condition.comparison_operator!) && condition.sub_variable_condition)
|
||||
? (
|
||||
<ConditionFilesListValue condition={condition} />
|
||||
)
|
||||
: (
|
||||
<ConditionValue
|
||||
variableSelector={condition.variable_selector!}
|
||||
operator={condition.comparison_operator!}
|
||||
value={condition.value}
|
||||
/>
|
||||
)
|
||||
(!isEmptyRelatedOperator(condition.comparison_operator!) && condition.sub_variable_condition)
|
||||
? (
|
||||
<ConditionFilesListValue condition={condition} />
|
||||
)
|
||||
: (
|
||||
<ConditionValue
|
||||
variableSelector={condition.variable_selector!}
|
||||
operator={condition.comparison_operator!}
|
||||
value={condition.value}
|
||||
/>
|
||||
)
|
||||
|
||||
)
|
||||
: conditionNotSet}
|
||||
)
|
||||
: conditionNotSet
|
||||
}
|
||||
{i !== caseItem.conditions.length - 1 && (
|
||||
<div className='absolute bottom-[-10px] right-1 z-10 text-[10px] font-medium uppercase leading-4 text-text-accent'>{t(`${i18nPrefix}.${caseItem.logical_operator}`)}</div>
|
||||
<div className="absolute bottom-[-10px] right-1 z-10 text-[10px] font-medium uppercase leading-4 text-text-accent">{t(`${i18nPrefix}.${caseItem.logical_operator}`)}</div>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
@ -88,12 +92,12 @@ const IfElseNode: FC<NodeProps<IfElseNodeType>> = (props) => {
|
||||
</div>
|
||||
))
|
||||
}
|
||||
<div className='relative flex h-6 items-center px-1'>
|
||||
<div className='w-full text-right text-xs font-semibold text-text-secondary'>ELSE</div>
|
||||
<div className="relative flex h-6 items-center px-1">
|
||||
<div className="w-full text-right text-xs font-semibold text-text-secondary">ELSE</div>
|
||||
<NodeSourceHandle
|
||||
{...props}
|
||||
handleId='false'
|
||||
handleClassName='!top-1/2 !-right-[21px] !-translate-y-1/2'
|
||||
handleId="false"
|
||||
handleClassName="!top-1/2 !-right-[21px] !-translate-y-1/2"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -8,7 +8,7 @@ const CustomNode = (props: NodeProps) => {
|
||||
|
||||
return (
|
||||
<>
|
||||
<BaseNode { ...props }>
|
||||
<BaseNode {...props}>
|
||||
{ NodeComponent && <NodeComponent /> }
|
||||
</BaseNode>
|
||||
</>
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { memo } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import type { NodeProps } from 'reactflow'
|
||||
import { RiHome5Fill } from '@remixicon/react'
|
||||
import { memo } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import Tooltip from '@/app/components/base/tooltip'
|
||||
import { NodeSourceHandle } from '../../node-handle'
|
||||
|
||||
@ -9,17 +9,17 @@ const IterationStartNode = ({ id, data }: NodeProps) => {
|
||||
const { t } = useTranslation()
|
||||
|
||||
return (
|
||||
<div className='nodrag group mt-1 flex h-11 w-11 items-center justify-center rounded-2xl border border-workflow-block-border bg-workflow-block-bg shadow-xs'>
|
||||
<div className="nodrag group mt-1 flex h-11 w-11 items-center justify-center rounded-2xl border border-workflow-block-border bg-workflow-block-bg shadow-xs">
|
||||
<Tooltip popupContent={t('workflow.blocks.iteration-start')} asChild={false}>
|
||||
<div className='flex h-6 w-6 items-center justify-center rounded-full border-[0.5px] border-components-panel-border-subtle bg-util-colors-blue-brand-blue-brand-500'>
|
||||
<RiHome5Fill className='h-3 w-3 text-text-primary-on-surface' />
|
||||
<div className="flex h-6 w-6 items-center justify-center rounded-full border-[0.5px] border-components-panel-border-subtle bg-util-colors-blue-brand-blue-brand-500">
|
||||
<RiHome5Fill className="h-3 w-3 text-text-primary-on-surface" />
|
||||
</div>
|
||||
</Tooltip>
|
||||
<NodeSourceHandle
|
||||
id={id}
|
||||
data={data}
|
||||
handleClassName='!top-1/2 !-right-[9px] !-translate-y-1/2'
|
||||
handleId='source'
|
||||
handleClassName="!top-1/2 !-right-[9px] !-translate-y-1/2"
|
||||
handleId="source"
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
|
||||
@ -1,4 +1,6 @@
|
||||
import type { FC } from 'react'
|
||||
import type { IterationNodeType } from '@/app/components/workflow/nodes/iteration/types'
|
||||
import type { NodeProps } from '@/app/components/workflow/types'
|
||||
import {
|
||||
memo,
|
||||
} from 'react'
|
||||
@ -6,9 +8,7 @@ import {
|
||||
Background,
|
||||
useViewport,
|
||||
} from 'reactflow'
|
||||
import type { IterationNodeType } from '@/app/components/workflow/nodes/iteration/types'
|
||||
import { cn } from '@/utils/classnames'
|
||||
import type { NodeProps } from '@/app/components/workflow/types'
|
||||
|
||||
const Node: FC<NodeProps<IterationNodeType>> = ({
|
||||
id,
|
||||
@ -18,13 +18,14 @@ const Node: FC<NodeProps<IterationNodeType>> = ({
|
||||
return (
|
||||
<div className={cn(
|
||||
'relative h-full min-h-[90px] w-full min-w-[240px] rounded-2xl bg-workflow-canvas-workflow-bg',
|
||||
)}>
|
||||
)}
|
||||
>
|
||||
<Background
|
||||
id={`iteration-background-${id}`}
|
||||
className='!z-0 rounded-2xl'
|
||||
className="!z-0 rounded-2xl"
|
||||
gap={[14 / zoom, 14 / zoom]}
|
||||
size={2 / zoom}
|
||||
color='var(--color-workflow-canvas-workflow-dot-color)'
|
||||
color="var(--color-workflow-canvas-workflow-dot-color)"
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { memo } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import type { NodeProps } from 'reactflow'
|
||||
import { RiHome5Fill } from '@remixicon/react'
|
||||
import { memo } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import Tooltip from '@/app/components/base/tooltip'
|
||||
import { NodeSourceHandle } from '../../node-handle'
|
||||
|
||||
@ -9,17 +9,17 @@ const LoopStartNode = ({ id, data }: NodeProps) => {
|
||||
const { t } = useTranslation()
|
||||
|
||||
return (
|
||||
<div className='nodrag group mt-1 flex h-11 w-11 items-center justify-center rounded-2xl border border-workflow-block-border bg-workflow-block-bg'>
|
||||
<div className="nodrag group mt-1 flex h-11 w-11 items-center justify-center rounded-2xl border border-workflow-block-border bg-workflow-block-bg">
|
||||
<Tooltip popupContent={t('workflow.blocks.loop-start')} asChild={false}>
|
||||
<div className='flex h-6 w-6 items-center justify-center rounded-full border-[0.5px] border-components-panel-border-subtle bg-util-colors-blue-brand-blue-brand-500'>
|
||||
<RiHome5Fill className='h-3 w-3 text-text-primary-on-surface' />
|
||||
<div className="flex h-6 w-6 items-center justify-center rounded-full border-[0.5px] border-components-panel-border-subtle bg-util-colors-blue-brand-blue-brand-500">
|
||||
<RiHome5Fill className="h-3 w-3 text-text-primary-on-surface" />
|
||||
</div>
|
||||
</Tooltip>
|
||||
<NodeSourceHandle
|
||||
id={id}
|
||||
data={data}
|
||||
handleClassName='!top-1/2 !-right-[9px] !-translate-y-1/2'
|
||||
handleId='source'
|
||||
handleClassName="!top-1/2 !-right-[9px] !-translate-y-1/2"
|
||||
handleId="source"
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
import { useCallback } from 'react'
|
||||
import { produce } from 'immer'
|
||||
import { useStoreApi } from 'reactflow'
|
||||
import type {
|
||||
Node,
|
||||
} from '@/app/components/workflow/types'
|
||||
import { produce } from 'immer'
|
||||
import { useCallback } from 'react'
|
||||
import { useStoreApi } from 'reactflow'
|
||||
import {
|
||||
LOOP_PADDING,
|
||||
} from '@/app/components/workflow/constants'
|
||||
|
||||
@ -1,4 +1,6 @@
|
||||
import type { FC } from 'react'
|
||||
import type { LoopNodeType } from '@/app/components/workflow/nodes/loop/types'
|
||||
import type { NodeProps } from '@/app/components/workflow/types'
|
||||
import {
|
||||
memo,
|
||||
useEffect,
|
||||
@ -8,9 +10,7 @@ import {
|
||||
useNodesInitialized,
|
||||
useViewport,
|
||||
} from 'reactflow'
|
||||
import type { LoopNodeType } from '@/app/components/workflow/nodes/loop/types'
|
||||
import { cn } from '@/utils/classnames'
|
||||
import type { NodeProps } from '@/app/components/workflow/types'
|
||||
import { useNodeLoopInteractions } from './hooks'
|
||||
|
||||
const Node: FC<NodeProps<LoopNodeType>> = ({
|
||||
@ -36,10 +36,10 @@ const Node: FC<NodeProps<LoopNodeType>> = ({
|
||||
>
|
||||
<Background
|
||||
id={`loop-background-${id}`}
|
||||
className='!z-0 rounded-2xl'
|
||||
className="!z-0 rounded-2xl"
|
||||
gap={[14 / zoom, 14 / zoom]}
|
||||
size={2 / zoom}
|
||||
color='var(--color-workflow-canvas-workflow-dot-color)'
|
||||
color="var(--color-workflow-canvas-workflow-dot-color)"
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
import type { FC } from 'react'
|
||||
import type { NodeProps } from 'reactflow'
|
||||
import type { QuestionClassifierNodeType } from '@/app/components/workflow/nodes/question-classifier/types'
|
||||
import React from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import type { NodeProps } from 'reactflow'
|
||||
import InfoPanel from '@/app/components/workflow/nodes/_base/components/info-panel'
|
||||
import type { QuestionClassifierNodeType } from '@/app/components/workflow/nodes/question-classifier/types'
|
||||
import { NodeSourceHandle } from '../../node-handle'
|
||||
|
||||
const i18nPrefix = 'workflow.nodes.questionClassifiers'
|
||||
@ -14,23 +14,23 @@ const Node: FC<NodeProps<QuestionClassifierNodeType>> = (props) => {
|
||||
const topics = data.classes
|
||||
|
||||
return (
|
||||
<div className='mb-1 px-3 py-1'>
|
||||
<div className="mb-1 px-3 py-1">
|
||||
{
|
||||
!!topics.length && (
|
||||
<div className='mt-2 space-y-0.5'>
|
||||
<div className="mt-2 space-y-0.5">
|
||||
{topics.map((topic, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className='relative'
|
||||
className="relative"
|
||||
>
|
||||
<InfoPanel
|
||||
title={`${t(`${i18nPrefix}.class`)} ${index + 1}`}
|
||||
content={''}
|
||||
content=""
|
||||
/>
|
||||
<NodeSourceHandle
|
||||
{...props}
|
||||
handleId={topic.id}
|
||||
handleClassName='!top-1/2 !-translate-y-1/2 !-right-[21px]'
|
||||
handleClassName="!top-1/2 !-translate-y-1/2 !-right-[21px]"
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
|
||||
@ -1,15 +1,15 @@
|
||||
import type { NodeProps } from 'reactflow'
|
||||
import type { NoteNodeType } from '@/app/components/workflow/note-node/types'
|
||||
import {
|
||||
memo,
|
||||
useRef,
|
||||
} from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import type { NodeProps } from 'reactflow'
|
||||
import { THEME_MAP } from '@/app/components/workflow/note-node/constants'
|
||||
import {
|
||||
NoteEditor,
|
||||
NoteEditorContextProvider,
|
||||
} from '@/app/components/workflow/note-node/note-editor'
|
||||
import { THEME_MAP } from '@/app/components/workflow/note-node/constants'
|
||||
import type { NoteNodeType } from '@/app/components/workflow/note-node/types'
|
||||
import { cn } from '@/utils/classnames'
|
||||
|
||||
const NoteNode = ({
|
||||
@ -41,11 +41,14 @@ const NoteNode = ({
|
||||
className={cn(
|
||||
'h-2 shrink-0 rounded-t-md opacity-50',
|
||||
THEME_MAP[theme].title,
|
||||
)}></div>
|
||||
<div className='grow overflow-y-auto px-3 py-2.5'>
|
||||
)}
|
||||
>
|
||||
</div>
|
||||
<div className="grow overflow-y-auto px-3 py-2.5">
|
||||
<div className={cn(
|
||||
data.selected && 'nodrag nopan nowheel cursor-text',
|
||||
)}>
|
||||
)}
|
||||
>
|
||||
<NoteEditor
|
||||
containerElement={ref.current}
|
||||
placeholder={t('workflow.nodes.note.editor.placeholder') || ''}
|
||||
@ -54,7 +57,7 @@ const NoteNode = ({
|
||||
</div>
|
||||
{
|
||||
data.showAuthor && (
|
||||
<div className='p-3 pt-0 text-xs text-text-tertiary'>
|
||||
<div className="p-3 pt-0 text-xs text-text-tertiary">
|
||||
{data.author}
|
||||
</div>
|
||||
)
|
||||
|
||||
@ -1,28 +1,28 @@
|
||||
import type { FC } from 'react'
|
||||
import {
|
||||
RiZoomInLine,
|
||||
RiZoomOutLine,
|
||||
} from '@remixicon/react'
|
||||
import {
|
||||
Fragment,
|
||||
memo,
|
||||
useCallback,
|
||||
useState,
|
||||
} from 'react'
|
||||
import {
|
||||
RiZoomInLine,
|
||||
RiZoomOutLine,
|
||||
} from '@remixicon/react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import {
|
||||
useReactFlow,
|
||||
useViewport,
|
||||
} from 'reactflow'
|
||||
import ShortcutsName from '@/app/components/workflow/shortcuts-name'
|
||||
import Divider from '@/app/components/base/divider'
|
||||
import TipPopup from '@/app/components/workflow/operator/tip-popup'
|
||||
import { cn } from '@/utils/classnames'
|
||||
import {
|
||||
PortalToFollowElem,
|
||||
PortalToFollowElemContent,
|
||||
PortalToFollowElemTrigger,
|
||||
} from '@/app/components/base/portal-to-follow-elem'
|
||||
import TipPopup from '@/app/components/workflow/operator/tip-popup'
|
||||
import ShortcutsName from '@/app/components/workflow/shortcuts-name'
|
||||
import { cn } from '@/utils/classnames'
|
||||
|
||||
enum ZoomType {
|
||||
zoomIn = 'zoomIn',
|
||||
@ -103,7 +103,7 @@ const ZoomInOut: FC = () => {
|
||||
|
||||
return (
|
||||
<PortalToFollowElem
|
||||
placement='top-start'
|
||||
placement="top-start"
|
||||
open={open}
|
||||
onOpenChange={setOpen}
|
||||
offset={{
|
||||
@ -121,7 +121,8 @@ const ZoomInOut: FC = () => {
|
||||
>
|
||||
<div className={cn(
|
||||
'flex h-8 w-[98px] items-center justify-between rounded-lg',
|
||||
)}>
|
||||
)}
|
||||
>
|
||||
<TipPopup
|
||||
title={t('workflow.operator.zoomOut')}
|
||||
shortcuts={['ctrl', '-']}
|
||||
@ -136,10 +137,13 @@ const ZoomInOut: FC = () => {
|
||||
zoomOut()
|
||||
}}
|
||||
>
|
||||
<RiZoomOutLine className='h-4 w-4 text-text-tertiary hover:text-text-secondary' />
|
||||
<RiZoomOutLine className="h-4 w-4 text-text-tertiary hover:text-text-secondary" />
|
||||
</div>
|
||||
</TipPopup>
|
||||
<div onClick={handleTrigger} className={cn('system-sm-medium w-[34px] text-text-tertiary hover:text-text-secondary')}>{Number.parseFloat(`${zoom * 100}`).toFixed(0)}%</div>
|
||||
<div onClick={handleTrigger} className={cn('system-sm-medium w-[34px] text-text-tertiary hover:text-text-secondary')}>
|
||||
{Number.parseFloat(`${zoom * 100}`).toFixed(0)}
|
||||
%
|
||||
</div>
|
||||
<TipPopup
|
||||
title={t('workflow.operator.zoomIn')}
|
||||
shortcuts={['ctrl', '+']}
|
||||
@ -154,32 +158,32 @@ const ZoomInOut: FC = () => {
|
||||
zoomIn()
|
||||
}}
|
||||
>
|
||||
<RiZoomInLine className='h-4 w-4 text-text-tertiary hover:text-text-secondary' />
|
||||
<RiZoomInLine className="h-4 w-4 text-text-tertiary hover:text-text-secondary" />
|
||||
</div>
|
||||
</TipPopup>
|
||||
</div>
|
||||
</div>
|
||||
</PortalToFollowElemTrigger>
|
||||
<PortalToFollowElemContent className='z-10'>
|
||||
<div className='w-[145px] rounded-xl border-[0.5px] border-components-panel-border bg-components-panel-bg-blur shadow-lg backdrop-blur-[5px]'>
|
||||
<PortalToFollowElemContent className="z-10">
|
||||
<div className="w-[145px] rounded-xl border-[0.5px] border-components-panel-border bg-components-panel-bg-blur shadow-lg backdrop-blur-[5px]">
|
||||
{
|
||||
ZOOM_IN_OUT_OPTIONS.map((options, i) => (
|
||||
<Fragment key={i}>
|
||||
{
|
||||
i !== 0 && (
|
||||
<Divider className='m-0' />
|
||||
<Divider className="m-0" />
|
||||
)
|
||||
}
|
||||
<div className='p-1'>
|
||||
<div className="p-1">
|
||||
{
|
||||
options.map(option => (
|
||||
<div
|
||||
key={option.key}
|
||||
className='system-md-regular flex h-8 cursor-pointer items-center justify-between space-x-1 rounded-lg py-1.5 pl-3 pr-2 text-text-secondary hover:bg-state-base-hover'
|
||||
className="system-md-regular flex h-8 cursor-pointer items-center justify-between space-x-1 rounded-lg py-1.5 pl-3 pr-2 text-text-secondary hover:bg-state-base-hover"
|
||||
onClick={() => handleZoom(option.key)}
|
||||
>
|
||||
<span>{option.text}</span>
|
||||
<div className='flex items-center space-x-0.5'>
|
||||
<div className="flex items-center space-x-0.5">
|
||||
{
|
||||
option.key === ZoomType.zoomToFit && (
|
||||
<ShortcutsName keys={['ctrl', '1']} />
|
||||
|
||||
Reference in New Issue
Block a user