mirror of
https://github.com/langgenius/dify.git
synced 2026-05-05 18:08:07 +08:00
chore(web): new lint setup (#30020)
Co-authored-by: yyh <yuanyouhuilyz@gmail.com>
This commit is contained in:
@ -1,11 +1,11 @@
|
||||
'use client'
|
||||
import type { FC } from 'react'
|
||||
import React from 'react'
|
||||
import {
|
||||
RiAddLine,
|
||||
} from '@remixicon/react'
|
||||
import { cn } from '@/utils/classnames'
|
||||
import React from 'react'
|
||||
import Button from '@/app/components/base/button'
|
||||
import { cn } from '@/utils/classnames'
|
||||
|
||||
type Props = {
|
||||
className?: string
|
||||
@ -21,11 +21,11 @@ const AddButton: FC<Props> = ({
|
||||
return (
|
||||
<Button
|
||||
className={cn('w-full', className)}
|
||||
variant='tertiary'
|
||||
size='medium'
|
||||
variant="tertiary"
|
||||
size="medium"
|
||||
onClick={onClick}
|
||||
>
|
||||
<RiAddLine className='mr-1 h-3.5 w-3.5' />
|
||||
<RiAddLine className="mr-1 h-3.5 w-3.5" />
|
||||
<div>{text}</div>
|
||||
</Button>
|
||||
)
|
||||
|
||||
@ -1,22 +1,22 @@
|
||||
import type {
|
||||
ValueSelector,
|
||||
Var,
|
||||
VarType,
|
||||
} from '../../../types'
|
||||
import { useClickAway } from 'ahooks'
|
||||
import {
|
||||
memo,
|
||||
useCallback,
|
||||
useMemo,
|
||||
useRef,
|
||||
} from 'react'
|
||||
import { useClickAway } from 'ahooks'
|
||||
import { useStore } from '../../../store'
|
||||
import {
|
||||
useIsChatMode,
|
||||
useNodeDataUpdate,
|
||||
useWorkflow,
|
||||
useWorkflowVariables,
|
||||
} from '../../../hooks'
|
||||
import type {
|
||||
ValueSelector,
|
||||
Var,
|
||||
VarType,
|
||||
} from '../../../types'
|
||||
import { useStore } from '../../../store'
|
||||
import { useVariableAssigner } from '../../variable-assigner/hooks'
|
||||
import { filterVar } from '../../variable-assigner/utils'
|
||||
import AddVariablePopup from './add-variable-popup'
|
||||
@ -112,7 +112,7 @@ const AddVariablePopupWithPosition = ({
|
||||
|
||||
return (
|
||||
<div
|
||||
className='absolute z-10'
|
||||
className="absolute z-10"
|
||||
style={{
|
||||
left: showAssignVariablePopup.x,
|
||||
top: showAssignVariablePopup.y,
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
import { memo } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import VarReferenceVars from '@/app/components/workflow/nodes/_base/components/variable/var-reference-vars'
|
||||
import type {
|
||||
NodeOutPutVar,
|
||||
ValueSelector,
|
||||
Var,
|
||||
} from '@/app/components/workflow/types'
|
||||
import { memo } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import VarReferenceVars from '@/app/components/workflow/nodes/_base/components/variable/var-reference-vars'
|
||||
|
||||
export type AddVariablePopupProps = {
|
||||
availableVars: NodeOutPutVar[]
|
||||
@ -18,11 +18,11 @@ export const AddVariablePopup = ({
|
||||
const { t } = useTranslation()
|
||||
|
||||
return (
|
||||
<div className='w-[240px] rounded-lg border-[0.5px] border-components-panel-border bg-components-panel-bg shadow-lg'>
|
||||
<div className='flex h-[34px] items-center border-b-[0.5px] border-b-divider-regular px-4 text-[13px] font-semibold text-text-secondary'>
|
||||
<div className="w-[240px] rounded-lg border-[0.5px] border-components-panel-border bg-components-panel-bg shadow-lg">
|
||||
<div className="flex h-[34px] items-center border-b-[0.5px] border-b-divider-regular px-4 text-[13px] font-semibold text-text-secondary">
|
||||
{t('workflow.nodes.variableAssigner.setAssignVariable')}
|
||||
</div>
|
||||
<div className='p-1'>
|
||||
<div className="p-1">
|
||||
<VarReferenceVars
|
||||
hideSearch
|
||||
vars={availableVars}
|
||||
|
||||
@ -1,59 +1,62 @@
|
||||
import { PortalToFollowElem, PortalToFollowElemContent, PortalToFollowElemTrigger } from '@/app/components/base/portal-to-follow-elem'
|
||||
import type { ReactNode } from 'react'
|
||||
import { memo, useEffect, useMemo, useRef, useState } from 'react'
|
||||
import type { Strategy } from './agent-strategy'
|
||||
import { cn } from '@/utils/classnames'
|
||||
import { RiArrowDownSLine, RiErrorWarningFill } from '@remixicon/react'
|
||||
import Tooltip from '@/app/components/base/tooltip'
|
||||
import Link from 'next/link'
|
||||
import { InstallPluginButton } from './install-plugin-button'
|
||||
import ViewTypeSelect, { ViewType } from '../../../block-selector/view-type-select'
|
||||
import SearchInput from '@/app/components/base/search-input'
|
||||
import Tools from '../../../block-selector/tools'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useStrategyProviders } from '@/service/use-strategy'
|
||||
import { PluginCategoryEnum, type StrategyPluginDetail } from '@/app/components/plugins/types'
|
||||
import type { ToolWithProvider } from '../../../types'
|
||||
import { CollectionType } from '@/app/components/tools/types'
|
||||
import useGetIcon from '@/app/components/plugins/install-plugin/base/use-get-icon'
|
||||
import { useStrategyInfo } from '../../agent/use-config'
|
||||
import { SwitchPluginVersion } from './switch-plugin-version'
|
||||
import type { ListRef } from '@/app/components/workflow/block-selector/market-place-plugin/list'
|
||||
import PluginList, { type ListProps } from '@/app/components/workflow/block-selector/market-place-plugin/list'
|
||||
import { useMarketplacePlugins } from '@/app/components/plugins/marketplace/hooks'
|
||||
import type { Strategy } from './agent-strategy'
|
||||
import type { StrategyPluginDetail } from '@/app/components/plugins/types'
|
||||
import type { ListProps, ListRef } from '@/app/components/workflow/block-selector/market-place-plugin/list'
|
||||
import { RiArrowDownSLine, RiErrorWarningFill } from '@remixicon/react'
|
||||
import Link from 'next/link'
|
||||
import { memo, useEffect, useMemo, useRef, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { PortalToFollowElem, PortalToFollowElemContent, PortalToFollowElemTrigger } from '@/app/components/base/portal-to-follow-elem'
|
||||
import SearchInput from '@/app/components/base/search-input'
|
||||
import Tooltip from '@/app/components/base/tooltip'
|
||||
import { ToolTipContent } from '@/app/components/base/tooltip/content'
|
||||
import useGetIcon from '@/app/components/plugins/install-plugin/base/use-get-icon'
|
||||
import { useMarketplacePlugins } from '@/app/components/plugins/marketplace/hooks'
|
||||
import { PluginCategoryEnum } from '@/app/components/plugins/types'
|
||||
import { CollectionType } from '@/app/components/tools/types'
|
||||
import PluginList from '@/app/components/workflow/block-selector/market-place-plugin/list'
|
||||
import { useGlobalPublicStore } from '@/context/global-public-context'
|
||||
import { useStrategyProviders } from '@/service/use-strategy'
|
||||
import { cn } from '@/utils/classnames'
|
||||
import Tools from '../../../block-selector/tools'
|
||||
import ViewTypeSelect, { ViewType } from '../../../block-selector/view-type-select'
|
||||
import { useStrategyInfo } from '../../agent/use-config'
|
||||
import { InstallPluginButton } from './install-plugin-button'
|
||||
import { SwitchPluginVersion } from './switch-plugin-version'
|
||||
|
||||
const DEFAULT_TAGS: ListProps['tags'] = []
|
||||
|
||||
const NotFoundWarn = (props: {
|
||||
title: ReactNode,
|
||||
title: ReactNode
|
||||
description: ReactNode
|
||||
}) => {
|
||||
const { title, description } = props
|
||||
|
||||
const { t } = useTranslation()
|
||||
return <Tooltip
|
||||
popupContent={
|
||||
<div className='space-y-1 text-xs'>
|
||||
<h3 className='font-semibold text-text-primary'>
|
||||
{title}
|
||||
</h3>
|
||||
<p className='tracking-tight text-text-secondary'>
|
||||
{description}
|
||||
</p>
|
||||
<p>
|
||||
<Link href={'/plugins'} className='tracking-tight text-text-accent'>
|
||||
{t('workflow.nodes.agent.linkToPlugin')}
|
||||
</Link>
|
||||
</p>
|
||||
return (
|
||||
<Tooltip
|
||||
popupContent={(
|
||||
<div className="space-y-1 text-xs">
|
||||
<h3 className="font-semibold text-text-primary">
|
||||
{title}
|
||||
</h3>
|
||||
<p className="tracking-tight text-text-secondary">
|
||||
{description}
|
||||
</p>
|
||||
<p>
|
||||
<Link href="/plugins" className="tracking-tight text-text-accent">
|
||||
{t('workflow.nodes.agent.linkToPlugin')}
|
||||
</Link>
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
>
|
||||
<div>
|
||||
<RiErrorWarningFill className="size-4 text-text-destructive" />
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<div>
|
||||
<RiErrorWarningFill className='size-4 text-text-destructive' />
|
||||
</div>
|
||||
</Tooltip>
|
||||
</Tooltip>
|
||||
)
|
||||
}
|
||||
|
||||
function formatStrategy(input: StrategyPluginDetail[], getIcon: (i: string) => string): ToolWithProvider[] {
|
||||
@ -87,9 +90,9 @@ function formatStrategy(input: StrategyPluginDetail[], getIcon: (i: string) => s
|
||||
}
|
||||
|
||||
export type AgentStrategySelectorProps = {
|
||||
value?: Strategy,
|
||||
onChange: (value?: Strategy) => void,
|
||||
canChooseMCPTool: boolean,
|
||||
value?: Strategy
|
||||
onChange: (value?: Strategy) => void
|
||||
canChooseMCPTool: boolean
|
||||
}
|
||||
|
||||
export const AgentStrategySelector = memo((props: AgentStrategySelectorProps) => {
|
||||
@ -103,7 +106,8 @@ export const AgentStrategySelector = memo((props: AgentStrategySelectorProps) =>
|
||||
const { getIconUrl } = useGetIcon()
|
||||
const list = stra.data ? formatStrategy(stra.data, getIconUrl) : undefined
|
||||
const filteredTools = useMemo(() => {
|
||||
if (!list) return []
|
||||
if (!list)
|
||||
return []
|
||||
return list.filter(tool => tool.name.toLowerCase().includes(query.toLowerCase()))
|
||||
}, [query, list])
|
||||
const { strategyStatus, refetch: refetchStrategyInfo } = useStrategyInfo(
|
||||
@ -136,7 +140,8 @@ export const AgentStrategySelector = memo((props: AgentStrategySelectorProps) =>
|
||||
} = useMarketplacePlugins()
|
||||
|
||||
useEffect(() => {
|
||||
if (!enable_marketplace) return
|
||||
if (!enable_marketplace)
|
||||
return
|
||||
if (query) {
|
||||
fetchPlugins({
|
||||
query,
|
||||
@ -147,97 +152,115 @@ export const AgentStrategySelector = memo((props: AgentStrategySelectorProps) =>
|
||||
|
||||
const pluginRef = useRef<ListRef>(null)
|
||||
|
||||
return <PortalToFollowElem open={open} onOpenChange={setOpen} placement='bottom'>
|
||||
<PortalToFollowElemTrigger className='w-full'>
|
||||
<div
|
||||
className='flex h-8 w-full select-none items-center gap-0.5 rounded-lg bg-components-input-bg-normal p-1 hover:bg-state-base-hover-alt'
|
||||
onClick={() => setOpen(o => !o)}
|
||||
>
|
||||
{ }
|
||||
{icon && <div className='flex h-6 w-6 items-center justify-center'><img
|
||||
src={icon}
|
||||
width={20}
|
||||
height={20}
|
||||
className='rounded-md border-[0.5px] border-components-panel-border-subtle bg-background-default-dodge'
|
||||
alt='icon'
|
||||
/></div>}
|
||||
<p
|
||||
className={cn(value ? 'text-components-input-text-filled' : 'text-components-input-text-placeholder', 'px-1 text-xs')}
|
||||
return (
|
||||
<PortalToFollowElem open={open} onOpenChange={setOpen} placement="bottom">
|
||||
<PortalToFollowElemTrigger className="w-full">
|
||||
<div
|
||||
className="flex h-8 w-full select-none items-center gap-0.5 rounded-lg bg-components-input-bg-normal p-1 hover:bg-state-base-hover-alt"
|
||||
onClick={() => setOpen(o => !o)}
|
||||
>
|
||||
{value?.agent_strategy_label || t('workflow.nodes.agent.strategy.selectTip')}
|
||||
</p>
|
||||
<div className='ml-auto flex items-center gap-1'>
|
||||
{showInstallButton && value && <InstallPluginButton
|
||||
onClick={e => e.stopPropagation()}
|
||||
size={'small'}
|
||||
uniqueIdentifier={value.plugin_unique_identifier}
|
||||
/>}
|
||||
{showPluginNotInstalledWarn
|
||||
? <NotFoundWarn
|
||||
title={t('workflow.nodes.agent.pluginNotInstalled')}
|
||||
description={t('workflow.nodes.agent.pluginNotInstalledDesc')}
|
||||
/>
|
||||
: showUnsupportedStrategy
|
||||
? <NotFoundWarn
|
||||
title={t('workflow.nodes.agent.unsupportedStrategy')}
|
||||
description={t('workflow.nodes.agent.strategyNotFoundDesc')}
|
||||
{ }
|
||||
{icon && (
|
||||
<div className="flex h-6 w-6 items-center justify-center">
|
||||
<img
|
||||
src={icon}
|
||||
width={20}
|
||||
height={20}
|
||||
className="rounded-md border-[0.5px] border-components-panel-border-subtle bg-background-default-dodge"
|
||||
alt="icon"
|
||||
/>
|
||||
: <RiArrowDownSLine className='size-4 text-text-tertiary' />
|
||||
}
|
||||
{showSwitchVersion && <SwitchPluginVersion
|
||||
uniqueIdentifier={value.plugin_unique_identifier}
|
||||
tooltip={<ToolTipContent
|
||||
title={t('workflow.nodes.agent.unsupportedStrategy')}>
|
||||
{t('workflow.nodes.agent.strategyNotFoundDescAndSwitchVersion')}
|
||||
</ToolTipContent>}
|
||||
onChange={() => {
|
||||
refetchStrategyInfo()
|
||||
}}
|
||||
/>}
|
||||
</div>
|
||||
)}
|
||||
<p
|
||||
className={cn(value ? 'text-components-input-text-filled' : 'text-components-input-text-placeholder', 'px-1 text-xs')}
|
||||
>
|
||||
{value?.agent_strategy_label || t('workflow.nodes.agent.strategy.selectTip')}
|
||||
</p>
|
||||
<div className="ml-auto flex items-center gap-1">
|
||||
{showInstallButton && value && (
|
||||
<InstallPluginButton
|
||||
onClick={e => e.stopPropagation()}
|
||||
size="small"
|
||||
uniqueIdentifier={value.plugin_unique_identifier}
|
||||
/>
|
||||
)}
|
||||
{showPluginNotInstalledWarn
|
||||
? (
|
||||
<NotFoundWarn
|
||||
title={t('workflow.nodes.agent.pluginNotInstalled')}
|
||||
description={t('workflow.nodes.agent.pluginNotInstalledDesc')}
|
||||
/>
|
||||
)
|
||||
: showUnsupportedStrategy
|
||||
? (
|
||||
<NotFoundWarn
|
||||
title={t('workflow.nodes.agent.unsupportedStrategy')}
|
||||
description={t('workflow.nodes.agent.strategyNotFoundDesc')}
|
||||
/>
|
||||
)
|
||||
: <RiArrowDownSLine className="size-4 text-text-tertiary" />}
|
||||
{showSwitchVersion && (
|
||||
<SwitchPluginVersion
|
||||
uniqueIdentifier={value.plugin_unique_identifier}
|
||||
tooltip={(
|
||||
<ToolTipContent
|
||||
title={t('workflow.nodes.agent.unsupportedStrategy')}
|
||||
>
|
||||
{t('workflow.nodes.agent.strategyNotFoundDescAndSwitchVersion')}
|
||||
</ToolTipContent>
|
||||
)}
|
||||
onChange={() => {
|
||||
refetchStrategyInfo()
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</PortalToFollowElemTrigger>
|
||||
<PortalToFollowElemContent className='z-10'>
|
||||
<div className='w-[388px] overflow-hidden rounded-md border-[0.5px] border-components-panel-border bg-components-panel-bg-blur shadow'>
|
||||
<header className='flex gap-1 p-2'>
|
||||
<SearchInput placeholder={t('workflow.nodes.agent.strategy.searchPlaceholder')} value={query} onChange={setQuery} className={'w-full'} />
|
||||
<ViewTypeSelect viewType={viewType} onChange={setViewType} />
|
||||
</header>
|
||||
<main className="relative flex w-full flex-col overflow-hidden md:max-h-[300px] xl:max-h-[400px] 2xl:max-h-[564px]" ref={wrapElemRef}>
|
||||
<Tools
|
||||
tools={filteredTools}
|
||||
viewType={viewType}
|
||||
onSelect={(_, tool) => {
|
||||
onChange({
|
||||
agent_strategy_name: tool!.tool_name,
|
||||
agent_strategy_provider_name: tool!.provider_name,
|
||||
agent_strategy_label: tool!.tool_label,
|
||||
agent_output_schema: tool!.output_schema || {},
|
||||
plugin_unique_identifier: tool!.provider_id,
|
||||
meta: tool!.meta,
|
||||
})
|
||||
setOpen(false)
|
||||
}}
|
||||
className='h-full max-h-full max-w-none overflow-y-auto'
|
||||
indexBarClassName='top-0 xl:top-36'
|
||||
hasSearchText={false}
|
||||
canNotSelectMultiple
|
||||
canChooseMCPTool={canChooseMCPTool}
|
||||
isAgent
|
||||
/>
|
||||
{enable_marketplace && <PluginList
|
||||
ref={pluginRef}
|
||||
wrapElemRef={wrapElemRef}
|
||||
list={notInstalledPlugins}
|
||||
searchText={query}
|
||||
tags={DEFAULT_TAGS}
|
||||
category={PluginCategoryEnum.agent}
|
||||
disableMaxWidth
|
||||
/>}
|
||||
</main>
|
||||
</div>
|
||||
</PortalToFollowElemContent>
|
||||
</PortalToFollowElem>
|
||||
</PortalToFollowElemTrigger>
|
||||
<PortalToFollowElemContent className="z-10">
|
||||
<div className="w-[388px] overflow-hidden rounded-md border-[0.5px] border-components-panel-border bg-components-panel-bg-blur shadow">
|
||||
<header className="flex gap-1 p-2">
|
||||
<SearchInput placeholder={t('workflow.nodes.agent.strategy.searchPlaceholder')} value={query} onChange={setQuery} className="w-full" />
|
||||
<ViewTypeSelect viewType={viewType} onChange={setViewType} />
|
||||
</header>
|
||||
<main className="relative flex w-full flex-col overflow-hidden md:max-h-[300px] xl:max-h-[400px] 2xl:max-h-[564px]" ref={wrapElemRef}>
|
||||
<Tools
|
||||
tools={filteredTools}
|
||||
viewType={viewType}
|
||||
onSelect={(_, tool) => {
|
||||
onChange({
|
||||
agent_strategy_name: tool!.tool_name,
|
||||
agent_strategy_provider_name: tool!.provider_name,
|
||||
agent_strategy_label: tool!.tool_label,
|
||||
agent_output_schema: tool!.output_schema || {},
|
||||
plugin_unique_identifier: tool!.provider_id,
|
||||
meta: tool!.meta,
|
||||
})
|
||||
setOpen(false)
|
||||
}}
|
||||
className="h-full max-h-full max-w-none overflow-y-auto"
|
||||
indexBarClassName="top-0 xl:top-36"
|
||||
hasSearchText={false}
|
||||
canNotSelectMultiple
|
||||
canChooseMCPTool={canChooseMCPTool}
|
||||
isAgent
|
||||
/>
|
||||
{enable_marketplace && (
|
||||
<PluginList
|
||||
ref={pluginRef}
|
||||
wrapElemRef={wrapElemRef}
|
||||
list={notInstalledPlugins}
|
||||
searchText={query}
|
||||
tags={DEFAULT_TAGS}
|
||||
category={PluginCategoryEnum.agent}
|
||||
disableMaxWidth
|
||||
/>
|
||||
)}
|
||||
</main>
|
||||
</div>
|
||||
</PortalToFollowElemContent>
|
||||
</PortalToFollowElem>
|
||||
)
|
||||
})
|
||||
|
||||
AgentStrategySelector.displayName = 'AgentStrategySelector'
|
||||
|
||||
@ -1,28 +1,29 @@
|
||||
import type { CredentialFormSchemaNumberInput, CredentialFormSchemaTextInput } from '@/app/components/header/account-setting/model-provider-page/declarations'
|
||||
import { type CredentialFormSchema, FormTypeEnum, ModelTypeEnum } from '@/app/components/header/account-setting/model-provider-page/declarations'
|
||||
import type { ToolVarInputs } from '../../tool/types'
|
||||
import ListEmpty from '@/app/components/base/list-empty'
|
||||
import { AgentStrategySelector } from './agent-strategy-selector'
|
||||
import Link from 'next/link'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import Form from '@/app/components/header/account-setting/model-provider-page/model-modal/Form'
|
||||
import { Agent } from '@/app/components/base/icons/src/vender/workflow'
|
||||
import { InputNumber } from '@/app/components/base/input-number'
|
||||
import Slider from '@/app/components/base/slider'
|
||||
import ToolSelector from '@/app/components/plugins/plugin-detail-panel/tool-selector'
|
||||
import MultipleToolSelector from '@/app/components/plugins/plugin-detail-panel/multiple-tool-selector'
|
||||
import Field from './field'
|
||||
import { type ComponentProps, memo } from 'react'
|
||||
import { useDefaultModel } from '@/app/components/header/account-setting/model-provider-page/hooks'
|
||||
import Editor from './prompt/editor'
|
||||
import { useWorkflowStore } from '../../../store'
|
||||
import { useRenderI18nObject } from '@/hooks/use-i18n'
|
||||
import type { NodeOutPutVar } from '../../../types'
|
||||
import type { ComponentProps } from 'react'
|
||||
import type { Node } from 'reactflow'
|
||||
import type { NodeOutPutVar } from '../../../types'
|
||||
import type { ToolVarInputs } from '../../tool/types'
|
||||
import type { CredentialFormSchema, CredentialFormSchemaNumberInput, CredentialFormSchemaTextInput } from '@/app/components/header/account-setting/model-provider-page/declarations'
|
||||
import type { PluginMeta } from '@/app/components/plugins/types'
|
||||
import { noop } from 'lodash-es'
|
||||
import Link from 'next/link'
|
||||
import { memo } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { Agent } from '@/app/components/base/icons/src/vender/workflow'
|
||||
import { InputNumber } from '@/app/components/base/input-number'
|
||||
import ListEmpty from '@/app/components/base/list-empty'
|
||||
import Slider from '@/app/components/base/slider'
|
||||
import { FormTypeEnum, ModelTypeEnum } from '@/app/components/header/account-setting/model-provider-page/declarations'
|
||||
import { useDefaultModel } from '@/app/components/header/account-setting/model-provider-page/hooks'
|
||||
import Form from '@/app/components/header/account-setting/model-provider-page/model-modal/Form'
|
||||
import MultipleToolSelector from '@/app/components/plugins/plugin-detail-panel/multiple-tool-selector'
|
||||
import ToolSelector from '@/app/components/plugins/plugin-detail-panel/tool-selector'
|
||||
import { useDocLink } from '@/context/i18n'
|
||||
import { useRenderI18nObject } from '@/hooks/use-i18n'
|
||||
import { AppModeEnum } from '@/types/app'
|
||||
import { useWorkflowStore } from '../../../store'
|
||||
import { AgentStrategySelector } from './agent-strategy-selector'
|
||||
import Field from './field'
|
||||
import Editor from './prompt/editor'
|
||||
|
||||
export type Strategy = {
|
||||
agent_strategy_provider_name: string
|
||||
@ -39,8 +40,8 @@ export type AgentStrategyProps = {
|
||||
formSchema: CredentialFormSchema[]
|
||||
formValue: ToolVarInputs
|
||||
onFormValueChange: (value: ToolVarInputs) => void
|
||||
nodeOutputVars?: NodeOutPutVar[],
|
||||
availableNodes?: Node[],
|
||||
nodeOutputVars?: NodeOutPutVar[]
|
||||
availableNodes?: Node[]
|
||||
nodeId?: string
|
||||
canChooseMCPTool: boolean
|
||||
}
|
||||
@ -78,38 +79,41 @@ export const AgentStrategy = memo((props: AgentStrategyProps) => {
|
||||
onChange(value)
|
||||
setControlPromptEditorRerenderKey(Math.random())
|
||||
}
|
||||
return <Editor
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
onGenerated={handleGenerated}
|
||||
instanceId={instanceId}
|
||||
key={instanceId}
|
||||
title={renderI18nObject(schema.label)}
|
||||
headerClassName='bg-transparent px-0 text-text-secondary system-sm-semibold-uppercase'
|
||||
containerBackgroundClassName='bg-transparent'
|
||||
gradientBorder={false}
|
||||
nodeId={nodeId}
|
||||
isSupportPromptGenerator={!!def.auto_generate?.type}
|
||||
titleTooltip={schema.tooltip && renderI18nObject(schema.tooltip)}
|
||||
editorContainerClassName='px-0 bg-components-input-bg-normal focus-within:bg-components-input-bg-active rounded-lg'
|
||||
availableNodes={availableNodes}
|
||||
nodesOutputVars={nodeOutputVars}
|
||||
isSupportJinja={def.template?.enabled}
|
||||
required={def.required}
|
||||
varList={[]}
|
||||
modelConfig={
|
||||
defaultModel.data
|
||||
? {
|
||||
mode: AppModeEnum.CHAT,
|
||||
name: defaultModel.data.model,
|
||||
provider: defaultModel.data.provider.provider,
|
||||
completion_params: {},
|
||||
} : undefined
|
||||
}
|
||||
placeholderClassName='px-2 py-1'
|
||||
titleClassName='system-sm-semibold-uppercase text-text-secondary text-[13px]'
|
||||
inputClassName='px-2 py-1'
|
||||
/>
|
||||
return (
|
||||
<Editor
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
onGenerated={handleGenerated}
|
||||
instanceId={instanceId}
|
||||
key={instanceId}
|
||||
title={renderI18nObject(schema.label)}
|
||||
headerClassName="bg-transparent px-0 text-text-secondary system-sm-semibold-uppercase"
|
||||
containerBackgroundClassName="bg-transparent"
|
||||
gradientBorder={false}
|
||||
nodeId={nodeId}
|
||||
isSupportPromptGenerator={!!def.auto_generate?.type}
|
||||
titleTooltip={schema.tooltip && renderI18nObject(schema.tooltip)}
|
||||
editorContainerClassName="px-0 bg-components-input-bg-normal focus-within:bg-components-input-bg-active rounded-lg"
|
||||
availableNodes={availableNodes}
|
||||
nodesOutputVars={nodeOutputVars}
|
||||
isSupportJinja={def.template?.enabled}
|
||||
required={def.required}
|
||||
varList={[]}
|
||||
modelConfig={
|
||||
defaultModel.data
|
||||
? {
|
||||
mode: AppModeEnum.CHAT,
|
||||
name: defaultModel.data.model,
|
||||
provider: defaultModel.data.provider.provider,
|
||||
completion_params: {},
|
||||
}
|
||||
: undefined
|
||||
}
|
||||
placeholderClassName="px-2 py-1"
|
||||
titleClassName="system-sm-semibold-uppercase text-text-secondary text-[13px]"
|
||||
inputClassName="px-2 py-1"
|
||||
/>
|
||||
)
|
||||
}
|
||||
case FormTypeEnum.textNumber: {
|
||||
const def = schema as CredentialFormSchemaNumberInput
|
||||
@ -121,34 +125,40 @@ export const AgentStrategy = memo((props: AgentStrategyProps) => {
|
||||
const onChange = (value: number) => {
|
||||
props.onChange({ ...props.value, [schema.variable]: value })
|
||||
}
|
||||
return <Field
|
||||
title={<>
|
||||
{renderI18nObject(def.label)} {def.required && <span className='text-red-500'>*</span>}
|
||||
</>}
|
||||
key={def.variable}
|
||||
tooltip={def.tooltip && renderI18nObject(def.tooltip)}
|
||||
inline
|
||||
>
|
||||
<div className='flex w-[200px] items-center gap-3'>
|
||||
<Slider
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
className='w-full'
|
||||
min={def.min}
|
||||
max={def.max}
|
||||
/>
|
||||
<InputNumber
|
||||
value={value}
|
||||
// TODO: maybe empty, handle this
|
||||
onChange={onChange as any}
|
||||
defaultValue={defaultValue}
|
||||
size='regular'
|
||||
min={def.min}
|
||||
max={def.max}
|
||||
className='w-12'
|
||||
/>
|
||||
</div>
|
||||
</Field>
|
||||
return (
|
||||
<Field
|
||||
title={(
|
||||
<>
|
||||
{renderI18nObject(def.label)}
|
||||
{' '}
|
||||
{def.required && <span className="text-red-500">*</span>}
|
||||
</>
|
||||
)}
|
||||
key={def.variable}
|
||||
tooltip={def.tooltip && renderI18nObject(def.tooltip)}
|
||||
inline
|
||||
>
|
||||
<div className="flex w-[200px] items-center gap-3">
|
||||
<Slider
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
className="w-full"
|
||||
min={def.min}
|
||||
max={def.max}
|
||||
/>
|
||||
<InputNumber
|
||||
value={value}
|
||||
// TODO: maybe empty, handle this
|
||||
onChange={onChange as any}
|
||||
defaultValue={defaultValue}
|
||||
size="regular"
|
||||
min={def.min}
|
||||
max={def.max}
|
||||
className="w-12"
|
||||
/>
|
||||
</div>
|
||||
</Field>
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -162,9 +172,13 @@ export const AgentStrategy = memo((props: AgentStrategyProps) => {
|
||||
}
|
||||
return (
|
||||
<Field
|
||||
title={<>
|
||||
{renderI18nObject(schema.label)} {schema.required && <span className='text-red-500'>*</span>}
|
||||
</>}
|
||||
title={(
|
||||
<>
|
||||
{renderI18nObject(schema.label)}
|
||||
{' '}
|
||||
{schema.required && <span className="text-red-500">*</span>}
|
||||
</>
|
||||
)}
|
||||
tooltip={schema.tooltip && renderI18nObject(schema.tooltip)}
|
||||
>
|
||||
<ToolSelector
|
||||
@ -204,46 +218,59 @@ export const AgentStrategy = memo((props: AgentStrategyProps) => {
|
||||
}
|
||||
}
|
||||
}
|
||||
return <div className='space-y-2'>
|
||||
<AgentStrategySelector value={strategy} onChange={onStrategyChange} canChooseMCPTool={canChooseMCPTool} />
|
||||
{
|
||||
strategy
|
||||
? <div>
|
||||
<Form<CustomField>
|
||||
formSchemas={[
|
||||
...formSchema,
|
||||
]}
|
||||
value={formValue}
|
||||
onChange={onFormValueChange}
|
||||
validating={false}
|
||||
showOnVariableMap={{}}
|
||||
isEditMode={true}
|
||||
isAgentStrategy={true}
|
||||
fieldLabelClassName='uppercase'
|
||||
customRenderField={renderField}
|
||||
override={override}
|
||||
nodeId={nodeId}
|
||||
nodeOutputVars={nodeOutputVars || []}
|
||||
availableNodes={availableNodes || []}
|
||||
canChooseMCPTool={canChooseMCPTool}
|
||||
/>
|
||||
</div>
|
||||
: <ListEmpty
|
||||
icon={<Agent className='h-5 w-5 shrink-0 text-text-accent' />}
|
||||
title={t('workflow.nodes.agent.strategy.configureTip')}
|
||||
description={<div className='text-xs text-text-tertiary'>
|
||||
{t('workflow.nodes.agent.strategy.configureTipDesc')} <br />
|
||||
<Link href={docLink('/guides/workflow/node/agent#select-an-agent-strategy', {
|
||||
'zh-Hans': '/guides/workflow/node/agent#选择-agent-策略',
|
||||
'ja-JP': '/guides/workflow/node/agent#エージェント戦略の選択',
|
||||
})}
|
||||
className='text-text-accent-secondary' target='_blank'>
|
||||
{t('workflow.nodes.agent.learnMore')}
|
||||
</Link>
|
||||
</div>}
|
||||
/>
|
||||
}
|
||||
</div>
|
||||
return (
|
||||
<div className="space-y-2">
|
||||
<AgentStrategySelector value={strategy} onChange={onStrategyChange} canChooseMCPTool={canChooseMCPTool} />
|
||||
{
|
||||
strategy
|
||||
? (
|
||||
<div>
|
||||
<Form<CustomField>
|
||||
formSchemas={[
|
||||
...formSchema,
|
||||
]}
|
||||
value={formValue}
|
||||
onChange={onFormValueChange}
|
||||
validating={false}
|
||||
showOnVariableMap={{}}
|
||||
isEditMode={true}
|
||||
isAgentStrategy={true}
|
||||
fieldLabelClassName="uppercase"
|
||||
customRenderField={renderField}
|
||||
override={override}
|
||||
nodeId={nodeId}
|
||||
nodeOutputVars={nodeOutputVars || []}
|
||||
availableNodes={availableNodes || []}
|
||||
canChooseMCPTool={canChooseMCPTool}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
: (
|
||||
<ListEmpty
|
||||
icon={<Agent className="h-5 w-5 shrink-0 text-text-accent" />}
|
||||
title={t('workflow.nodes.agent.strategy.configureTip')}
|
||||
description={(
|
||||
<div className="text-xs text-text-tertiary">
|
||||
{t('workflow.nodes.agent.strategy.configureTipDesc')}
|
||||
{' '}
|
||||
<br />
|
||||
<Link
|
||||
href={docLink('/guides/workflow/node/agent#select-an-agent-strategy', {
|
||||
'zh-Hans': '/guides/workflow/node/agent#选择-agent-策略',
|
||||
'ja-JP': '/guides/workflow/node/agent#エージェント戦略の選択',
|
||||
})}
|
||||
className="text-text-accent-secondary"
|
||||
target="_blank"
|
||||
>
|
||||
{t('workflow.nodes.agent.learnMore')}
|
||||
</Link>
|
||||
</div>
|
||||
)}
|
||||
/>
|
||||
)
|
||||
}
|
||||
</div>
|
||||
)
|
||||
})
|
||||
|
||||
AgentStrategy.displayName = 'AgentStrategy'
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
'use client'
|
||||
import Checkbox from '@/app/components/base/checkbox'
|
||||
import type { FC } from 'react'
|
||||
import React, { useCallback } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import Checkbox from '@/app/components/base/checkbox'
|
||||
|
||||
type Props = {
|
||||
name: string
|
||||
@ -22,15 +22,15 @@ const BoolInput: FC<Props> = ({
|
||||
onChange(!value)
|
||||
}, [value, onChange])
|
||||
return (
|
||||
<div className='flex h-6 items-center gap-2'>
|
||||
<div className="flex h-6 items-center gap-2">
|
||||
<Checkbox
|
||||
className='!h-4 !w-4'
|
||||
className="!h-4 !w-4"
|
||||
checked={!!value}
|
||||
onCheck={handleChange}
|
||||
/>
|
||||
<div className='system-sm-medium flex items-center gap-1 text-text-secondary'>
|
||||
<div className="system-sm-medium flex items-center gap-1 text-text-secondary">
|
||||
{name}
|
||||
{!required && <span className='system-xs-regular text-text-tertiary'>{t('workflow.panel.optional')}</span>}
|
||||
{!required && <span className="system-xs-regular text-text-tertiary">{t('workflow.panel.optional')}</span>}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
@ -1,31 +1,31 @@
|
||||
'use client'
|
||||
import type { FC } from 'react'
|
||||
import React, { useCallback, useMemo } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { produce } from 'immer'
|
||||
import type { InputVar } from '../../../../types'
|
||||
import type { FileEntity } from '@/app/components/base/file-uploader/types'
|
||||
import {
|
||||
RiDeleteBinLine,
|
||||
} from '@remixicon/react'
|
||||
import type { InputVar } from '../../../../types'
|
||||
import { BlockEnum, InputVarType, SupportUploadFileTypes } from '../../../../types'
|
||||
import CodeEditor from '../editor/code-editor'
|
||||
import { CodeLanguage } from '../../../code/types'
|
||||
import TextEditor from '../editor/text-editor'
|
||||
import Select from '@/app/components/base/select'
|
||||
import Input from '@/app/components/base/input'
|
||||
import Textarea from '@/app/components/base/textarea'
|
||||
import TextGenerationImageUploader from '@/app/components/base/image-uploader/text-generation-image-uploader'
|
||||
import { produce } from 'immer'
|
||||
import React, { useCallback, useMemo } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { FileUploaderInAttachmentWrapper } from '@/app/components/base/file-uploader'
|
||||
import { Resolution, TransferMethod } from '@/types/app'
|
||||
import { VarBlockIcon } from '@/app/components/workflow/block-icon'
|
||||
import { Line3 } from '@/app/components/base/icons/src/public/common'
|
||||
import { Variable02 } from '@/app/components/base/icons/src/vender/solid/development'
|
||||
import { BubbleX } from '@/app/components/base/icons/src/vender/line/others'
|
||||
import { Variable02 } from '@/app/components/base/icons/src/vender/solid/development'
|
||||
import TextGenerationImageUploader from '@/app/components/base/image-uploader/text-generation-image-uploader'
|
||||
import Input from '@/app/components/base/input'
|
||||
import { FILE_EXTS } from '@/app/components/base/prompt-editor/constants'
|
||||
import { cn } from '@/utils/classnames'
|
||||
import type { FileEntity } from '@/app/components/base/file-uploader/types'
|
||||
import BoolInput from './bool-input'
|
||||
import Select from '@/app/components/base/select'
|
||||
import Textarea from '@/app/components/base/textarea'
|
||||
import { VarBlockIcon } from '@/app/components/workflow/block-icon'
|
||||
import { useHooksStore } from '@/app/components/workflow/hooks-store'
|
||||
import { Resolution, TransferMethod } from '@/types/app'
|
||||
import { cn } from '@/utils/classnames'
|
||||
import { BlockEnum, InputVarType, SupportUploadFileTypes } from '../../../../types'
|
||||
import { CodeLanguage } from '../../../code/types'
|
||||
import CodeEditor from '../editor/code-editor'
|
||||
import TextEditor from '../editor/text-editor'
|
||||
import BoolInput from './bool-input'
|
||||
|
||||
type Props = {
|
||||
payload: InputVar
|
||||
@ -69,22 +69,22 @@ const FormItem: FC<Props> = ({
|
||||
if (typeof payload.label === 'object') {
|
||||
const { nodeType, nodeName, variable, isChatVar } = payload.label
|
||||
return (
|
||||
<div className='flex h-full items-center'>
|
||||
<div className="flex h-full items-center">
|
||||
{!isChatVar && (
|
||||
<div className='flex items-center'>
|
||||
<div className='p-[1px]'>
|
||||
<div className="flex items-center">
|
||||
<div className="p-[1px]">
|
||||
<VarBlockIcon type={nodeType || BlockEnum.Start} />
|
||||
</div>
|
||||
<div className='mx-0.5 max-w-[150px] truncate text-xs font-medium text-gray-700' title={nodeName}>
|
||||
<div className="mx-0.5 max-w-[150px] truncate text-xs font-medium text-gray-700" title={nodeName}>
|
||||
{nodeName}
|
||||
</div>
|
||||
<Line3 className='mr-0.5'></Line3>
|
||||
<Line3 className="mr-0.5"></Line3>
|
||||
</div>
|
||||
)}
|
||||
<div className='flex items-center text-primary-600'>
|
||||
{!isChatVar && <Variable02 className='h-3.5 w-3.5' />}
|
||||
{isChatVar && <BubbleX className='h-3.5 w-3.5 text-util-colors-teal-teal-700' />}
|
||||
<div className={cn('ml-0.5 max-w-[150px] truncate text-xs font-medium', isChatVar && 'text-text-secondary')} title={variable} >
|
||||
<div className="flex items-center text-primary-600">
|
||||
{!isChatVar && <Variable02 className="h-3.5 w-3.5" />}
|
||||
{isChatVar && <BubbleX className="h-3.5 w-3.5 text-util-colors-teal-teal-700" />}
|
||||
<div className={cn('ml-0.5 max-w-[150px] truncate text-xs font-medium', isChatVar && 'text-text-secondary')} title={variable}>
|
||||
{variable}
|
||||
</div>
|
||||
</div>
|
||||
@ -117,24 +117,26 @@ const FormItem: FC<Props> = ({
|
||||
return (
|
||||
<div className={cn(className)}>
|
||||
{!isArrayLikeType && !isBooleanType && (
|
||||
<div className='system-sm-semibold mb-1 flex h-6 items-center gap-1 text-text-secondary'>
|
||||
<div className='truncate'>
|
||||
<div className="system-sm-semibold mb-1 flex h-6 items-center gap-1 text-text-secondary">
|
||||
<div className="truncate">
|
||||
{typeof payload.label === 'object' ? nodeKey : payload.label}
|
||||
</div>
|
||||
{payload.hide === true ? (
|
||||
<span className='system-xs-regular text-text-tertiary'>
|
||||
{t('workflow.panel.optional_and_hidden')}
|
||||
</span>
|
||||
) : (
|
||||
!payload.required && (
|
||||
<span className='system-xs-regular text-text-tertiary'>
|
||||
{t('workflow.panel.optional')}
|
||||
</span>
|
||||
)
|
||||
)}
|
||||
{payload.hide === true
|
||||
? (
|
||||
<span className="system-xs-regular text-text-tertiary">
|
||||
{t('workflow.panel.optional_and_hidden')}
|
||||
</span>
|
||||
)
|
||||
: (
|
||||
!payload.required && (
|
||||
<span className="system-xs-regular text-text-tertiary">
|
||||
{t('workflow.panel.optional')}
|
||||
</span>
|
||||
)
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
<div className='grow'>
|
||||
<div className="grow">
|
||||
{
|
||||
type === InputVarType.textInput && (
|
||||
<Input
|
||||
@ -206,9 +208,9 @@ const FormItem: FC<Props> = ({
|
||||
language={CodeLanguage.json}
|
||||
onChange={onChange}
|
||||
noWrapper
|
||||
className='bg h-[80px] overflow-y-auto rounded-[10px] bg-components-input-bg-normal p-1'
|
||||
className="bg h-[80px] overflow-y-auto rounded-[10px] bg-components-input-bg-normal p-1"
|
||||
placeholder={
|
||||
<div className='whitespace-pre'>{payload.json_schema}</div>
|
||||
<div className="whitespace-pre">{payload.json_schema}</div>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
@ -219,19 +221,19 @@ const FormItem: FC<Props> = ({
|
||||
fileConfig={{
|
||||
allowed_file_types: inStepRun && (!payload.allowed_file_types || payload.allowed_file_types.length === 0)
|
||||
? [
|
||||
SupportUploadFileTypes.image,
|
||||
SupportUploadFileTypes.document,
|
||||
SupportUploadFileTypes.audio,
|
||||
SupportUploadFileTypes.video,
|
||||
]
|
||||
SupportUploadFileTypes.image,
|
||||
SupportUploadFileTypes.document,
|
||||
SupportUploadFileTypes.audio,
|
||||
SupportUploadFileTypes.video,
|
||||
]
|
||||
: payload.allowed_file_types,
|
||||
allowed_file_extensions: inStepRun && (!payload.allowed_file_extensions || payload.allowed_file_extensions.length === 0)
|
||||
? [
|
||||
...FILE_EXTS[SupportUploadFileTypes.image],
|
||||
...FILE_EXTS[SupportUploadFileTypes.document],
|
||||
...FILE_EXTS[SupportUploadFileTypes.audio],
|
||||
...FILE_EXTS[SupportUploadFileTypes.video],
|
||||
]
|
||||
...FILE_EXTS[SupportUploadFileTypes.image],
|
||||
...FILE_EXTS[SupportUploadFileTypes.document],
|
||||
...FILE_EXTS[SupportUploadFileTypes.audio],
|
||||
...FILE_EXTS[SupportUploadFileTypes.video],
|
||||
]
|
||||
: payload.allowed_file_extensions,
|
||||
allowed_file_upload_methods: inStepRun ? [TransferMethod.local_file, TransferMethod.remote_url] : payload.allowed_file_upload_methods,
|
||||
number_limits: 1,
|
||||
@ -246,19 +248,19 @@ const FormItem: FC<Props> = ({
|
||||
fileConfig={{
|
||||
allowed_file_types: (inStepRun || isIteratorItemFile) && (!payload.allowed_file_types || payload.allowed_file_types.length === 0)
|
||||
? [
|
||||
SupportUploadFileTypes.image,
|
||||
SupportUploadFileTypes.document,
|
||||
SupportUploadFileTypes.audio,
|
||||
SupportUploadFileTypes.video,
|
||||
]
|
||||
SupportUploadFileTypes.image,
|
||||
SupportUploadFileTypes.document,
|
||||
SupportUploadFileTypes.audio,
|
||||
SupportUploadFileTypes.video,
|
||||
]
|
||||
: payload.allowed_file_types,
|
||||
allowed_file_extensions: (inStepRun || isIteratorItemFile) && (!payload.allowed_file_extensions || payload.allowed_file_extensions.length === 0)
|
||||
? [
|
||||
...FILE_EXTS[SupportUploadFileTypes.image],
|
||||
...FILE_EXTS[SupportUploadFileTypes.document],
|
||||
...FILE_EXTS[SupportUploadFileTypes.audio],
|
||||
...FILE_EXTS[SupportUploadFileTypes.video],
|
||||
]
|
||||
...FILE_EXTS[SupportUploadFileTypes.image],
|
||||
...FILE_EXTS[SupportUploadFileTypes.document],
|
||||
...FILE_EXTS[SupportUploadFileTypes.audio],
|
||||
...FILE_EXTS[SupportUploadFileTypes.video],
|
||||
]
|
||||
: payload.allowed_file_extensions,
|
||||
allowed_file_upload_methods: (inStepRun || isIteratorItemFile) ? [TransferMethod.local_file, TransferMethod.remote_url] : payload.allowed_file_upload_methods,
|
||||
number_limits: (inStepRun || isIteratorItemFile) ? 5 : payload.max_length,
|
||||
@ -286,7 +288,7 @@ const FormItem: FC<Props> = ({
|
||||
|
||||
{
|
||||
isContext && (
|
||||
<div className='space-y-2'>
|
||||
<div className="space-y-2">
|
||||
{(value || []).map((item: any, index: number) => (
|
||||
<CodeEditor
|
||||
key={index}
|
||||
@ -294,10 +296,12 @@ const FormItem: FC<Props> = ({
|
||||
title={<span>JSON</span>}
|
||||
headerRight={
|
||||
(value as any).length > 1
|
||||
? (<RiDeleteBinLine
|
||||
onClick={handleArrayItemRemove(index)}
|
||||
className='mr-1 h-3.5 w-3.5 cursor-pointer text-text-tertiary'
|
||||
/>)
|
||||
? (
|
||||
<RiDeleteBinLine
|
||||
onClick={handleArrayItemRemove(index)}
|
||||
className="mr-1 h-3.5 w-3.5 cursor-pointer text-text-tertiary"
|
||||
/>
|
||||
)
|
||||
: undefined
|
||||
}
|
||||
language={CodeLanguage.json}
|
||||
@ -310,20 +314,29 @@ const FormItem: FC<Props> = ({
|
||||
|
||||
{
|
||||
(isIterator && !isIteratorItemFile) && (
|
||||
<div className='space-y-2'>
|
||||
<div className="space-y-2">
|
||||
{(value || []).map((item: any, index: number) => (
|
||||
<TextEditor
|
||||
key={index}
|
||||
isInNode
|
||||
value={item}
|
||||
title={<span>{t('appDebug.variableConfig.content')} {index + 1} </span>}
|
||||
title={(
|
||||
<span>
|
||||
{t('appDebug.variableConfig.content')}
|
||||
{' '}
|
||||
{index + 1}
|
||||
{' '}
|
||||
</span>
|
||||
)}
|
||||
onChange={handleArrayItemChange(index)}
|
||||
headerRight={
|
||||
(value as any).length > 1
|
||||
? (<RiDeleteBinLine
|
||||
onClick={handleArrayItemRemove(index)}
|
||||
className='mr-1 h-3.5 w-3.5 cursor-pointer text-text-tertiary'
|
||||
/>)
|
||||
? (
|
||||
<RiDeleteBinLine
|
||||
onClick={handleArrayItemRemove(index)}
|
||||
className="mr-1 h-3.5 w-3.5 cursor-pointer text-text-tertiary"
|
||||
/>
|
||||
)
|
||||
: undefined
|
||||
}
|
||||
/>
|
||||
|
||||
@ -1,13 +1,13 @@
|
||||
'use client'
|
||||
import type { FC } from 'react'
|
||||
import React, { useCallback, useEffect, useMemo, useRef } from 'react'
|
||||
import { produce } from 'immer'
|
||||
import type { InputVar } from '../../../../types'
|
||||
import FormItem from './form-item'
|
||||
import { cn } from '@/utils/classnames'
|
||||
import { InputVarType } from '@/app/components/workflow/types'
|
||||
import { produce } from 'immer'
|
||||
import React, { useCallback, useEffect, useMemo, useRef } from 'react'
|
||||
import AddButton from '@/app/components/base/button/add-button'
|
||||
import { RETRIEVAL_OUTPUT_STRUCT } from '@/app/components/workflow/constants'
|
||||
import { InputVarType } from '@/app/components/workflow/types'
|
||||
import { cn } from '@/utils/classnames'
|
||||
import FormItem from './form-item'
|
||||
|
||||
export type Props = {
|
||||
className?: string
|
||||
@ -77,8 +77,8 @@ const Form: FC<Props> = ({
|
||||
return (
|
||||
<div className={cn(className, 'space-y-2')}>
|
||||
{label && (
|
||||
<div className='mb-1 flex items-center justify-between'>
|
||||
<div className='system-xs-medium-uppercase flex h-6 items-center text-text-tertiary'>{label}</div>
|
||||
<div className="mb-1 flex items-center justify-between">
|
||||
<div className="system-xs-medium-uppercase flex h-6 items-center text-text-tertiary">{label}</div>
|
||||
{isArrayLikeType && !isIteratorItemFile && (
|
||||
<AddButton onClick={handleAddContext} />
|
||||
)}
|
||||
|
||||
@ -1,20 +1,21 @@
|
||||
'use client'
|
||||
import type { FC } from 'react'
|
||||
import React, { useEffect, useRef } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import type { Props as FormProps } from './form'
|
||||
import Form from './form'
|
||||
import { cn } from '@/utils/classnames'
|
||||
import Button from '@/app/components/base/button'
|
||||
import Split from '@/app/components/workflow/nodes/_base/components/split'
|
||||
import { InputVarType } from '@/app/components/workflow/types'
|
||||
import Toast from '@/app/components/base/toast'
|
||||
import { TransferMethod } from '@/types/app'
|
||||
import { getProcessedFiles } from '@/app/components/base/file-uploader/utils'
|
||||
import type { BlockEnum, NodeRunningStatus } from '@/app/components/workflow/types'
|
||||
import type { Emoji } from '@/app/components/tools/types'
|
||||
import type { SpecialResultPanelProps } from '@/app/components/workflow/run/special-result-panel'
|
||||
import type { BlockEnum, NodeRunningStatus } from '@/app/components/workflow/types'
|
||||
import React, { useEffect, useRef } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import Button from '@/app/components/base/button'
|
||||
import { getProcessedFiles } from '@/app/components/base/file-uploader/utils'
|
||||
import Toast from '@/app/components/base/toast'
|
||||
import Split from '@/app/components/workflow/nodes/_base/components/split'
|
||||
import { InputVarType } from '@/app/components/workflow/types'
|
||||
import { TransferMethod } from '@/types/app'
|
||||
import { cn } from '@/utils/classnames'
|
||||
import Form from './form'
|
||||
import PanelWrap from './panel-wrap'
|
||||
|
||||
const i18nPrefix = 'workflow.singleRun'
|
||||
|
||||
export type BeforeRunFormProps = {
|
||||
@ -32,9 +33,9 @@ export type BeforeRunFormProps = {
|
||||
} & Partial<SpecialResultPanelProps>
|
||||
|
||||
function formatValue(value: string | any, type: InputVarType) {
|
||||
if(type === InputVarType.checkbox)
|
||||
if (type === InputVarType.checkbox)
|
||||
return !!value
|
||||
if(value === undefined || value === null)
|
||||
if (value === undefined || value === null)
|
||||
return value
|
||||
if (type === InputVarType.number)
|
||||
return Number.parseFloat(value)
|
||||
@ -138,14 +139,14 @@ const BeforeRunForm: FC<BeforeRunFormProps> = ({
|
||||
const hasRun = useRef(false)
|
||||
useEffect(() => {
|
||||
// React 18 run twice in dev mode
|
||||
if(hasRun.current)
|
||||
if (hasRun.current)
|
||||
return
|
||||
hasRun.current = true
|
||||
if(filteredExistVarForms.length === 0)
|
||||
if (filteredExistVarForms.length === 0)
|
||||
onRun({})
|
||||
}, [filteredExistVarForms, onRun])
|
||||
|
||||
if(filteredExistVarForms.length === 0)
|
||||
if (filteredExistVarForms.length === 0)
|
||||
return null
|
||||
|
||||
return (
|
||||
@ -153,8 +154,8 @@ const BeforeRunForm: FC<BeforeRunFormProps> = ({
|
||||
nodeName={nodeName}
|
||||
onHide={onHide}
|
||||
>
|
||||
<div className='h-0 grow overflow-y-auto pb-4'>
|
||||
<div className='mt-3 space-y-4 px-4'>
|
||||
<div className="h-0 grow overflow-y-auto pb-4">
|
||||
<div className="mt-3 space-y-4 px-4">
|
||||
{filteredExistVarForms.map((form, index) => (
|
||||
<div key={index}>
|
||||
<Form
|
||||
@ -166,8 +167,8 @@ const BeforeRunForm: FC<BeforeRunFormProps> = ({
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<div className='mt-4 flex justify-between space-x-2 px-4' >
|
||||
<Button disabled={!isFileLoaded} variant='primary' className='w-0 grow space-x-2' onClick={handleRun}>
|
||||
<div className="mt-4 flex justify-between space-x-2 px-4">
|
||||
<Button disabled={!isFileLoaded} variant="primary" className="w-0 grow space-x-2" onClick={handleRun}>
|
||||
<div>{t(`${i18nPrefix}.startRun`)}</div>
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
'use client'
|
||||
import type { FC } from 'react'
|
||||
import React from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import {
|
||||
RiCloseLine,
|
||||
} from '@remixicon/react'
|
||||
import React from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
|
||||
const i18nPrefix = 'workflow.singleRun'
|
||||
|
||||
@ -21,16 +21,21 @@ const PanelWrap: FC<Props> = ({
|
||||
}) => {
|
||||
const { t } = useTranslation()
|
||||
return (
|
||||
<div className='absolute inset-0 z-10 rounded-2xl bg-background-overlay-alt'>
|
||||
<div className='flex h-full flex-col rounded-2xl bg-components-panel-bg'>
|
||||
<div className='flex h-8 shrink-0 items-center justify-between pl-4 pr-3 pt-3'>
|
||||
<div className='truncate text-base font-semibold text-text-primary'>
|
||||
{t(`${i18nPrefix}.testRun`)} {nodeName}
|
||||
<div className="absolute inset-0 z-10 rounded-2xl bg-background-overlay-alt">
|
||||
<div className="flex h-full flex-col rounded-2xl bg-components-panel-bg">
|
||||
<div className="flex h-8 shrink-0 items-center justify-between pl-4 pr-3 pt-3">
|
||||
<div className="truncate text-base font-semibold text-text-primary">
|
||||
{t(`${i18nPrefix}.testRun`)}
|
||||
{' '}
|
||||
{nodeName}
|
||||
</div>
|
||||
<div className='ml-2 shrink-0 cursor-pointer p-1' onClick={() => {
|
||||
onHide()
|
||||
}}>
|
||||
<RiCloseLine className='h-4 w-4 text-text-tertiary ' />
|
||||
<div
|
||||
className="ml-2 shrink-0 cursor-pointer p-1"
|
||||
onClick={() => {
|
||||
onHide()
|
||||
}}
|
||||
>
|
||||
<RiCloseLine className="h-4 w-4 text-text-tertiary " />
|
||||
</div>
|
||||
</div>
|
||||
{children}
|
||||
|
||||
@ -1,14 +1,14 @@
|
||||
'use client'
|
||||
import type { FC } from 'react'
|
||||
import React, { useCallback } from 'react'
|
||||
import { useBoolean } from 'ahooks'
|
||||
import { cn } from '@/utils/classnames'
|
||||
import type { CodeLanguage } from '../../code/types'
|
||||
import { Generator } from '@/app/components/base/icons/src/vender/other'
|
||||
import { ActionButton } from '@/app/components/base/action-button'
|
||||
import { AppModeEnum } from '@/types/app'
|
||||
import type { GenRes } from '@/service/debug'
|
||||
import { useBoolean } from 'ahooks'
|
||||
import React, { useCallback } from 'react'
|
||||
import { GetCodeGeneratorResModal } from '@/app/components/app/configuration/config/code-generator/get-code-generator-res'
|
||||
import { ActionButton } from '@/app/components/base/action-button'
|
||||
import { Generator } from '@/app/components/base/icons/src/vender/other'
|
||||
import { AppModeEnum } from '@/types/app'
|
||||
import { cn } from '@/utils/classnames'
|
||||
import { useHooksStore } from '../../../hooks-store'
|
||||
|
||||
type Props = {
|
||||
@ -36,9 +36,10 @@ const CodeGenerateBtn: FC<Props> = ({
|
||||
return (
|
||||
<div className={cn(className)}>
|
||||
<ActionButton
|
||||
className='hover:bg-[#155EFF]/8'
|
||||
onClick={showAutomaticTrue}>
|
||||
<Generator className='h-4 w-4 text-primary-600' />
|
||||
className="hover:bg-[#155EFF]/8"
|
||||
onClick={showAutomaticTrue}
|
||||
>
|
||||
<Generator className="h-4 w-4 text-primary-600" />
|
||||
</ActionButton>
|
||||
{showAutomatic && (
|
||||
<GetCodeGeneratorResModal
|
||||
|
||||
@ -16,16 +16,16 @@ const FieldCollapse = ({
|
||||
operations,
|
||||
}: FieldCollapseProps) => {
|
||||
return (
|
||||
<div className='py-4'>
|
||||
<div className="py-4">
|
||||
<Collapse
|
||||
trigger={
|
||||
<div className='system-sm-semibold-uppercase flex h-6 cursor-pointer items-center text-text-secondary'>{title}</div>
|
||||
<div className="system-sm-semibold-uppercase flex h-6 cursor-pointer items-center text-text-secondary">{title}</div>
|
||||
}
|
||||
operations={operations}
|
||||
collapsed={collapsed}
|
||||
onCollapse={onCollapse}
|
||||
>
|
||||
<div className='px-4'>
|
||||
<div className="px-4">
|
||||
{children}
|
||||
</div>
|
||||
</Collapse>
|
||||
|
||||
@ -40,9 +40,9 @@ const Collapse = ({
|
||||
}, [collapsedMerged, disabled])
|
||||
return (
|
||||
<>
|
||||
<div className='group/collapse flex items-center'>
|
||||
<div className="group/collapse flex items-center">
|
||||
<div
|
||||
className='ml-4 flex grow items-center'
|
||||
className="ml-4 flex grow items-center"
|
||||
onClick={() => {
|
||||
if (!disabled) {
|
||||
setCollapsedLocal(!collapsedMerged)
|
||||
@ -52,7 +52,7 @@ const Collapse = ({
|
||||
>
|
||||
{typeof trigger === 'function' ? trigger(collapseIcon) : trigger}
|
||||
{!hideCollapseIcon && (
|
||||
<div className='h-4 w-4 shrink-0'>
|
||||
<div className="h-4 w-4 shrink-0">
|
||||
{collapseIcon}
|
||||
</div>
|
||||
)}
|
||||
|
||||
@ -1,15 +1,17 @@
|
||||
'use client'
|
||||
import type { FC } from 'react'
|
||||
import type { ValueSelector, Var, VisionSetting } from '@/app/components/workflow/types'
|
||||
import { produce } from 'immer'
|
||||
import React, { useCallback } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { produce } from 'immer'
|
||||
import VarReferencePicker from './variable/var-reference-picker'
|
||||
import ResolutionPicker from '@/app/components/workflow/nodes/llm/components/resolution-picker'
|
||||
import Field from '@/app/components/workflow/nodes/_base/components/field'
|
||||
import Switch from '@/app/components/base/switch'
|
||||
import { type ValueSelector, type Var, VarType, type VisionSetting } from '@/app/components/workflow/types'
|
||||
import { Resolution } from '@/types/app'
|
||||
import Tooltip from '@/app/components/base/tooltip'
|
||||
import Field from '@/app/components/workflow/nodes/_base/components/field'
|
||||
import ResolutionPicker from '@/app/components/workflow/nodes/llm/components/resolution-picker'
|
||||
import { VarType } from '@/app/components/workflow/types'
|
||||
import { Resolution } from '@/types/app'
|
||||
import VarReferencePicker from './variable/var-reference-picker'
|
||||
|
||||
const i18nPrefix = 'workflow.nodes.llm'
|
||||
|
||||
type Props = {
|
||||
@ -57,32 +59,32 @@ const ConfigVision: FC<Props> = ({
|
||||
<Field
|
||||
title={t(`${i18nPrefix}.vision`)}
|
||||
tooltip={t('appDebug.vision.description')!}
|
||||
operations={
|
||||
operations={(
|
||||
<Tooltip
|
||||
popupContent={t('appDebug.vision.onlySupportVisionModelTip')!}
|
||||
disabled={isVisionModel}
|
||||
>
|
||||
<Switch disabled={readOnly || !isVisionModel} size='md' defaultValue={!isVisionModel ? false : enabled} onChange={onEnabledChange} />
|
||||
<Switch disabled={readOnly || !isVisionModel} size="md" defaultValue={!isVisionModel ? false : enabled} onChange={onEnabledChange} />
|
||||
</Tooltip>
|
||||
}
|
||||
)}
|
||||
>
|
||||
{(enabled && isVisionModel)
|
||||
? (
|
||||
<div>
|
||||
<VarReferencePicker
|
||||
className='mb-4'
|
||||
filterVar={filterVar}
|
||||
nodeId={nodeId}
|
||||
value={config.variable_selector || []}
|
||||
onChange={handleVarSelectorChange}
|
||||
readonly={readOnly}
|
||||
/>
|
||||
<ResolutionPicker
|
||||
value={config.detail}
|
||||
onChange={handleVisionResolutionChange}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
<div>
|
||||
<VarReferencePicker
|
||||
className="mb-4"
|
||||
filterVar={filterVar}
|
||||
nodeId={nodeId}
|
||||
value={config.variable_selector || []}
|
||||
onChange={handleVarSelectorChange}
|
||||
readonly={readOnly}
|
||||
/>
|
||||
<ResolutionPicker
|
||||
value={config.detail}
|
||||
onChange={handleVisionResolutionChange}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
: null}
|
||||
|
||||
</Field>
|
||||
|
||||
@ -1,22 +1,22 @@
|
||||
'use client'
|
||||
import type { FC } from 'react'
|
||||
import React, { useCallback, useRef, useState } from 'react'
|
||||
import copy from 'copy-to-clipboard'
|
||||
import ToggleExpandBtn from '../toggle-expand-btn'
|
||||
import CodeGeneratorButton from '../code-generator-button'
|
||||
import type { CodeLanguage } from '../../../code/types'
|
||||
import Wrap from './wrap'
|
||||
import { cn } from '@/utils/classnames'
|
||||
import type { FileEntity } from '@/app/components/base/file-uploader/types'
|
||||
import type { Node, NodeOutPutVar } from '@/app/components/workflow/types'
|
||||
import copy from 'copy-to-clipboard'
|
||||
import React, { useCallback, useRef, useState } from 'react'
|
||||
import PromptEditorHeightResizeWrap from '@/app/components/app/configuration/config-prompt/prompt-editor-height-resize-wrap'
|
||||
import ActionButton from '@/app/components/base/action-button'
|
||||
import FileListInLog from '@/app/components/base/file-uploader/file-list-in-log'
|
||||
import {
|
||||
Copy,
|
||||
CopyCheck,
|
||||
} from '@/app/components/base/icons/src/vender/line/files'
|
||||
import useToggleExpend from '@/app/components/workflow/nodes/_base/hooks/use-toggle-expend'
|
||||
import type { FileEntity } from '@/app/components/base/file-uploader/types'
|
||||
import FileListInLog from '@/app/components/base/file-uploader/file-list-in-log'
|
||||
import ActionButton from '@/app/components/base/action-button'
|
||||
import type { Node, NodeOutPutVar } from '@/app/components/workflow/types'
|
||||
import { cn } from '@/utils/classnames'
|
||||
import CodeGeneratorButton from '../code-generator-button'
|
||||
import ToggleExpandBtn from '../toggle-expand-btn'
|
||||
import Wrap from './wrap'
|
||||
|
||||
type Props = {
|
||||
nodeId?: string
|
||||
@ -84,15 +84,18 @@ const Base: FC<Props> = ({
|
||||
return (
|
||||
<Wrap className={cn(wrapClassName)} style={wrapStyle} isInNode={isInNode} isExpand={isExpand}>
|
||||
<div ref={ref} className={cn(className, isExpand && 'h-full', 'rounded-lg border', !isFocus ? 'border-transparent bg-components-input-bg-normal' : 'overflow-hidden border-components-input-border-hover bg-components-input-bg-hover')}>
|
||||
<div className='flex h-7 items-center justify-between pl-3 pr-2 pt-1'>
|
||||
<div className='system-xs-semibold-uppercase text-text-secondary'>{title}</div>
|
||||
<div className='flex items-center' onClick={(e) => {
|
||||
e.nativeEvent.stopImmediatePropagation()
|
||||
e.stopPropagation()
|
||||
}}>
|
||||
<div className="flex h-7 items-center justify-between pl-3 pr-2 pt-1">
|
||||
<div className="system-xs-semibold-uppercase text-text-secondary">{title}</div>
|
||||
<div
|
||||
className="flex items-center"
|
||||
onClick={(e) => {
|
||||
e.nativeEvent.stopImmediatePropagation()
|
||||
e.stopPropagation()
|
||||
}}
|
||||
>
|
||||
{headerRight}
|
||||
{showCodeGenerator && codeLanguages && (
|
||||
<div className='ml-1'>
|
||||
<div className="ml-1">
|
||||
<CodeGeneratorButton
|
||||
onGenerated={onGenerated}
|
||||
codeLanguages={codeLanguages}
|
||||
@ -101,29 +104,28 @@ const Base: FC<Props> = ({
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<ActionButton className='ml-1' onClick={handleCopy}>
|
||||
<ActionButton className="ml-1" onClick={handleCopy}>
|
||||
{!isCopied
|
||||
? (
|
||||
<Copy className='h-4 w-4 cursor-pointer' />
|
||||
)
|
||||
<Copy className="h-4 w-4 cursor-pointer" />
|
||||
)
|
||||
: (
|
||||
<CopyCheck className='h-4 w-4' />
|
||||
)
|
||||
}
|
||||
<CopyCheck className="h-4 w-4" />
|
||||
)}
|
||||
</ActionButton>
|
||||
<div className='ml-1'>
|
||||
<div className="ml-1">
|
||||
<ToggleExpandBtn isExpand={isExpand} onExpandChange={setIsExpand} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{tip && <div className='px-1 py-0.5'>{tip}</div>}
|
||||
{tip && <div className="px-1 py-0.5">{tip}</div>}
|
||||
<PromptEditorHeightResizeWrap
|
||||
height={isExpand ? editorExpandHeight : editorContentHeight}
|
||||
minHeight={editorContentMinHeight}
|
||||
onHeightChange={setEditorContentHeight}
|
||||
hideResize={isExpand}
|
||||
>
|
||||
<div className='h-full pb-2 pl-2'>
|
||||
<div className="h-full pb-2 pl-2">
|
||||
{children}
|
||||
</div>
|
||||
</PromptEditorHeightResizeWrap>
|
||||
|
||||
@ -1,13 +1,13 @@
|
||||
'use client'
|
||||
import type { FC } from 'react'
|
||||
import React, { useEffect, useRef, useState } from 'react'
|
||||
import { useBoolean } from 'ahooks'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import type { Props as EditorProps } from '.'
|
||||
import Editor from '.'
|
||||
import { cn } from '@/utils/classnames'
|
||||
import VarReferenceVars from '@/app/components/workflow/nodes/_base/components/variable/var-reference-vars'
|
||||
import type { NodeOutPutVar, Variable } from '@/app/components/workflow/types'
|
||||
import { useBoolean } from 'ahooks'
|
||||
import React, { useEffect, useRef, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import VarReferenceVars from '@/app/components/workflow/nodes/_base/components/variable/var-reference-vars'
|
||||
import { cn } from '@/utils/classnames'
|
||||
import Editor from '.'
|
||||
|
||||
const TO_WINDOW_OFFSET = 8
|
||||
|
||||
@ -149,7 +149,7 @@ const CodeEditor: FC<Props> = ({
|
||||
{isShowVarPicker && (
|
||||
<div
|
||||
ref={popupRef}
|
||||
className='w-[228px] space-y-1 rounded-lg border border-components-panel-border bg-components-panel-bg p-1 shadow-lg'
|
||||
className="w-[228px] space-y-1 rounded-lg border border-components-panel-border bg-components-panel-bg p-1 shadow-lg"
|
||||
style={{
|
||||
position: 'fixed',
|
||||
top: popupPosition.y,
|
||||
|
||||
@ -1,18 +1,18 @@
|
||||
'use client'
|
||||
import type { FC } from 'react'
|
||||
import Editor, { loader } from '@monaco-editor/react'
|
||||
import { noop } from 'lodash-es'
|
||||
import React, { useEffect, useMemo, useRef, useState } from 'react'
|
||||
import Base from '../base'
|
||||
import { cn } from '@/utils/classnames'
|
||||
import { CodeLanguage } from '@/app/components/workflow/nodes/code/types'
|
||||
import {
|
||||
getFilesInLogs,
|
||||
} from '@/app/components/base/file-uploader/utils'
|
||||
import { Theme } from '@/types/app'
|
||||
import { CodeLanguage } from '@/app/components/workflow/nodes/code/types'
|
||||
import useTheme from '@/hooks/use-theme'
|
||||
import './style.css'
|
||||
import { noop } from 'lodash-es'
|
||||
import { Theme } from '@/types/app'
|
||||
import { cn } from '@/utils/classnames'
|
||||
import { basePath } from '@/utils/var'
|
||||
import Base from '../base'
|
||||
import './style.css'
|
||||
|
||||
// load file from local instead of cdn https://github.com/suren-atoyan/monaco-react/issues/482
|
||||
if (typeof window !== 'undefined')
|
||||
@ -145,7 +145,7 @@ const CodeEditor: FC<Props> = ({
|
||||
language={languageMap[language] || 'javascript'}
|
||||
theme={isMounted ? theme : 'default-theme'} // sometimes not load the default theme
|
||||
value={outPutValue}
|
||||
loading={<span className='text-text-primary'>Loading...</span>}
|
||||
loading={<span className="text-text-primary">Loading...</span>}
|
||||
onChange={handleEditorChange}
|
||||
// https://microsoft.github.io/monaco-editor/typedoc/interfaces/editor.IEditorOptions.html
|
||||
options={{
|
||||
@ -166,40 +166,45 @@ const CodeEditor: FC<Props> = ({
|
||||
}}
|
||||
onMount={handleEditorDidMount}
|
||||
/>
|
||||
{!outPutValue && !isFocus && <div className='pointer-events-none absolute left-[36px] top-0 text-[13px] font-normal leading-[18px] text-gray-300'>{placeholder}</div>}
|
||||
{!outPutValue && !isFocus && <div className="pointer-events-none absolute left-[36px] top-0 text-[13px] font-normal leading-[18px] text-gray-300">{placeholder}</div>}
|
||||
</>
|
||||
)
|
||||
|
||||
return (
|
||||
<div className={cn(isExpand && 'h-full', className)}>
|
||||
{noWrapper
|
||||
? <div className='no-wrapper relative' style={{
|
||||
height: isExpand ? '100%' : (editorContentHeight) / 2 + CODE_EDITOR_LINE_HEIGHT, // In IDE, the last line can always be in lop line. So there is some blank space in the bottom.
|
||||
minHeight: CODE_EDITOR_LINE_HEIGHT,
|
||||
}}>
|
||||
{main}
|
||||
</div>
|
||||
? (
|
||||
<div
|
||||
className="no-wrapper relative"
|
||||
style={{
|
||||
height: isExpand ? '100%' : (editorContentHeight) / 2 + CODE_EDITOR_LINE_HEIGHT, // In IDE, the last line can always be in lop line. So there is some blank space in the bottom.
|
||||
minHeight: CODE_EDITOR_LINE_HEIGHT,
|
||||
}}
|
||||
>
|
||||
{main}
|
||||
</div>
|
||||
)
|
||||
: (
|
||||
<Base
|
||||
nodeId={nodeId}
|
||||
className='relative'
|
||||
title={title}
|
||||
value={outPutValue}
|
||||
headerRight={headerRight}
|
||||
isFocus={isFocus && !readOnly}
|
||||
minHeight={minHeight}
|
||||
isInNode={isInNode}
|
||||
onGenerated={onGenerated}
|
||||
codeLanguages={language}
|
||||
fileList={fileList as any}
|
||||
showFileList={showFileList}
|
||||
showCodeGenerator={showCodeGenerator}
|
||||
tip={tip}
|
||||
footer={footer}
|
||||
>
|
||||
{main}
|
||||
</Base>
|
||||
)}
|
||||
<Base
|
||||
nodeId={nodeId}
|
||||
className="relative"
|
||||
title={title}
|
||||
value={outPutValue}
|
||||
headerRight={headerRight}
|
||||
isFocus={isFocus && !readOnly}
|
||||
minHeight={minHeight}
|
||||
isInNode={isInNode}
|
||||
onGenerated={onGenerated}
|
||||
codeLanguages={language}
|
||||
fileList={fileList as any}
|
||||
showFileList={showFileList}
|
||||
showCodeGenerator={showCodeGenerator}
|
||||
tip={tip}
|
||||
footer={footer}
|
||||
>
|
||||
{main}
|
||||
</Base>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
'use client'
|
||||
import type { FC } from 'react'
|
||||
import React, { useCallback } from 'react'
|
||||
import { useBoolean } from 'ahooks'
|
||||
import React, { useCallback } from 'react'
|
||||
import Base from './base'
|
||||
|
||||
type Props = {
|
||||
@ -52,7 +52,7 @@ const TextEditor: FC<Props> = ({
|
||||
onChange={e => onChange(e.target.value)}
|
||||
onFocus={setIsFocus}
|
||||
onBlur={handleBlur}
|
||||
className='h-full w-full resize-none border-none bg-transparent px-3 text-[13px] font-normal leading-[18px] text-gray-900 placeholder:text-gray-300 focus:outline-none'
|
||||
className="h-full w-full resize-none border-none bg-transparent px-3 text-[13px] font-normal leading-[18px] text-gray-900 placeholder:text-gray-300 focus:outline-none"
|
||||
placeholder={placeholder}
|
||||
readOnly={readonly}
|
||||
/>
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
import type { DefaultValueForm } from './types'
|
||||
import { useCallback } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import type { DefaultValueForm } from './types'
|
||||
import Input from '@/app/components/base/input'
|
||||
import { VarType } from '@/app/components/workflow/types'
|
||||
import { CodeLanguage } from '@/app/components/workflow/nodes/code/types'
|
||||
import CodeEditor from '@/app/components/workflow/nodes/_base/components/editor/code-editor'
|
||||
import { CodeLanguage } from '@/app/components/workflow/nodes/code/types'
|
||||
import { VarType } from '@/app/components/workflow/types'
|
||||
import { useDocLink } from '@/context/i18n'
|
||||
|
||||
type DefaultValueProps = {
|
||||
@ -31,31 +31,31 @@ const DefaultValue = ({
|
||||
}, [onFormChange])
|
||||
|
||||
return (
|
||||
<div className='px-4 pt-2'>
|
||||
<div className='body-xs-regular mb-2 text-text-tertiary'>
|
||||
<div className="px-4 pt-2">
|
||||
<div className="body-xs-regular mb-2 text-text-tertiary">
|
||||
{t('workflow.nodes.common.errorHandle.defaultValue.desc')}
|
||||
|
||||
<a
|
||||
href={docLink('/guides/workflow/error-handling/README', {
|
||||
'zh-Hans': '/guides/workflow/error-handling/readme',
|
||||
})}
|
||||
target='_blank'
|
||||
className='text-text-accent'
|
||||
target="_blank"
|
||||
className="text-text-accent"
|
||||
>
|
||||
{t('workflow.common.learnMore')}
|
||||
</a>
|
||||
</div>
|
||||
<div className='space-y-1'>
|
||||
<div className="space-y-1">
|
||||
{
|
||||
forms.map((form, index) => {
|
||||
return (
|
||||
<div
|
||||
key={index}
|
||||
className='py-1'
|
||||
className="py-1"
|
||||
>
|
||||
<div className='mb-1 flex items-center'>
|
||||
<div className='system-sm-medium mr-1 text-text-primary'>{form.key}</div>
|
||||
<div className='system-xs-regular text-text-tertiary'>{form.type}</div>
|
||||
<div className="mb-1 flex items-center">
|
||||
<div className="system-sm-medium mr-1 text-text-primary">{form.key}</div>
|
||||
<div className="system-xs-regular text-text-tertiary">{form.type}</div>
|
||||
</div>
|
||||
{
|
||||
(form.type === VarType.string || form.type === VarType.number) && (
|
||||
|
||||
@ -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 './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'
|
||||
import { ErrorHandleTypeEnum } from './types'
|
||||
|
||||
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,8 +56,8 @@ 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'
|
||||
nodeSelectorClassName='!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"
|
||||
nodeSelectorClassName="!bg-workflow-link-line-failure-button-bg"
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
@ -1,20 +1,20 @@
|
||||
import { useCallback } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import Collapse from '../collapse'
|
||||
import { ErrorHandleTypeEnum } from './types'
|
||||
import ErrorHandleTypeSelector from './error-handle-type-selector'
|
||||
import FailBranchCard from './fail-branch-card'
|
||||
import DefaultValue from './default-value'
|
||||
import {
|
||||
useDefaultValue,
|
||||
useErrorHandle,
|
||||
} from './hooks'
|
||||
import type { DefaultValueForm } from './types'
|
||||
import type {
|
||||
CommonNodeType,
|
||||
Node,
|
||||
} from '@/app/components/workflow/types'
|
||||
import { useCallback } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import Tooltip from '@/app/components/base/tooltip'
|
||||
import Collapse from '../collapse'
|
||||
import DefaultValue from './default-value'
|
||||
import ErrorHandleTypeSelector from './error-handle-type-selector'
|
||||
import FailBranchCard from './fail-branch-card'
|
||||
import {
|
||||
useDefaultValue,
|
||||
useErrorHandle,
|
||||
} from './hooks'
|
||||
import { ErrorHandleTypeEnum } from './types'
|
||||
|
||||
type ErrorHandleProps = Pick<Node, 'id' | 'data'>
|
||||
const ErrorHandle = ({
|
||||
@ -44,7 +44,7 @@ const ErrorHandle = ({
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className='py-4'>
|
||||
<div className="py-4">
|
||||
<Collapse
|
||||
disabled={!error_strategy}
|
||||
collapsed={collapsed}
|
||||
@ -52,9 +52,9 @@ const ErrorHandle = ({
|
||||
hideCollapseIcon
|
||||
trigger={
|
||||
collapseIcon => (
|
||||
<div className='flex grow items-center justify-between pr-4'>
|
||||
<div className='flex items-center'>
|
||||
<div className='system-sm-semibold-uppercase mr-0.5 text-text-secondary'>
|
||||
<div className="flex grow items-center justify-between pr-4">
|
||||
<div className="flex items-center">
|
||||
<div className="system-sm-semibold-uppercase mr-0.5 text-text-secondary">
|
||||
{t('workflow.nodes.common.errorHandle.title')}
|
||||
</div>
|
||||
<Tooltip popupContent={t('workflow.nodes.common.errorHandle.tip')} />
|
||||
@ -65,7 +65,8 @@ const ErrorHandle = ({
|
||||
onSelected={getHandleErrorHandleTypeChange(data)}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
)
|
||||
}
|
||||
>
|
||||
<>
|
||||
{
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import { RiAlertFill } from '@remixicon/react'
|
||||
import { useMemo } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { RiAlertFill } from '@remixicon/react'
|
||||
import { ErrorHandleTypeEnum } from './types'
|
||||
|
||||
type ErrorHandleTipProps = {
|
||||
@ -24,16 +24,17 @@ const ErrorHandleTip = ({
|
||||
|
||||
return (
|
||||
<div
|
||||
className='relative flex rounded-lg border-[0.5px] border-components-panel-border bg-components-panel-bg-blur p-2 pr-[52px] shadow-xs'
|
||||
className="relative flex rounded-lg border-[0.5px] border-components-panel-border bg-components-panel-bg-blur p-2 pr-[52px] shadow-xs"
|
||||
>
|
||||
<div
|
||||
className='absolute inset-0 rounded-lg opacity-40'
|
||||
className="absolute inset-0 rounded-lg opacity-40"
|
||||
style={{
|
||||
background: 'linear-gradient(92deg, rgba(247, 144, 9, 0.25) 0%, rgba(255, 255, 255, 0.00) 100%)',
|
||||
}}
|
||||
></div>
|
||||
<RiAlertFill className='mr-1 h-4 w-4 shrink-0 text-text-warning-secondary' />
|
||||
<div className='system-xs-medium grow text-text-primary'>
|
||||
>
|
||||
</div>
|
||||
<RiAlertFill className="mr-1 h-4 w-4 shrink-0 text-text-warning-secondary" />
|
||||
<div className="system-xs-medium grow text-text-primary">
|
||||
{text}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -1,16 +1,16 @@
|
||||
import { useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import {
|
||||
RiArrowDownSLine,
|
||||
RiCheckLine,
|
||||
} from '@remixicon/react'
|
||||
import { ErrorHandleTypeEnum } from './types'
|
||||
import { useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import Button from '@/app/components/base/button'
|
||||
import {
|
||||
PortalToFollowElem,
|
||||
PortalToFollowElemContent,
|
||||
PortalToFollowElemTrigger,
|
||||
} from '@/app/components/base/portal-to-follow-elem'
|
||||
import Button from '@/app/components/base/button'
|
||||
import { ErrorHandleTypeEnum } from './types'
|
||||
|
||||
type ErrorHandleTypeSelectorProps = {
|
||||
value: ErrorHandleTypeEnum
|
||||
@ -45,28 +45,29 @@ const ErrorHandleTypeSelector = ({
|
||||
<PortalToFollowElem
|
||||
open={open}
|
||||
onOpenChange={setOpen}
|
||||
placement='bottom-end'
|
||||
placement="bottom-end"
|
||||
offset={4}
|
||||
>
|
||||
<PortalToFollowElemTrigger onClick={(e) => {
|
||||
e.stopPropagation()
|
||||
e.nativeEvent.stopImmediatePropagation()
|
||||
setOpen(v => !v)
|
||||
}}>
|
||||
}}
|
||||
>
|
||||
<Button
|
||||
size='small'
|
||||
size="small"
|
||||
>
|
||||
{selectedOption?.label}
|
||||
<RiArrowDownSLine className='h-3.5 w-3.5' />
|
||||
<RiArrowDownSLine className="h-3.5 w-3.5" />
|
||||
</Button>
|
||||
</PortalToFollowElemTrigger>
|
||||
<PortalToFollowElemContent className='z-[11]'>
|
||||
<div className='w-[280px] rounded-xl border-[0.5px] border-components-panel-border bg-components-panel-bg-blur p-1 shadow-lg'>
|
||||
<PortalToFollowElemContent className="z-[11]">
|
||||
<div className="w-[280px] rounded-xl border-[0.5px] border-components-panel-border bg-components-panel-bg-blur p-1 shadow-lg">
|
||||
{
|
||||
options.map(option => (
|
||||
<div
|
||||
key={option.value}
|
||||
className='flex cursor-pointer rounded-lg p-2 pr-3 hover:bg-state-base-hover'
|
||||
className="flex cursor-pointer rounded-lg p-2 pr-3 hover:bg-state-base-hover"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation()
|
||||
e.nativeEvent.stopImmediatePropagation()
|
||||
@ -74,16 +75,16 @@ const ErrorHandleTypeSelector = ({
|
||||
setOpen(false)
|
||||
}}
|
||||
>
|
||||
<div className='mr-1 w-4 shrink-0'>
|
||||
<div className="mr-1 w-4 shrink-0">
|
||||
{
|
||||
value === option.value && (
|
||||
<RiCheckLine className='h-4 w-4 text-text-accent' />
|
||||
<RiCheckLine className="h-4 w-4 text-text-accent" />
|
||||
)
|
||||
}
|
||||
</div>
|
||||
<div className='grow'>
|
||||
<div className='system-sm-semibold mb-0.5 text-text-secondary'>{option.label}</div>
|
||||
<div className='system-xs-regular text-text-tertiary'>{option.description}</div>
|
||||
<div className="grow">
|
||||
<div className="system-sm-semibold mb-0.5 text-text-secondary">{option.label}</div>
|
||||
<div className="system-xs-regular text-text-tertiary">{option.description}</div>
|
||||
</div>
|
||||
</div>
|
||||
))
|
||||
|
||||
@ -7,21 +7,21 @@ const FailBranchCard = () => {
|
||||
const docLink = useDocLink()
|
||||
|
||||
return (
|
||||
<div className='px-4 pt-2'>
|
||||
<div className='rounded-[10px] bg-workflow-process-bg p-4'>
|
||||
<div className='mb-2 flex h-8 w-8 items-center justify-center rounded-[10px] border-[0.5px] border-components-card-border bg-components-card-bg shadow-lg'>
|
||||
<RiMindMap className='h-5 w-5 text-text-tertiary' />
|
||||
<div className="px-4 pt-2">
|
||||
<div className="rounded-[10px] bg-workflow-process-bg p-4">
|
||||
<div className="mb-2 flex h-8 w-8 items-center justify-center rounded-[10px] border-[0.5px] border-components-card-border bg-components-card-bg shadow-lg">
|
||||
<RiMindMap className="h-5 w-5 text-text-tertiary" />
|
||||
</div>
|
||||
<div className='system-sm-medium mb-1 text-text-secondary'>
|
||||
<div className="system-sm-medium mb-1 text-text-secondary">
|
||||
{t('workflow.nodes.common.errorHandle.failBranch.customize')}
|
||||
</div>
|
||||
<div className='system-xs-regular text-text-tertiary'>
|
||||
<div className="system-xs-regular text-text-tertiary">
|
||||
{t('workflow.nodes.common.errorHandle.failBranch.customizeTip')}
|
||||
|
||||
<a
|
||||
href={docLink('/guides/workflow/error-handling/error-type')}
|
||||
target='_blank'
|
||||
className='text-text-accent'
|
||||
target="_blank"
|
||||
className="text-text-accent"
|
||||
>
|
||||
{t('workflow.common.learnMore')}
|
||||
</a>
|
||||
|
||||
@ -1,18 +1,18 @@
|
||||
import type { DefaultValueForm } from './types'
|
||||
import type {
|
||||
CommonNodeType,
|
||||
} from '@/app/components/workflow/types'
|
||||
import {
|
||||
useCallback,
|
||||
useMemo,
|
||||
useState,
|
||||
} from 'react'
|
||||
import { ErrorHandleTypeEnum } from './types'
|
||||
import type { DefaultValueForm } from './types'
|
||||
import { getDefaultValue } from './utils'
|
||||
import type {
|
||||
CommonNodeType,
|
||||
} from '@/app/components/workflow/types'
|
||||
import {
|
||||
useEdgesInteractions,
|
||||
useNodeDataUpdate,
|
||||
} from '@/app/components/workflow/hooks'
|
||||
import { ErrorHandleTypeEnum } from './types'
|
||||
import { getDefaultValue } from './utils'
|
||||
|
||||
export const useDefaultValue = (
|
||||
id: string,
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
import type { CodeNodeType } from '@/app/components/workflow/nodes/code/types'
|
||||
import type { CommonNodeType } from '@/app/components/workflow/types'
|
||||
import {
|
||||
BlockEnum,
|
||||
VarType,
|
||||
} from '@/app/components/workflow/types'
|
||||
import type { CodeNodeType } from '@/app/components/workflow/nodes/code/types'
|
||||
|
||||
const getDefaultValueByType = (type: VarType) => {
|
||||
if (type === VarType.string)
|
||||
|
||||
@ -1,12 +1,12 @@
|
||||
'use client'
|
||||
import type { FC, ReactNode } from 'react'
|
||||
import React from 'react'
|
||||
import {
|
||||
RiArrowDownSLine,
|
||||
} from '@remixicon/react'
|
||||
import { useBoolean } from 'ahooks'
|
||||
import { cn } from '@/utils/classnames'
|
||||
import React from 'react'
|
||||
import Tooltip from '@/app/components/base/tooltip'
|
||||
import { cn } from '@/utils/classnames'
|
||||
|
||||
type Props = {
|
||||
className?: string
|
||||
@ -38,23 +38,26 @@ const Field: FC<Props> = ({
|
||||
<div className={cn(className, inline && 'flex w-full items-center justify-between')}>
|
||||
<div
|
||||
onClick={() => supportFold && toggleFold()}
|
||||
className={cn('flex items-center justify-between', supportFold && 'cursor-pointer')}>
|
||||
<div className='flex h-6 items-center'>
|
||||
className={cn('flex items-center justify-between', supportFold && 'cursor-pointer')}
|
||||
>
|
||||
<div className="flex h-6 items-center">
|
||||
<div className={cn(isSubTitle ? 'system-xs-medium-uppercase text-text-tertiary' : 'system-sm-semibold-uppercase text-text-secondary')}>
|
||||
{title} {required && <span className='text-text-destructive'>*</span>}
|
||||
{title}
|
||||
{' '}
|
||||
{required && <span className="text-text-destructive">*</span>}
|
||||
</div>
|
||||
{tooltip && (
|
||||
<Tooltip
|
||||
popupContent={tooltip}
|
||||
popupClassName='ml-1'
|
||||
triggerClassName='w-4 h-4 ml-1'
|
||||
popupClassName="ml-1"
|
||||
triggerClassName="w-4 h-4 ml-1"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<div className='flex'>
|
||||
<div className="flex">
|
||||
{operations && <div>{operations}</div>}
|
||||
{supportFold && (
|
||||
<RiArrowDownSLine className='h-4 w-4 cursor-pointer text-text-tertiary transition-transform' style={{ transform: fold ? 'rotate(-90deg)' : 'rotate(0deg)' }} />
|
||||
<RiArrowDownSLine className="h-4 w-4 cursor-pointer text-text-tertiary transition-transform" style={{ transform: fold ? 'rotate(-90deg)' : 'rotate(0deg)' }} />
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -1,14 +1,14 @@
|
||||
'use client'
|
||||
import type { FC } from 'react'
|
||||
import { noop } from 'lodash-es'
|
||||
import React, { useCallback } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { SupportUploadFileTypes } from '../../../types'
|
||||
import { cn } from '@/utils/classnames'
|
||||
import { FILE_EXTS } from '@/app/components/base/prompt-editor/constants'
|
||||
import TagInput from '@/app/components/base/tag-input'
|
||||
import Checkbox from '@/app/components/base/checkbox'
|
||||
import { FileTypeIcon } from '@/app/components/base/file-uploader'
|
||||
import { noop } from 'lodash-es'
|
||||
import { FILE_EXTS } from '@/app/components/base/prompt-editor/constants'
|
||||
import TagInput from '@/app/components/base/tag-input'
|
||||
import { cn } from '@/utils/classnames'
|
||||
import { SupportUploadFileTypes } from '../../../types'
|
||||
|
||||
type Props = {
|
||||
type: SupportUploadFileTypes.image | SupportUploadFileTypes.document | SupportUploadFileTypes.audio | SupportUploadFileTypes.video | SupportUploadFileTypes.custom
|
||||
@ -45,31 +45,31 @@ const FileTypeItem: FC<Props> = ({
|
||||
>
|
||||
{isCustomSelected
|
||||
? (
|
||||
<div>
|
||||
<div className='flex items-center border-b border-divider-subtle p-3 pb-2'>
|
||||
<FileTypeIcon className='shrink-0' type={type} size='lg' />
|
||||
<div className='system-sm-medium mx-2 grow text-text-primary'>{t(`appDebug.variableConfig.file.${type}.name`)}</div>
|
||||
<Checkbox className='shrink-0' checked={selected} />
|
||||
<div>
|
||||
<div className="flex items-center border-b border-divider-subtle p-3 pb-2">
|
||||
<FileTypeIcon className="shrink-0" type={type} size="lg" />
|
||||
<div className="system-sm-medium mx-2 grow text-text-primary">{t(`appDebug.variableConfig.file.${type}.name`)}</div>
|
||||
<Checkbox className="shrink-0" checked={selected} />
|
||||
</div>
|
||||
<div className="p-3" onClick={e => e.stopPropagation()}>
|
||||
<TagInput
|
||||
items={customFileTypes}
|
||||
onChange={onCustomFileTypesChange}
|
||||
placeholder={t('appDebug.variableConfig.file.custom.createPlaceholder')!}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className='p-3' onClick={e => e.stopPropagation()}>
|
||||
<TagInput
|
||||
items={customFileTypes}
|
||||
onChange={onCustomFileTypesChange}
|
||||
placeholder={t('appDebug.variableConfig.file.custom.createPlaceholder')!}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
)
|
||||
: (
|
||||
<div className='flex items-center'>
|
||||
<FileTypeIcon className='shrink-0' type={type} size='lg' />
|
||||
<div className='mx-2 grow'>
|
||||
<div className='system-sm-medium text-text-primary'>{t(`appDebug.variableConfig.file.${type}.name`)}</div>
|
||||
<div className='system-2xs-regular-uppercase mt-1 text-text-tertiary'>{type !== SupportUploadFileTypes.custom ? FILE_EXTS[type].join(', ') : t('appDebug.variableConfig.file.custom.description')}</div>
|
||||
<div className="flex items-center">
|
||||
<FileTypeIcon className="shrink-0" type={type} size="lg" />
|
||||
<div className="mx-2 grow">
|
||||
<div className="system-sm-medium text-text-primary">{t(`appDebug.variableConfig.file.${type}.name`)}</div>
|
||||
<div className="system-2xs-regular-uppercase mt-1 text-text-tertiary">{type !== SupportUploadFileTypes.custom ? FILE_EXTS[type].join(', ') : t('appDebug.variableConfig.file.custom.description')}</div>
|
||||
</div>
|
||||
<Checkbox className="shrink-0" checked={selected} />
|
||||
</div>
|
||||
<Checkbox className='shrink-0' checked={selected} />
|
||||
</div>
|
||||
)}
|
||||
)}
|
||||
|
||||
</div>
|
||||
)
|
||||
|
||||
@ -1,18 +1,18 @@
|
||||
'use client'
|
||||
import type { FC } from 'react'
|
||||
import React, { useCallback } from 'react'
|
||||
import { produce } from 'immer'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import type { UploadFileSetting } from '../../../types'
|
||||
import { produce } from 'immer'
|
||||
import React, { useCallback } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import Field from '@/app/components/app/configuration/config-var/config-modal/field'
|
||||
import { useFileSizeLimit } from '@/app/components/base/file-uploader/hooks'
|
||||
import { useFileUploadConfig } from '@/service/use-common'
|
||||
import { TransferMethod } from '@/types/app'
|
||||
import { formatFileSize } from '@/utils/format'
|
||||
import { SupportUploadFileTypes } from '../../../types'
|
||||
import OptionCard from './option-card'
|
||||
import FileTypeItem from './file-type-item'
|
||||
import InputNumberWithSlider from './input-number-with-slider'
|
||||
import Field from '@/app/components/app/configuration/config-var/config-modal/field'
|
||||
import { TransferMethod } from '@/types/app'
|
||||
import { useFileSizeLimit } from '@/app/components/base/file-uploader/hooks'
|
||||
import { formatFileSize } from '@/utils/format'
|
||||
import { useFileUploadConfig } from '@/service/use-common'
|
||||
import OptionCard from './option-card'
|
||||
|
||||
type Props = {
|
||||
payload: UploadFileSetting
|
||||
@ -100,7 +100,7 @@ const FileUploadSetting: FC<Props> = ({
|
||||
<Field
|
||||
title={t('appDebug.variableConfig.file.supportFileTypes')}
|
||||
>
|
||||
<div className='space-y-1'>
|
||||
<div className="space-y-1">
|
||||
{
|
||||
[SupportUploadFileTypes.document, SupportUploadFileTypes.image, SupportUploadFileTypes.audio, SupportUploadFileTypes.video].map((type: SupportUploadFileTypes) => (
|
||||
<FileTypeItem
|
||||
@ -123,9 +123,9 @@ const FileUploadSetting: FC<Props> = ({
|
||||
)}
|
||||
<Field
|
||||
title={t('appDebug.variableConfig.uploadFileTypes')}
|
||||
className='mt-4'
|
||||
className="mt-4"
|
||||
>
|
||||
<div className='grid grid-cols-3 gap-2'>
|
||||
<div className="grid grid-cols-3 gap-2">
|
||||
<OptionCard
|
||||
title={t('appDebug.variableConfig.localUpload')}
|
||||
selected={allowed_file_upload_methods.length === 1 && allowed_file_upload_methods.includes(TransferMethod.local_file)}
|
||||
@ -145,16 +145,18 @@ const FileUploadSetting: FC<Props> = ({
|
||||
</Field>
|
||||
{isMultiple && (
|
||||
<Field
|
||||
className='mt-4'
|
||||
className="mt-4"
|
||||
title={t('appDebug.variableConfig.maxNumberOfUploads')!}
|
||||
>
|
||||
<div>
|
||||
<div className='body-xs-regular mb-1.5 text-text-tertiary'>{t('appDebug.variableConfig.maxNumberTip', {
|
||||
imgLimit: formatFileSize(imgSizeLimit),
|
||||
docLimit: formatFileSize(docSizeLimit),
|
||||
audioLimit: formatFileSize(audioSizeLimit),
|
||||
videoLimit: formatFileSize(videoSizeLimit),
|
||||
})}</div>
|
||||
<div className="body-xs-regular mb-1.5 text-text-tertiary">
|
||||
{t('appDebug.variableConfig.maxNumberTip', {
|
||||
imgLimit: formatFileSize(imgSizeLimit),
|
||||
docLimit: formatFileSize(docSizeLimit),
|
||||
audioLimit: formatFileSize(audioSizeLimit),
|
||||
videoLimit: formatFileSize(videoSizeLimit),
|
||||
})}
|
||||
</div>
|
||||
|
||||
<InputNumberWithSlider
|
||||
value={max_length}
|
||||
@ -168,9 +170,9 @@ const FileUploadSetting: FC<Props> = ({
|
||||
{inFeaturePanel && !hideSupportFileType && (
|
||||
<Field
|
||||
title={t('appDebug.variableConfig.file.supportFileTypes')}
|
||||
className='mt-4'
|
||||
className="mt-4"
|
||||
>
|
||||
<div className='space-y-1'>
|
||||
<div className="space-y-1">
|
||||
{
|
||||
[SupportUploadFileTypes.document, SupportUploadFileTypes.image, SupportUploadFileTypes.audio, SupportUploadFileTypes.video].map((type: SupportUploadFileTypes) => (
|
||||
<FileTypeItem
|
||||
|
||||
@ -12,7 +12,7 @@ const FormInputBoolean: FC<Props> = ({
|
||||
onChange,
|
||||
}) => {
|
||||
return (
|
||||
<div className='flex w-full space-x-1'>
|
||||
<div className="flex w-full space-x-1">
|
||||
<div
|
||||
className={cn(
|
||||
'system-sm-regular flex h-8 grow cursor-default items-center justify-center rounded-md border border-components-option-card-option-border bg-components-option-card-option-bg px-2 text-text-secondary',
|
||||
@ -20,7 +20,9 @@ const FormInputBoolean: FC<Props> = ({
|
||||
value && 'system-sm-medium border-[1.5px] border-components-option-card-option-selected-border bg-components-option-card-option-selected-bg shadow-xs',
|
||||
)}
|
||||
onClick={() => onChange(true)}
|
||||
>True</div>
|
||||
>
|
||||
True
|
||||
</div>
|
||||
<div
|
||||
className={cn(
|
||||
'system-sm-regular flex h-8 grow cursor-default items-center justify-center rounded-md border border-components-option-card-option-border bg-components-option-card-option-bg px-2 text-text-secondary',
|
||||
@ -28,7 +30,9 @@ const FormInputBoolean: FC<Props> = ({
|
||||
!value && 'system-sm-medium border-[1.5px] border-components-option-card-option-selected-border bg-components-option-card-option-selected-bg shadow-xs',
|
||||
)}
|
||||
onClick={() => onChange(false)}
|
||||
>False</div>
|
||||
>
|
||||
False
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@ -1,35 +1,35 @@
|
||||
'use client'
|
||||
import type { FC } from 'react'
|
||||
import { useEffect, useMemo, useState } from 'react'
|
||||
import { type ResourceVarInputs, VarKindType } from '../types'
|
||||
import type { ResourceVarInputs } from '../types'
|
||||
import type { CredentialFormSchema, FormOption } from '@/app/components/header/account-setting/model-provider-page/declarations'
|
||||
import { useLanguage } from '@/app/components/header/account-setting/model-provider-page/hooks'
|
||||
import type { Event, Tool } from '@/app/components/tools/types'
|
||||
import type { TriggerWithProvider } from '@/app/components/workflow/block-selector/types'
|
||||
import type { ToolWithProvider, ValueSelector, Var } from '@/app/components/workflow/types'
|
||||
import { Listbox, ListboxButton, ListboxOption, ListboxOptions } from '@headlessui/react'
|
||||
import { ChevronDownIcon } from '@heroicons/react/20/solid'
|
||||
|
||||
import { RiCheckLine, RiLoader4Line } from '@remixicon/react'
|
||||
import { useEffect, useMemo, useState } from 'react'
|
||||
import CheckboxList from '@/app/components/base/checkbox-list'
|
||||
import Input from '@/app/components/base/input'
|
||||
import { SimpleSelect } from '@/app/components/base/select'
|
||||
import { FormTypeEnum } from '@/app/components/header/account-setting/model-provider-page/declarations'
|
||||
import { useLanguage } from '@/app/components/header/account-setting/model-provider-page/hooks'
|
||||
import AppSelector from '@/app/components/plugins/plugin-detail-panel/app-selector'
|
||||
import ModelParameterModal from '@/app/components/plugins/plugin-detail-panel/model-selector'
|
||||
import { PluginCategoryEnum } from '@/app/components/plugins/types'
|
||||
import CodeEditor from '@/app/components/workflow/nodes/_base/components/editor/code-editor'
|
||||
import VarReferencePicker from '@/app/components/workflow/nodes/_base/components/variable/var-reference-picker'
|
||||
import useAvailableVarList from '@/app/components/workflow/nodes/_base/hooks/use-available-var-list'
|
||||
import { CodeLanguage } from '@/app/components/workflow/nodes/code/types'
|
||||
import MixedVariableTextInput from '@/app/components/workflow/nodes/tool/components/mixed-variable-text-input'
|
||||
import { VarType } from '@/app/components/workflow/types'
|
||||
import { useFetchDynamicOptions } from '@/service/use-plugins'
|
||||
import { useTriggerPluginDynamicOptions } from '@/service/use-triggers'
|
||||
|
||||
import type { ToolWithProvider, ValueSelector, Var } from '@/app/components/workflow/types'
|
||||
import type { TriggerWithProvider } from '@/app/components/workflow/block-selector/types'
|
||||
import type { Tool } from '@/app/components/tools/types'
|
||||
import FormInputTypeSwitch from './form-input-type-switch'
|
||||
import useAvailableVarList from '@/app/components/workflow/nodes/_base/hooks/use-available-var-list'
|
||||
import Input from '@/app/components/base/input'
|
||||
import { SimpleSelect } from '@/app/components/base/select'
|
||||
import MixedVariableTextInput from '@/app/components/workflow/nodes/tool/components/mixed-variable-text-input'
|
||||
import AppSelector from '@/app/components/plugins/plugin-detail-panel/app-selector'
|
||||
import ModelParameterModal from '@/app/components/plugins/plugin-detail-panel/model-selector'
|
||||
import VarReferencePicker from '@/app/components/workflow/nodes/_base/components/variable/var-reference-picker'
|
||||
import CodeEditor from '@/app/components/workflow/nodes/_base/components/editor/code-editor'
|
||||
import { CodeLanguage } from '@/app/components/workflow/nodes/code/types'
|
||||
import { cn } from '@/utils/classnames'
|
||||
import { Listbox, ListboxButton, ListboxOption, ListboxOptions } from '@headlessui/react'
|
||||
import { ChevronDownIcon } from '@heroicons/react/20/solid'
|
||||
import { RiCheckLine, RiLoader4Line } from '@remixicon/react'
|
||||
import type { Event } from '@/app/components/tools/types'
|
||||
import { PluginCategoryEnum } from '@/app/components/plugins/types'
|
||||
import CheckboxList from '@/app/components/base/checkbox-list'
|
||||
import { VarKindType } from '../types'
|
||||
import FormInputBoolean from './form-input-boolean'
|
||||
import FormInputTypeSwitch from './form-input-type-switch'
|
||||
|
||||
type Props = {
|
||||
readOnly: boolean
|
||||
@ -284,7 +284,7 @@ const FormInputItem: FC<Props> = ({
|
||||
}
|
||||
|
||||
const availableCheckboxOptions = useMemo(() => (
|
||||
(options || []).filter((option: { show_on?: Array<{ variable: string; value: any }> }) => {
|
||||
(options || []).filter((option: { show_on?: Array<{ variable: string, value: any }> }) => {
|
||||
if (option.show_on?.length)
|
||||
return option.show_on.every(showOnItem => value[showOnItem.variable]?.value === showOnItem.value || value[showOnItem.variable] === showOnItem.value)
|
||||
return true
|
||||
@ -292,7 +292,7 @@ const FormInputItem: FC<Props> = ({
|
||||
), [options, value])
|
||||
|
||||
const checkboxListOptions = useMemo(() => (
|
||||
availableCheckboxOptions.map((option: { value: string; label: Record<string, string> }) => ({
|
||||
availableCheckboxOptions.map((option: { value: string, label: Record<string, string> }) => ({
|
||||
value: option.value,
|
||||
label: option.label?.[language] || option.label?.en_US || option.value,
|
||||
}))
|
||||
@ -341,8 +341,8 @@ const FormInputItem: FC<Props> = ({
|
||||
)}
|
||||
{isNumber && isConstant && (
|
||||
<Input
|
||||
className='h-8 grow'
|
||||
type='number'
|
||||
className="h-8 grow"
|
||||
type="number"
|
||||
value={Number.isNaN(varInput?.value) ? '' : varInput?.value}
|
||||
onChange={e => handleValueChange(e.target.value)}
|
||||
placeholder={placeholder?.[language] || placeholder?.en_US}
|
||||
@ -355,7 +355,7 @@ const FormInputItem: FC<Props> = ({
|
||||
onChange={handleCheckboxListChange}
|
||||
options={checkboxListOptions}
|
||||
disabled={readOnly}
|
||||
maxHeight='200px'
|
||||
maxHeight="200px"
|
||||
/>
|
||||
)}
|
||||
{isBoolean && isConstant && (
|
||||
@ -366,7 +366,7 @@ const FormInputItem: FC<Props> = ({
|
||||
)}
|
||||
{isSelect && isConstant && !isMultipleSelect && (
|
||||
<SimpleSelect
|
||||
wrapperClassName='h-8 grow'
|
||||
wrapperClassName="h-8 grow"
|
||||
disabled={readOnly}
|
||||
defaultValue={varInput?.value}
|
||||
items={options.filter((option: { show_on: any[] }) => {
|
||||
@ -374,21 +374,23 @@ const FormInputItem: FC<Props> = ({
|
||||
return option.show_on.every(showOnItem => value[showOnItem.variable] === showOnItem.value)
|
||||
|
||||
return true
|
||||
}).map((option: { value: any; label: { [x: string]: any; en_US: any }; icon?: string }) => ({
|
||||
}).map((option: { value: any, label: { [x: string]: any, en_US: any }, icon?: string }) => ({
|
||||
value: option.value,
|
||||
name: option.label[language] || option.label.en_US,
|
||||
icon: option.icon,
|
||||
}))}
|
||||
onSelect={item => handleValueChange(item.value as string)}
|
||||
placeholder={placeholder?.[language] || placeholder?.en_US}
|
||||
renderOption={options.some((opt: any) => opt.icon) ? ({ item }) => (
|
||||
<div className="flex items-center">
|
||||
{item.icon && (
|
||||
<img src={item.icon} alt="" className="mr-2 h-4 w-4" />
|
||||
)}
|
||||
<span>{item.name}</span>
|
||||
</div>
|
||||
) : undefined}
|
||||
renderOption={options.some((opt: any) => opt.icon)
|
||||
? ({ item }) => (
|
||||
<div className="flex items-center">
|
||||
{item.icon && (
|
||||
<img src={item.icon} alt="" className="mr-2 h-4 w-4" />
|
||||
)}
|
||||
<span>{item.name}</span>
|
||||
</div>
|
||||
)
|
||||
: undefined}
|
||||
/>
|
||||
)}
|
||||
{isSelect && isConstant && isMultipleSelect && (
|
||||
@ -400,9 +402,7 @@ const FormInputItem: FC<Props> = ({
|
||||
>
|
||||
<div className="group/simple-select relative h-8 grow">
|
||||
<ListboxButton className="flex h-full w-full cursor-pointer items-center rounded-lg border-0 bg-components-input-bg-normal pl-3 pr-10 focus-visible:bg-state-base-hover-alt focus-visible:outline-none group-hover/simple-select:bg-state-base-hover-alt sm:text-sm sm:leading-6">
|
||||
<span className={cn('system-sm-regular block truncate text-left',
|
||||
varInput?.value?.length > 0 ? 'text-components-input-text-filled' : 'text-components-input-text-placeholder',
|
||||
)}>
|
||||
<span className={cn('system-sm-regular block truncate text-left', varInput?.value?.length > 0 ? 'text-components-input-text-filled' : 'text-components-input-text-placeholder')}>
|
||||
{getSelectedLabels(varInput?.value) || placeholder?.[language] || placeholder?.en_US || 'Select options'}
|
||||
</span>
|
||||
<span className="absolute inset-y-0 right-0 flex items-center pr-2">
|
||||
@ -417,15 +417,12 @@ const FormInputItem: FC<Props> = ({
|
||||
if (option.show_on?.length)
|
||||
return option.show_on.every(showOnItem => value[showOnItem.variable] === showOnItem.value)
|
||||
return true
|
||||
}).map((option: { value: any; label: { [x: string]: any; en_US: any }; icon?: string }) => (
|
||||
}).map((option: { value: any, label: { [x: string]: any, en_US: any }, icon?: string }) => (
|
||||
<ListboxOption
|
||||
key={option.value}
|
||||
value={option.value}
|
||||
className={({ focus }) =>
|
||||
cn('relative cursor-pointer select-none rounded-lg py-2 pl-3 pr-9 text-text-secondary hover:bg-state-base-hover',
|
||||
focus && 'bg-state-base-hover',
|
||||
)
|
||||
}
|
||||
cn('relative cursor-pointer select-none rounded-lg py-2 pl-3 pr-9 text-text-secondary hover:bg-state-base-hover', focus && 'bg-state-base-hover')}
|
||||
>
|
||||
{({ selected }) => (
|
||||
<>
|
||||
@ -452,7 +449,7 @@ const FormInputItem: FC<Props> = ({
|
||||
)}
|
||||
{isDynamicSelect && !isMultipleSelect && (
|
||||
<SimpleSelect
|
||||
wrapperClassName='h-8 grow'
|
||||
wrapperClassName="h-8 grow"
|
||||
disabled={readOnly || isLoadingOptions}
|
||||
defaultValue={varInput?.value}
|
||||
items={(dynamicOptions || options || []).filter((option: { show_on?: any[] }) => {
|
||||
@ -460,7 +457,7 @@ const FormInputItem: FC<Props> = ({
|
||||
return option.show_on.every(showOnItem => value[showOnItem.variable] === showOnItem.value)
|
||||
|
||||
return true
|
||||
}).map((option: { value: any; label: { [x: string]: any; en_US: any }; icon?: string }) => ({
|
||||
}).map((option: { value: any, label: { [x: string]: any, en_US: any }, icon?: string }) => ({
|
||||
value: option.value,
|
||||
name: option.label[language] || option.label.en_US,
|
||||
icon: option.icon,
|
||||
@ -486,23 +483,25 @@ const FormInputItem: FC<Props> = ({
|
||||
>
|
||||
<div className="group/simple-select relative h-8 grow">
|
||||
<ListboxButton className="flex h-full w-full cursor-pointer items-center rounded-lg border-0 bg-components-input-bg-normal pl-3 pr-10 focus-visible:bg-state-base-hover-alt focus-visible:outline-none group-hover/simple-select:bg-state-base-hover-alt sm:text-sm sm:leading-6">
|
||||
<span className={cn('system-sm-regular block truncate text-left',
|
||||
isLoadingOptions ? 'text-components-input-text-placeholder'
|
||||
: varInput?.value?.length > 0 ? 'text-components-input-text-filled' : 'text-components-input-text-placeholder',
|
||||
)}>
|
||||
<span className={cn('system-sm-regular block truncate text-left', isLoadingOptions
|
||||
? 'text-components-input-text-placeholder'
|
||||
: varInput?.value?.length > 0 ? 'text-components-input-text-filled' : 'text-components-input-text-placeholder')}
|
||||
>
|
||||
{isLoadingOptions
|
||||
? 'Loading...'
|
||||
: getSelectedLabels(varInput?.value) || placeholder?.[language] || placeholder?.en_US || 'Select options'}
|
||||
</span>
|
||||
<span className="absolute inset-y-0 right-0 flex items-center pr-2">
|
||||
{isLoadingOptions ? (
|
||||
<RiLoader4Line className='h-3.5 w-3.5 animate-spin text-text-secondary' />
|
||||
) : (
|
||||
<ChevronDownIcon
|
||||
className="h-4 w-4 text-text-quaternary group-hover/simple-select:text-text-secondary"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
)}
|
||||
{isLoadingOptions
|
||||
? (
|
||||
<RiLoader4Line className="h-3.5 w-3.5 animate-spin text-text-secondary" />
|
||||
)
|
||||
: (
|
||||
<ChevronDownIcon
|
||||
className="h-4 w-4 text-text-quaternary group-hover/simple-select:text-text-secondary"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
)}
|
||||
</span>
|
||||
</ListboxButton>
|
||||
<ListboxOptions className="absolute z-10 mt-1 max-h-60 w-full overflow-auto rounded-xl border-[0.5px] border-components-panel-border bg-components-panel-bg-blur px-1 py-1 text-base shadow-lg backdrop-blur-sm focus:outline-none sm:text-sm">
|
||||
@ -510,15 +509,12 @@ const FormInputItem: FC<Props> = ({
|
||||
if (option.show_on?.length)
|
||||
return option.show_on.every(showOnItem => value[showOnItem.variable] === showOnItem.value)
|
||||
return true
|
||||
}).map((option: { value: any; label: { [x: string]: any; en_US: any }; icon?: string }) => (
|
||||
}).map((option: { value: any, label: { [x: string]: any, en_US: any }, icon?: string }) => (
|
||||
<ListboxOption
|
||||
key={option.value}
|
||||
value={option.value}
|
||||
className={({ focus }) =>
|
||||
cn('relative cursor-pointer select-none rounded-lg py-2 pl-3 pr-9 text-text-secondary hover:bg-state-base-hover',
|
||||
focus && 'bg-state-base-hover',
|
||||
)
|
||||
}
|
||||
cn('relative cursor-pointer select-none rounded-lg py-2 pl-3 pr-9 text-text-secondary hover:bg-state-base-hover', focus && 'bg-state-base-hover')}
|
||||
>
|
||||
{({ selected }) => (
|
||||
<>
|
||||
@ -544,16 +540,16 @@ const FormInputItem: FC<Props> = ({
|
||||
</Listbox>
|
||||
)}
|
||||
{isShowJSONEditor && isConstant && (
|
||||
<div className='mt-1 w-full'>
|
||||
<div className="mt-1 w-full">
|
||||
<CodeEditor
|
||||
title='JSON'
|
||||
title="JSON"
|
||||
value={varInput?.value as any}
|
||||
isExpand
|
||||
isInNode
|
||||
language={CodeLanguage.json}
|
||||
onChange={handleValueChange}
|
||||
className='w-full'
|
||||
placeholder={<div className='whitespace-pre'>{placeholder?.[language] || placeholder?.en_US}</div>}
|
||||
className="w-full"
|
||||
placeholder={<div className="whitespace-pre">{placeholder?.[language] || placeholder?.en_US}</div>}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
@ -567,7 +563,7 @@ const FormInputItem: FC<Props> = ({
|
||||
)}
|
||||
{isModelSelector && isConstant && (
|
||||
<ModelParameterModal
|
||||
popupClassName='!w-[387px]'
|
||||
popupClassName="!w-[387px]"
|
||||
isAdvancedMode
|
||||
isInWorkflow
|
||||
value={varInput?.value}
|
||||
@ -579,7 +575,7 @@ const FormInputItem: FC<Props> = ({
|
||||
{showVariableSelector && (
|
||||
<VarReferencePicker
|
||||
zIndex={inPanel ? 1000 : undefined}
|
||||
className='h-8 grow'
|
||||
className="h-8 grow"
|
||||
readonly={readOnly}
|
||||
isShowNodeName
|
||||
nodeId={nodeId}
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
'use client'
|
||||
import type { FC } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import {
|
||||
RiEditLine,
|
||||
} from '@remixicon/react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { Variable02 } from '@/app/components/base/icons/src/vender/solid/development'
|
||||
import Tooltip from '@/app/components/base/tooltip'
|
||||
import { VarType } from '@/app/components/workflow/nodes/tool/types'
|
||||
@ -20,7 +20,7 @@ const FormInputTypeSwitch: FC<Props> = ({
|
||||
}) => {
|
||||
const { t } = useTranslation()
|
||||
return (
|
||||
<div className='inline-flex h-8 shrink-0 gap-px rounded-[10px] bg-components-segmented-control-bg-normal p-0.5'>
|
||||
<div className="inline-flex h-8 shrink-0 gap-px rounded-[10px] bg-components-segmented-control-bg-normal p-0.5">
|
||||
<Tooltip
|
||||
popupContent={value === VarType.variable ? '' : t('workflow.nodes.common.typeSwitch.variable')}
|
||||
>
|
||||
@ -28,7 +28,7 @@ const FormInputTypeSwitch: FC<Props> = ({
|
||||
className={cn('cursor-pointer rounded-lg px-2.5 py-1.5 text-text-tertiary hover:bg-state-base-hover', value === VarType.variable && 'bg-components-segmented-control-item-active-bg text-text-secondary shadow-xs hover:bg-components-segmented-control-item-active-bg')}
|
||||
onClick={() => onChange(VarType.variable)}
|
||||
>
|
||||
<Variable02 className='h-4 w-4' />
|
||||
<Variable02 className="h-4 w-4" />
|
||||
</div>
|
||||
</Tooltip>
|
||||
<Tooltip
|
||||
@ -38,7 +38,7 @@ const FormInputTypeSwitch: FC<Props> = ({
|
||||
className={cn('cursor-pointer rounded-lg px-2.5 py-1.5 text-text-tertiary hover:bg-state-base-hover', value === VarType.constant && 'bg-components-segmented-control-item-active-bg text-text-secondary shadow-xs hover:bg-components-segmented-control-item-active-bg')}
|
||||
onClick={() => onChange(VarType.constant)}
|
||||
>
|
||||
<RiEditLine className='h-4 w-4' />
|
||||
<RiEditLine className="h-4 w-4" />
|
||||
</div>
|
||||
</Tooltip>
|
||||
</div>
|
||||
|
||||
@ -1,13 +1,15 @@
|
||||
import { cn } from '@/utils/classnames'
|
||||
import type { ComponentProps, FC, PropsWithChildren, ReactNode } from 'react'
|
||||
import { cn } from '@/utils/classnames'
|
||||
|
||||
export type GroupLabelProps = ComponentProps<'div'>
|
||||
|
||||
export const GroupLabel: FC<GroupLabelProps> = (props) => {
|
||||
const { children, className, ...rest } = props
|
||||
return <div {...rest} className={cn('system-2xs-medium-uppercase mb-1 text-text-tertiary', className)}>
|
||||
{children}
|
||||
</div>
|
||||
return (
|
||||
<div {...rest} className={cn('system-2xs-medium-uppercase mb-1 text-text-tertiary', className)}>
|
||||
{children}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export type GroupProps = PropsWithChildren<{
|
||||
@ -16,10 +18,12 @@ export type GroupProps = PropsWithChildren<{
|
||||
|
||||
export const Group: FC<GroupProps> = (props) => {
|
||||
const { children, label } = props
|
||||
return <div className={cn('py-1')}>
|
||||
{label}
|
||||
<div className='space-y-0.5'>
|
||||
{children}
|
||||
return (
|
||||
<div className={cn('py-1')}>
|
||||
{label}
|
||||
<div className="space-y-0.5">
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
import type { BlockEnum } from '@/app/components/workflow/types'
|
||||
import { RiBookOpenLine } from '@remixicon/react'
|
||||
import { memo } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { RiBookOpenLine } from '@remixicon/react'
|
||||
import { useNodeHelpLink } from '../hooks/use-node-help-link'
|
||||
import TooltipPlus from '@/app/components/base/tooltip'
|
||||
import type { BlockEnum } from '@/app/components/workflow/types'
|
||||
import { useNodeHelpLink } from '../hooks/use-node-help-link'
|
||||
|
||||
type HelpLinkProps = {
|
||||
nodeType: BlockEnum
|
||||
@ -23,10 +23,10 @@ const HelpLink = ({
|
||||
>
|
||||
<a
|
||||
href={link}
|
||||
target='_blank'
|
||||
className='mr-1 flex h-6 w-6 items-center justify-center rounded-md hover:bg-state-base-hover'
|
||||
target="_blank"
|
||||
className="mr-1 flex h-6 w-6 items-center justify-center rounded-md hover:bg-state-base-hover"
|
||||
>
|
||||
<RiBookOpenLine className='h-4 w-4 text-gray-500' />
|
||||
<RiBookOpenLine className="h-4 w-4 text-gray-500" />
|
||||
</a>
|
||||
</TooltipPlus>
|
||||
|
||||
|
||||
@ -13,11 +13,11 @@ const InfoPanel: FC<Props> = ({
|
||||
}) => {
|
||||
return (
|
||||
<div>
|
||||
<div className='flex flex-col gap-y-0.5 rounded-md bg-workflow-block-parma-bg px-[5px] py-[3px]'>
|
||||
<div className='system-2xs-semibold-uppercase uppercase text-text-secondary'>
|
||||
<div className="flex flex-col gap-y-0.5 rounded-md bg-workflow-block-parma-bg px-[5px] py-[3px]">
|
||||
<div className="system-2xs-semibold-uppercase uppercase text-text-secondary">
|
||||
{title}
|
||||
</div>
|
||||
<div className='system-xs-regular break-words text-text-tertiary'>
|
||||
<div className="system-xs-regular break-words text-text-tertiary">
|
||||
{content}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -4,7 +4,7 @@ import ActionButton from '@/app/components/base/action-button'
|
||||
const Add = () => {
|
||||
return (
|
||||
<ActionButton>
|
||||
<RiAddLine className='h-4 w-4' />
|
||||
<RiAddLine className="h-4 w-4" />
|
||||
</ActionButton>
|
||||
)
|
||||
}
|
||||
|
||||
@ -38,11 +38,11 @@ const InputNumberWithSlider: FC<InputNumberWithSliderProps> = ({
|
||||
}, [onChange])
|
||||
|
||||
return (
|
||||
<div className='flex h-8 items-center justify-between space-x-2'>
|
||||
<div className="flex h-8 items-center justify-between space-x-2">
|
||||
<input
|
||||
value={value}
|
||||
className='block h-8 w-12 shrink-0 appearance-none rounded-lg bg-components-input-bg-normal pl-3 text-[13px] text-components-input-text-filled outline-none'
|
||||
type='number'
|
||||
className="block h-8 w-12 shrink-0 appearance-none rounded-lg bg-components-input-bg-normal pl-3 text-[13px] text-components-input-text-filled outline-none"
|
||||
type="number"
|
||||
min={min}
|
||||
max={max}
|
||||
step={1}
|
||||
@ -51,7 +51,7 @@ const InputNumberWithSlider: FC<InputNumberWithSliderProps> = ({
|
||||
disabled={readonly}
|
||||
/>
|
||||
<Slider
|
||||
className='grow'
|
||||
className="grow"
|
||||
value={value}
|
||||
min={min}
|
||||
max={max}
|
||||
|
||||
@ -1,19 +1,19 @@
|
||||
'use client'
|
||||
import type { FC } from 'react'
|
||||
import React, { useEffect } from 'react'
|
||||
import { useBoolean } from 'ahooks'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { cn } from '@/utils/classnames'
|
||||
import type {
|
||||
Node,
|
||||
NodeOutPutVar,
|
||||
} from '@/app/components/workflow/types'
|
||||
import { BlockEnum } from '@/app/components/workflow/types'
|
||||
import PromptEditor from '@/app/components/base/prompt-editor'
|
||||
import { Variable02 } from '@/app/components/base/icons/src/vender/solid/development'
|
||||
import Tooltip from '@/app/components/base/tooltip'
|
||||
import { useBoolean } from 'ahooks'
|
||||
import { noop } from 'lodash-es'
|
||||
import React, { useEffect } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { Variable02 } from '@/app/components/base/icons/src/vender/solid/development'
|
||||
import PromptEditor from '@/app/components/base/prompt-editor'
|
||||
import Tooltip from '@/app/components/base/tooltip'
|
||||
import { useStore } from '@/app/components/workflow/store'
|
||||
import { BlockEnum } from '@/app/components/workflow/types'
|
||||
import { cn } from '@/utils/classnames'
|
||||
|
||||
type Props = {
|
||||
instanceId?: string
|
||||
@ -115,20 +115,20 @@ const Editor: FC<Props> = ({
|
||||
onFocus={setFocus}
|
||||
/>
|
||||
{/* to patch Editor not support dynamic change editable status */}
|
||||
{readOnly && <div className='absolute inset-0 z-10'></div>}
|
||||
{readOnly && <div className="absolute inset-0 z-10"></div>}
|
||||
{isFocus && (
|
||||
<div className={cn('absolute z-10', insertVarTipToLeft ? 'left-[-12px] top-1.5' : ' right-1 top-[-9px]')}>
|
||||
<Tooltip
|
||||
popupContent={`${t('workflow.common.insertVarTip')}`}
|
||||
>
|
||||
<div className='cursor-pointer rounded-[5px] border-[0.5px] border-divider-regular bg-components-badge-white-to-dark p-0.5 shadow-lg'>
|
||||
<Variable02 className='h-3.5 w-3.5 text-components-button-secondary-accent-text' />
|
||||
<div className="cursor-pointer rounded-[5px] border-[0.5px] border-divider-regular bg-components-badge-white-to-dark p-0.5 shadow-lg">
|
||||
<Variable02 className="h-3.5 w-3.5 text-components-button-secondary-accent-text" />
|
||||
</div>
|
||||
</Tooltip>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
</div >
|
||||
</div>
|
||||
)
|
||||
}
|
||||
export default React.memo(Editor)
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
'use client'
|
||||
import type { FC } from 'react'
|
||||
import React from 'react'
|
||||
import {
|
||||
RiAlignLeft,
|
||||
RiBracesLine,
|
||||
@ -11,6 +10,7 @@ import {
|
||||
RiHashtag,
|
||||
RiTextSnippet,
|
||||
} from '@remixicon/react'
|
||||
import React from 'react'
|
||||
import { InputVarType } from '../../../types'
|
||||
|
||||
type Props = {
|
||||
|
||||
@ -1,12 +1,12 @@
|
||||
import Button from '@/app/components/base/button'
|
||||
import { RiInstallLine, RiLoader2Line } from '@remixicon/react'
|
||||
import type { ComponentProps, MouseEventHandler } from 'react'
|
||||
import { RiInstallLine, RiLoader2Line } from '@remixicon/react'
|
||||
import { useState } from 'react'
|
||||
import { cn } from '@/utils/classnames'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import Button from '@/app/components/base/button'
|
||||
import checkTaskStatus from '@/app/components/plugins/install-plugin/base/check-task-status'
|
||||
import { TaskStatus } from '@/app/components/plugins/types'
|
||||
import { useCheckInstalled, useInstallPackageFromMarketPlace } from '@/service/use-plugins'
|
||||
import { cn } from '@/utils/classnames'
|
||||
|
||||
type InstallPluginButtonProps = Omit<ComponentProps<typeof Button>, 'children' | 'loading'> & {
|
||||
uniqueIdentifier: string
|
||||
@ -83,22 +83,26 @@ export const InstallPluginButton = (props: InstallPluginButtonProps) => {
|
||||
},
|
||||
})
|
||||
}
|
||||
if (!manifest.data) return null
|
||||
if (!manifest.data)
|
||||
return null
|
||||
const identifierSet = new Set(identifiers)
|
||||
const isInstalled = manifest.data.plugins.some(plugin => (
|
||||
identifierSet.has(plugin.id)
|
||||
|| (plugin.plugin_unique_identifier && identifierSet.has(plugin.plugin_unique_identifier))
|
||||
|| (plugin.plugin_id && identifierSet.has(plugin.plugin_id))
|
||||
))
|
||||
if (isInstalled) return null
|
||||
return <Button
|
||||
variant={'secondary'}
|
||||
disabled={isLoading}
|
||||
{...rest}
|
||||
onClick={handleInstall}
|
||||
className={cn('flex items-center', className)}
|
||||
>
|
||||
{!isLoading ? t('workflow.nodes.agent.pluginInstaller.install') : t('workflow.nodes.agent.pluginInstaller.installing')}
|
||||
{!isLoading ? <RiInstallLine className='ml-1 size-3.5' /> : <RiLoader2Line className='ml-1 size-3.5 animate-spin' />}
|
||||
</Button>
|
||||
if (isInstalled)
|
||||
return null
|
||||
return (
|
||||
<Button
|
||||
variant="secondary"
|
||||
disabled={isLoading}
|
||||
{...rest}
|
||||
onClick={handleInstall}
|
||||
className={cn('flex items-center', className)}
|
||||
>
|
||||
{!isLoading ? t('workflow.nodes.agent.pluginInstaller.install') : t('workflow.nodes.agent.pluginInstaller.installing')}
|
||||
{!isLoading ? <RiInstallLine className="ml-1 size-3.5" /> : <RiLoader2Line className="ml-1 size-3.5 animate-spin" />}
|
||||
</Button>
|
||||
)
|
||||
}
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
import type { ReactNode } from 'react'
|
||||
import { memo } from 'react'
|
||||
import type {
|
||||
BoxGroupProps,
|
||||
FieldProps,
|
||||
} from '.'
|
||||
import { memo } from 'react'
|
||||
import {
|
||||
BoxGroup,
|
||||
Field,
|
||||
|
||||
@ -1,13 +1,13 @@
|
||||
import type { ReactNode } from 'react'
|
||||
import type {
|
||||
BoxProps,
|
||||
GroupProps,
|
||||
} from '.'
|
||||
import { memo } from 'react'
|
||||
import {
|
||||
Box,
|
||||
Group,
|
||||
} from '.'
|
||||
import type {
|
||||
BoxProps,
|
||||
GroupProps,
|
||||
} from '.'
|
||||
|
||||
export type BoxGroupProps = {
|
||||
children?: ReactNode
|
||||
|
||||
@ -18,7 +18,8 @@ export const Box = memo(({
|
||||
'py-2',
|
||||
withBorderBottom && 'border-b border-divider-subtle',
|
||||
className,
|
||||
)}>
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
)
|
||||
|
||||
@ -33,7 +33,7 @@ export const FieldTitle = memo(({
|
||||
return (
|
||||
<div className={cn('mb-0.5', !!subTitle && 'mb-1')}>
|
||||
<div
|
||||
className='group/collapse flex items-center justify-between py-1'
|
||||
className="group/collapse flex items-center justify-between py-1"
|
||||
onClick={() => {
|
||||
if (!disabled) {
|
||||
setCollapsedLocal(!collapsedMerged)
|
||||
@ -41,7 +41,7 @@ export const FieldTitle = memo(({
|
||||
}
|
||||
}}
|
||||
>
|
||||
<div className='system-sm-semibold-uppercase flex items-center text-text-secondary'>
|
||||
<div className="system-sm-semibold-uppercase flex items-center text-text-secondary">
|
||||
{title}
|
||||
{
|
||||
showArrow && (
|
||||
@ -57,7 +57,7 @@ export const FieldTitle = memo(({
|
||||
tooltip && (
|
||||
<Tooltip
|
||||
popupContent={tooltip}
|
||||
triggerClassName='w-4 h-4 ml-1'
|
||||
triggerClassName="w-4 h-4 ml-1"
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
import type { ReactNode } from 'react'
|
||||
import type { FieldTitleProps } from '.'
|
||||
import {
|
||||
memo,
|
||||
useState,
|
||||
} from 'react'
|
||||
import type { FieldTitleProps } from '.'
|
||||
import { FieldTitle } from '.'
|
||||
|
||||
export type FieldProps = {
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
import type { ReactNode } from 'react'
|
||||
import { memo } from 'react'
|
||||
import type {
|
||||
FieldProps,
|
||||
GroupProps,
|
||||
} from '.'
|
||||
import { memo } from 'react'
|
||||
import {
|
||||
Field,
|
||||
Group,
|
||||
|
||||
@ -18,7 +18,8 @@ export const Group = memo(({
|
||||
'px-4 py-2',
|
||||
withBorderBottom && 'border-b border-divider-subtle',
|
||||
className,
|
||||
)}>
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
)
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
export * from './box'
|
||||
export * from './group'
|
||||
export * from './box-group'
|
||||
export * from './field-title'
|
||||
export * from './field'
|
||||
export * from './group-field'
|
||||
export * from './box-group-field'
|
||||
export * from './field'
|
||||
export * from './field-title'
|
||||
export * from './group'
|
||||
export * from './group-field'
|
||||
|
||||
@ -10,7 +10,7 @@ const ListNoDataPlaceholder: FC<Props> = ({
|
||||
children,
|
||||
}) => {
|
||||
return (
|
||||
<div className='system-xs-regular flex min-h-[42px] w-full items-center justify-center rounded-[10px] bg-background-section text-text-tertiary'>
|
||||
<div className="system-xs-regular flex min-h-[42px] w-full items-center justify-center rounded-[10px] bg-background-section text-text-tertiary">
|
||||
{children}
|
||||
</div>
|
||||
)
|
||||
|
||||
@ -1,21 +1,21 @@
|
||||
'use client'
|
||||
import Tooltip from '@/app/components/base/tooltip'
|
||||
import { RiAlertFill } from '@remixicon/react'
|
||||
import type { FC } from 'react'
|
||||
import { RiAlertFill } from '@remixicon/react'
|
||||
import React from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import Tooltip from '@/app/components/base/tooltip'
|
||||
|
||||
const McpToolNotSupportTooltip: FC = () => {
|
||||
const { t } = useTranslation()
|
||||
return (
|
||||
<Tooltip
|
||||
popupContent={
|
||||
<div className='w-[256px]'>
|
||||
popupContent={(
|
||||
<div className="w-[256px]">
|
||||
{t('plugin.detailPanel.toolSelector.unsupportedMCPTool')}
|
||||
</div>
|
||||
}
|
||||
)}
|
||||
>
|
||||
<RiAlertFill className='size-4 text-text-warning-secondary' />
|
||||
<RiAlertFill className="size-4 text-text-warning-secondary" />
|
||||
</Tooltip>
|
||||
)
|
||||
}
|
||||
|
||||
@ -1,15 +1,15 @@
|
||||
'use client'
|
||||
import type { FC } from 'react'
|
||||
import type { Memory } from '../../../types'
|
||||
import { produce } from 'immer'
|
||||
import React, { useCallback } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { produce } from 'immer'
|
||||
import type { Memory } from '../../../types'
|
||||
import { MemoryRole } from '../../../types'
|
||||
import { cn } from '@/utils/classnames'
|
||||
import Field from '@/app/components/workflow/nodes/_base/components/field'
|
||||
import Switch from '@/app/components/base/switch'
|
||||
import Slider from '@/app/components/base/slider'
|
||||
import Input from '@/app/components/base/input'
|
||||
import Slider from '@/app/components/base/slider'
|
||||
import Switch from '@/app/components/base/switch'
|
||||
import Field from '@/app/components/workflow/nodes/_base/components/field'
|
||||
import { cn } from '@/utils/classnames'
|
||||
import { MemoryRole } from '../../../types'
|
||||
|
||||
const i18nPrefix = 'workflow.nodes.common.memory'
|
||||
const WINDOW_SIZE_MIN = 1
|
||||
@ -31,14 +31,15 @@ const RoleItem: FC<RoleItemProps> = ({
|
||||
onChange(e.target.value)
|
||||
}, [onChange])
|
||||
return (
|
||||
<div className='flex items-center justify-between'>
|
||||
<div className='text-[13px] font-normal text-text-secondary'>{title}</div>
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="text-[13px] font-normal text-text-secondary">{title}</div>
|
||||
<Input
|
||||
readOnly={readonly}
|
||||
value={value}
|
||||
onChange={handleChange}
|
||||
className='h-8 w-[200px]'
|
||||
type='text' />
|
||||
className="h-8 w-[200px]"
|
||||
type="text"
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@ -132,31 +133,31 @@ const MemoryConfig: FC<Props> = ({
|
||||
<Field
|
||||
title={t(`${i18nPrefix}.memory`)}
|
||||
tooltip={t(`${i18nPrefix}.memoryTip`)!}
|
||||
operations={
|
||||
operations={(
|
||||
<Switch
|
||||
defaultValue={!!payload}
|
||||
onChange={handleMemoryEnabledChange}
|
||||
size='md'
|
||||
size="md"
|
||||
disabled={readonly}
|
||||
/>
|
||||
}
|
||||
)}
|
||||
>
|
||||
{payload && (
|
||||
<>
|
||||
{/* window size */}
|
||||
<div className='flex justify-between'>
|
||||
<div className='flex h-8 items-center space-x-2'>
|
||||
<div className="flex justify-between">
|
||||
<div className="flex h-8 items-center space-x-2">
|
||||
<Switch
|
||||
defaultValue={payload?.window?.enabled}
|
||||
onChange={handleWindowEnabledChange}
|
||||
size='md'
|
||||
size="md"
|
||||
disabled={readonly}
|
||||
/>
|
||||
<div className='system-xs-medium-uppercase text-text-tertiary'>{t(`${i18nPrefix}.windowSize`)}</div>
|
||||
<div className="system-xs-medium-uppercase text-text-tertiary">{t(`${i18nPrefix}.windowSize`)}</div>
|
||||
</div>
|
||||
<div className='flex h-8 items-center space-x-2'>
|
||||
<div className="flex h-8 items-center space-x-2">
|
||||
<Slider
|
||||
className='w-[144px]'
|
||||
className="w-[144px]"
|
||||
value={(payload.window?.size || WINDOW_SIZE_DEFAULT) as number}
|
||||
min={WINDOW_SIZE_MIN}
|
||||
max={WINDOW_SIZE_MAX}
|
||||
@ -166,9 +167,9 @@ const MemoryConfig: FC<Props> = ({
|
||||
/>
|
||||
<Input
|
||||
value={(payload.window?.size || WINDOW_SIZE_DEFAULT) as number}
|
||||
wrapperClassName='w-12'
|
||||
className='appearance-none pr-0'
|
||||
type='number'
|
||||
wrapperClassName="w-12"
|
||||
className="appearance-none pr-0"
|
||||
type="number"
|
||||
min={WINDOW_SIZE_MIN}
|
||||
max={WINDOW_SIZE_MAX}
|
||||
step={1}
|
||||
@ -179,9 +180,9 @@ const MemoryConfig: FC<Props> = ({
|
||||
</div>
|
||||
</div>
|
||||
{canSetRoleName && (
|
||||
<div className='mt-4'>
|
||||
<div className='text-xs font-medium uppercase leading-6 text-text-tertiary'>{t(`${i18nPrefix}.conversationRoleName`)}</div>
|
||||
<div className='mt-1 space-y-2'>
|
||||
<div className="mt-4">
|
||||
<div className="text-xs font-medium uppercase leading-6 text-text-tertiary">{t(`${i18nPrefix}.conversationRoleName`)}</div>
|
||||
<div className="mt-1 space-y-2">
|
||||
<RoleItem
|
||||
readonly={readonly}
|
||||
title={t(`${i18nPrefix}.user`)}
|
||||
|
||||
@ -1,15 +1,15 @@
|
||||
import type {
|
||||
Node,
|
||||
NodeOutPutVar,
|
||||
} from '@/app/components/workflow/types'
|
||||
import {
|
||||
memo,
|
||||
} from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import PromptEditor from '@/app/components/base/prompt-editor'
|
||||
import Placeholder from './placeholder'
|
||||
import type {
|
||||
Node,
|
||||
NodeOutPutVar,
|
||||
} from '@/app/components/workflow/types'
|
||||
import { BlockEnum } from '@/app/components/workflow/types'
|
||||
import { cn } from '@/utils/classnames'
|
||||
import Placeholder from './placeholder'
|
||||
|
||||
type MixedVariableTextInputProps = {
|
||||
readOnly?: boolean
|
||||
@ -33,7 +33,7 @@ const MixedVariableTextInput = ({
|
||||
'hover:border-components-input-border-hover hover:bg-components-input-bg-hover',
|
||||
'focus-within:border-components-input-border-active focus-within:bg-components-input-bg-active focus-within:shadow-xs',
|
||||
)}
|
||||
className='caret:text-text-accent'
|
||||
className="caret:text-text-accent"
|
||||
editable={!readOnly}
|
||||
value={value}
|
||||
workflowVariableBlock={{
|
||||
|
||||
@ -1,10 +1,9 @@
|
||||
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext'
|
||||
import { $insertNodes, FOCUS_COMMAND } from 'lexical'
|
||||
import { useCallback } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext'
|
||||
import { FOCUS_COMMAND } from 'lexical'
|
||||
import { $insertNodes } from 'lexical'
|
||||
import { CustomTextNode } from '@/app/components/base/prompt-editor/plugins/custom-text/node'
|
||||
import Badge from '@/app/components/base/badge'
|
||||
import { CustomTextNode } from '@/app/components/base/prompt-editor/plugins/custom-text/node'
|
||||
|
||||
const Placeholder = () => {
|
||||
const { t } = useTranslation()
|
||||
@ -20,17 +19,17 @@ const Placeholder = () => {
|
||||
|
||||
return (
|
||||
<div
|
||||
className='pointer-events-auto flex h-full w-full cursor-text items-center px-2'
|
||||
className="pointer-events-auto flex h-full w-full cursor-text items-center px-2"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation()
|
||||
handleInsert('')
|
||||
}}
|
||||
>
|
||||
<div className='flex grow items-center'>
|
||||
<div className="flex grow items-center">
|
||||
{t('workflow.nodes.tool.insertPlaceholder1')}
|
||||
<div className='system-kbd mx-0.5 flex h-4 w-4 items-center justify-center rounded bg-components-kbd-bg-gray text-text-placeholder'>/</div>
|
||||
<div className="system-kbd mx-0.5 flex h-4 w-4 items-center justify-center rounded bg-components-kbd-bg-gray text-text-placeholder">/</div>
|
||||
<div
|
||||
className='system-sm-regular cursor-pointer text-components-input-text-placeholder underline decoration-dotted decoration-auto underline-offset-auto hover:text-text-tertiary'
|
||||
className="system-sm-regular cursor-pointer text-components-input-text-placeholder underline decoration-dotted decoration-auto underline-offset-auto hover:text-text-tertiary"
|
||||
onMouseDown={((e) => {
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
@ -41,8 +40,8 @@ const Placeholder = () => {
|
||||
</div>
|
||||
</div>
|
||||
<Badge
|
||||
className='shrink-0'
|
||||
text='String'
|
||||
className="shrink-0"
|
||||
text="String"
|
||||
uppercase={false}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@ -1,3 +1,10 @@
|
||||
import type {
|
||||
CommonNodeType,
|
||||
OnSelectBlock,
|
||||
} from '@/app/components/workflow/types'
|
||||
import {
|
||||
RiAddLine,
|
||||
} from '@remixicon/react'
|
||||
import {
|
||||
memo,
|
||||
useCallback,
|
||||
@ -5,19 +12,12 @@ import {
|
||||
useState,
|
||||
} from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import {
|
||||
RiAddLine,
|
||||
} from '@remixicon/react'
|
||||
import BlockSelector from '@/app/components/workflow/block-selector'
|
||||
import {
|
||||
useAvailableBlocks,
|
||||
useNodesInteractions,
|
||||
useNodesReadOnly,
|
||||
} from '@/app/components/workflow/hooks'
|
||||
import BlockSelector from '@/app/components/workflow/block-selector'
|
||||
import type {
|
||||
CommonNodeType,
|
||||
OnSelectBlock,
|
||||
} from '@/app/components/workflow/types'
|
||||
|
||||
type AddProps = {
|
||||
nodeId: string
|
||||
@ -75,10 +75,10 @@ const Add = ({
|
||||
${nodesReadOnly && '!cursor-not-allowed'}
|
||||
`}
|
||||
>
|
||||
<div className='mr-1.5 flex h-5 w-5 items-center justify-center rounded-[5px] bg-background-default-dimmed'>
|
||||
<RiAddLine className='h-3 w-3' />
|
||||
<div className="mr-1.5 flex h-5 w-5 items-center justify-center rounded-[5px] bg-background-default-dimmed">
|
||||
<RiAddLine className="h-3 w-3" />
|
||||
</div>
|
||||
<div className='flex items-center uppercase'>
|
||||
<div className="flex items-center uppercase">
|
||||
{tip}
|
||||
</div>
|
||||
</div>
|
||||
@ -91,10 +91,10 @@ const Add = ({
|
||||
onOpenChange={handleOpenChange}
|
||||
disabled={nodesReadOnly}
|
||||
onSelect={handleSelect}
|
||||
placement='top'
|
||||
placement="top"
|
||||
offset={0}
|
||||
trigger={renderTrigger}
|
||||
popupClassName='!w-[328px]'
|
||||
popupClassName="!w-[328px]"
|
||||
availableBlocksTypes={availableNextBlocks}
|
||||
/>
|
||||
)
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
import Add from './add'
|
||||
import Item from './item'
|
||||
import type {
|
||||
CommonNodeType,
|
||||
Node,
|
||||
} from '@/app/components/workflow/types'
|
||||
import { cn } from '@/utils/classnames'
|
||||
import Add from './add'
|
||||
import Item from './item'
|
||||
|
||||
type ContainerProps = {
|
||||
nodeId: string
|
||||
@ -27,7 +27,8 @@ const Container = ({
|
||||
<div className={cn(
|
||||
'space-y-0.5 rounded-[10px] bg-background-section-burn p-0.5',
|
||||
isFailBranch && 'border-[0.5px] border-state-warning-hover-alt bg-state-warning-hover',
|
||||
)}>
|
||||
)}
|
||||
>
|
||||
{
|
||||
branchName && (
|
||||
<div
|
||||
@ -47,7 +48,7 @@ const Container = ({
|
||||
key={nextNode.id}
|
||||
nodeId={nextNode.id}
|
||||
data={nextNode.data}
|
||||
sourceHandle='source'
|
||||
sourceHandle="source"
|
||||
/>
|
||||
))
|
||||
}
|
||||
|
||||
@ -1,21 +1,21 @@
|
||||
import type {
|
||||
Node,
|
||||
} from '../../../../types'
|
||||
import { isEqual } from 'lodash-es'
|
||||
import { memo, useMemo } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { isEqual } from 'lodash-es'
|
||||
import {
|
||||
getConnectedEdges,
|
||||
getOutgoers,
|
||||
useStore,
|
||||
} from 'reactflow'
|
||||
import { useToolIcon } from '../../../../hooks'
|
||||
import BlockIcon from '../../../../block-icon'
|
||||
import type {
|
||||
Node,
|
||||
} from '../../../../types'
|
||||
import { BlockEnum } from '../../../../types'
|
||||
import Line from './line'
|
||||
import Container from './container'
|
||||
import { hasErrorHandleNode } from '@/app/components/workflow/utils'
|
||||
import { ErrorHandleTypeEnum } from '@/app/components/workflow/nodes/_base/components/error-handle/types'
|
||||
import { hasErrorHandleNode } from '@/app/components/workflow/utils'
|
||||
import BlockIcon from '../../../../block-icon'
|
||||
import { useToolIcon } from '../../../../hooks'
|
||||
import { BlockEnum } from '../../../../types'
|
||||
import Container from './container'
|
||||
import Line from './line'
|
||||
|
||||
type NextStepProps = {
|
||||
selectedNode: Node
|
||||
@ -89,8 +89,8 @@ const NextStep = ({
|
||||
}, [branches, connectedEdges, data.error_strategy, data.type, outgoers, t])
|
||||
|
||||
return (
|
||||
<div className='flex py-1'>
|
||||
<div className='relative flex h-9 w-9 shrink-0 items-center justify-center rounded-lg border-[0.5px] border-divider-regular bg-background-default shadow-xs'>
|
||||
<div className="flex py-1">
|
||||
<div className="relative flex h-9 w-9 shrink-0 items-center justify-center rounded-lg border-[0.5px] border-divider-regular bg-background-default shadow-xs">
|
||||
<BlockIcon
|
||||
type={selectedNode!.data.type}
|
||||
toolIcon={toolIcon}
|
||||
@ -99,7 +99,7 @@ const NextStep = ({
|
||||
<Line
|
||||
list={list.length ? list.map(item => item.nextNodes.length + 1) : [1]}
|
||||
/>
|
||||
<div className='grow space-y-2'>
|
||||
<div className="grow space-y-2">
|
||||
{
|
||||
list.map((item, index) => {
|
||||
return (
|
||||
|
||||
@ -1,21 +1,21 @@
|
||||
import type {
|
||||
CommonNodeType,
|
||||
} from '@/app/components/workflow/types'
|
||||
import {
|
||||
memo,
|
||||
useCallback,
|
||||
useState,
|
||||
} from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import Operator from './operator'
|
||||
import type {
|
||||
CommonNodeType,
|
||||
} from '@/app/components/workflow/types'
|
||||
import Button from '@/app/components/base/button'
|
||||
import BlockIcon from '@/app/components/workflow/block-icon'
|
||||
import {
|
||||
useNodesInteractions,
|
||||
useNodesReadOnly,
|
||||
useToolIcon,
|
||||
} from '@/app/components/workflow/hooks'
|
||||
import Button from '@/app/components/base/button'
|
||||
import { cn } from '@/utils/classnames'
|
||||
import Operator from './operator'
|
||||
|
||||
type ItemProps = {
|
||||
nodeId: string
|
||||
@ -39,15 +39,15 @@ const Item = ({
|
||||
|
||||
return (
|
||||
<div
|
||||
className='group relative flex h-9 cursor-pointer items-center rounded-lg border-[0.5px] border-divider-regular bg-background-default px-2 text-xs text-text-secondary shadow-xs last-of-type:mb-0 hover:bg-background-default-hover'
|
||||
className="group relative flex h-9 cursor-pointer items-center rounded-lg border-[0.5px] border-divider-regular bg-background-default px-2 text-xs text-text-secondary shadow-xs last-of-type:mb-0 hover:bg-background-default-hover"
|
||||
>
|
||||
<BlockIcon
|
||||
type={data.type}
|
||||
toolIcon={toolIcon}
|
||||
className='mr-1.5 shrink-0'
|
||||
className="mr-1.5 shrink-0"
|
||||
/>
|
||||
<div
|
||||
className='system-xs-medium grow truncate text-text-secondary'
|
||||
className="system-xs-medium grow truncate text-text-secondary"
|
||||
title={data.title}
|
||||
>
|
||||
{data.title}
|
||||
@ -56,8 +56,8 @@ const Item = ({
|
||||
!nodesReadOnly && (
|
||||
<>
|
||||
<Button
|
||||
className='mr-1 hidden shrink-0 group-hover:flex'
|
||||
size='small'
|
||||
className="mr-1 hidden shrink-0 group-hover:flex"
|
||||
size="small"
|
||||
onClick={() => handleNodeSelect(nodeId)}
|
||||
>
|
||||
{t('workflow.common.jumpToNode')}
|
||||
|
||||
@ -19,7 +19,7 @@ const Line = ({
|
||||
const svgHeight = processedList[processedListLength - 1] + (processedListLength - 1) * 8
|
||||
|
||||
return (
|
||||
<svg className='w-6 shrink-0' style={{ height: svgHeight }}>
|
||||
<svg className="w-6 shrink-0" style={{ height: svgHeight }}>
|
||||
{
|
||||
processedList.map((item, index) => {
|
||||
const prevItem = index > 0 ? processedList[index - 1] : 0
|
||||
@ -30,17 +30,17 @@ const Line = ({
|
||||
index === 0 && (
|
||||
<>
|
||||
<path
|
||||
d='M0,18 L24,18'
|
||||
d="M0,18 L24,18"
|
||||
strokeWidth={1}
|
||||
fill='none'
|
||||
className='stroke-divider-solid'
|
||||
fill="none"
|
||||
className="stroke-divider-solid"
|
||||
/>
|
||||
<rect
|
||||
x={0}
|
||||
y={16}
|
||||
width={1}
|
||||
height={4}
|
||||
className='fill-divider-solid-alt'
|
||||
className="fill-divider-solid-alt"
|
||||
/>
|
||||
</>
|
||||
)
|
||||
@ -50,8 +50,8 @@ const Line = ({
|
||||
<path
|
||||
d={`M0,18 Q12,18 12,28 L12,${space - 10 + 2} Q12,${space + 2} 24,${space + 2}`}
|
||||
strokeWidth={1}
|
||||
fill='none'
|
||||
className='stroke-divider-solid'
|
||||
fill="none"
|
||||
className="stroke-divider-solid"
|
||||
/>
|
||||
)
|
||||
}
|
||||
@ -60,7 +60,7 @@ const Line = ({
|
||||
y={space}
|
||||
width={1}
|
||||
height={4}
|
||||
className='fill-divider-solid-alt'
|
||||
className="fill-divider-solid-alt"
|
||||
/>
|
||||
</g>
|
||||
)
|
||||
|
||||
@ -1,24 +1,24 @@
|
||||
import type {
|
||||
CommonNodeType,
|
||||
OnSelectBlock,
|
||||
} from '@/app/components/workflow/types'
|
||||
import { RiMoreFill } from '@remixicon/react'
|
||||
import { intersection } from 'lodash-es'
|
||||
import {
|
||||
useCallback,
|
||||
} from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { RiMoreFill } from '@remixicon/react'
|
||||
import { intersection } from 'lodash-es'
|
||||
import Button from '@/app/components/base/button'
|
||||
import {
|
||||
PortalToFollowElem,
|
||||
PortalToFollowElemContent,
|
||||
PortalToFollowElemTrigger,
|
||||
} from '@/app/components/base/portal-to-follow-elem'
|
||||
import Button from '@/app/components/base/button'
|
||||
import BlockSelector from '@/app/components/workflow/block-selector'
|
||||
import {
|
||||
useAvailableBlocks,
|
||||
useNodesInteractions,
|
||||
} from '@/app/components/workflow/hooks'
|
||||
import type {
|
||||
CommonNodeType,
|
||||
OnSelectBlock,
|
||||
} from '@/app/components/workflow/types'
|
||||
|
||||
type ChangeItemProps = {
|
||||
data: CommonNodeType
|
||||
@ -44,7 +44,7 @@ const ChangeItem = ({
|
||||
|
||||
const renderTrigger = useCallback(() => {
|
||||
return (
|
||||
<div className='flex h-8 cursor-pointer items-center rounded-lg px-2 hover:bg-state-base-hover'>
|
||||
<div className="flex h-8 cursor-pointer items-center rounded-lg px-2 hover:bg-state-base-hover">
|
||||
{t('workflow.panel.change')}
|
||||
</div>
|
||||
)
|
||||
@ -53,13 +53,13 @@ const ChangeItem = ({
|
||||
return (
|
||||
<BlockSelector
|
||||
onSelect={handleSelect}
|
||||
placement='top-end'
|
||||
placement="top-end"
|
||||
offset={{
|
||||
mainAxis: 6,
|
||||
crossAxis: 8,
|
||||
}}
|
||||
trigger={renderTrigger}
|
||||
popupClassName='!w-[328px]'
|
||||
popupClassName="!w-[328px]"
|
||||
availableBlocksTypes={intersection(availablePrevBlocks, availableNextBlocks).filter(item => item !== data.type)}
|
||||
/>
|
||||
)
|
||||
@ -87,34 +87,34 @@ const Operator = ({
|
||||
|
||||
return (
|
||||
<PortalToFollowElem
|
||||
placement='bottom-end'
|
||||
placement="bottom-end"
|
||||
offset={{ mainAxis: 4, crossAxis: -4 }}
|
||||
open={open}
|
||||
onOpenChange={onOpenChange}
|
||||
>
|
||||
<PortalToFollowElemTrigger onClick={() => onOpenChange(!open)}>
|
||||
<Button className='h-6 w-6 p-0'>
|
||||
<RiMoreFill className='h-4 w-4' />
|
||||
<Button className="h-6 w-6 p-0">
|
||||
<RiMoreFill className="h-4 w-4" />
|
||||
</Button>
|
||||
</PortalToFollowElemTrigger>
|
||||
<PortalToFollowElemContent className='z-10'>
|
||||
<div className='system-md-regular min-w-[120px] rounded-xl border-[0.5px] border-components-panel-border bg-components-panel-bg-blur text-text-secondary shadow-lg'>
|
||||
<div className='p-1'>
|
||||
<PortalToFollowElemContent className="z-10">
|
||||
<div className="system-md-regular min-w-[120px] rounded-xl border-[0.5px] border-components-panel-border bg-components-panel-bg-blur text-text-secondary shadow-lg">
|
||||
<div className="p-1">
|
||||
<ChangeItem
|
||||
data={data}
|
||||
nodeId={nodeId}
|
||||
sourceHandle={sourceHandle}
|
||||
/>
|
||||
<div
|
||||
className='flex h-8 cursor-pointer items-center rounded-lg px-2 hover:bg-state-base-hover'
|
||||
className="flex h-8 cursor-pointer items-center rounded-lg px-2 hover:bg-state-base-hover"
|
||||
onClick={() => handleNodeDisconnect(nodeId)}
|
||||
>
|
||||
{t('workflow.common.disconnect')}
|
||||
</div>
|
||||
</div>
|
||||
<div className='p-1'>
|
||||
<div className="p-1">
|
||||
<div
|
||||
className='flex h-8 cursor-pointer items-center rounded-lg px-2 hover:bg-state-base-hover'
|
||||
className="flex h-8 cursor-pointer items-center rounded-lg px-2 hover:bg-state-base-hover"
|
||||
onClick={() => handleNodeDelete(nodeId)}
|
||||
>
|
||||
{t('common.operation.delete')}
|
||||
|
||||
@ -1,24 +1,25 @@
|
||||
import type { FC } from 'react'
|
||||
import type { Node } from '../../../types'
|
||||
import {
|
||||
RiPlayLargeLine,
|
||||
} from '@remixicon/react'
|
||||
import {
|
||||
memo,
|
||||
useCallback,
|
||||
useState,
|
||||
} from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import {
|
||||
RiPlayLargeLine,
|
||||
} from '@remixicon/react'
|
||||
import {
|
||||
useNodesInteractions,
|
||||
} from '../../../hooks'
|
||||
import { type Node, NodeRunningStatus } from '../../../types'
|
||||
import { canRunBySingle } from '../../../utils'
|
||||
import PanelOperator from './panel-operator'
|
||||
import {
|
||||
Stop,
|
||||
} from '@/app/components/base/icons/src/vender/line/mediaAndDevices'
|
||||
import Tooltip from '@/app/components/base/tooltip'
|
||||
import { useWorkflowStore } from '@/app/components/workflow/store'
|
||||
import {
|
||||
useNodesInteractions,
|
||||
} from '../../../hooks'
|
||||
import { NodeRunningStatus } from '../../../types'
|
||||
import { canRunBySingle } from '../../../utils'
|
||||
import PanelOperator from './panel-operator'
|
||||
|
||||
type NodeControlProps = Pick<Node, 'id' | 'data'>
|
||||
const NodeControl: FC<NodeControlProps> = ({
|
||||
@ -45,7 +46,7 @@ const NodeControl: FC<NodeControlProps> = ({
|
||||
`}
|
||||
>
|
||||
<div
|
||||
className='flex h-6 items-center rounded-lg border-[0.5px] border-components-actionbar-border bg-components-actionbar-bg px-0.5 text-text-tertiary shadow-md backdrop-blur-[5px]'
|
||||
className="flex h-6 items-center rounded-lg border-[0.5px] border-components-actionbar-border bg-components-actionbar-bg px-0.5 text-text-tertiary shadow-md backdrop-blur-[5px]"
|
||||
onClick={e => e.stopPropagation()}
|
||||
>
|
||||
{
|
||||
@ -66,15 +67,15 @@ const NodeControl: FC<NodeControlProps> = ({
|
||||
>
|
||||
{
|
||||
isSingleRunning
|
||||
? <Stop className='h-3 w-3' />
|
||||
? <Stop className="h-3 w-3" />
|
||||
: (
|
||||
<Tooltip
|
||||
popupContent={t('workflow.panel.runThisStep')}
|
||||
asChild={false}
|
||||
>
|
||||
<RiPlayLargeLine className='h-3 w-3' />
|
||||
</Tooltip>
|
||||
)
|
||||
<Tooltip
|
||||
popupContent={t('workflow.panel.runThisStep')}
|
||||
asChild={false}
|
||||
>
|
||||
<RiPlayLargeLine className="h-3 w-3" />
|
||||
</Tooltip>
|
||||
)
|
||||
}
|
||||
</div>
|
||||
)
|
||||
@ -84,7 +85,7 @@ const NodeControl: FC<NodeControlProps> = ({
|
||||
data={data}
|
||||
offset={0}
|
||||
onOpenChange={handleOpenChange}
|
||||
triggerClassName='!w-5 !h-5'
|
||||
triggerClassName="!w-5 !h-5"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -1,22 +1,19 @@
|
||||
import type { MouseEvent } from 'react'
|
||||
import type { PluginDefaultValue } from '../../../block-selector/types'
|
||||
import type { Node } from '../../../types'
|
||||
import {
|
||||
memo,
|
||||
useCallback,
|
||||
useEffect,
|
||||
useState,
|
||||
} from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import {
|
||||
Handle,
|
||||
Position,
|
||||
} from 'reactflow'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import {
|
||||
BlockEnum,
|
||||
NodeRunningStatus,
|
||||
} from '../../../types'
|
||||
import type { Node } from '../../../types'
|
||||
import { cn } from '@/utils/classnames'
|
||||
import BlockSelector from '../../../block-selector'
|
||||
import type { PluginDefaultValue } from '../../../block-selector/types'
|
||||
import {
|
||||
useAvailableBlocks,
|
||||
useIsChatMode,
|
||||
@ -27,7 +24,10 @@ import {
|
||||
useStore,
|
||||
useWorkflowStore,
|
||||
} from '../../../store'
|
||||
import { cn } from '@/utils/classnames'
|
||||
import {
|
||||
BlockEnum,
|
||||
NodeRunningStatus,
|
||||
} from '../../../types'
|
||||
|
||||
type NodeHandleProps = {
|
||||
handleId: string
|
||||
@ -75,7 +75,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',
|
||||
@ -101,7 +101,7 @@ export const NodeTargetHandle = memo(({
|
||||
onOpenChange={handleOpenChange}
|
||||
onSelect={handleSelect}
|
||||
asChild
|
||||
placement='left'
|
||||
placement="left"
|
||||
triggerClassName={open => `
|
||||
hidden absolute left-0 top-0 pointer-events-none
|
||||
${nodeSelectorClassName}
|
||||
@ -186,7 +186,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',
|
||||
@ -201,14 +201,14 @@ export const NodeSourceHandle = memo(({
|
||||
isConnectable={isConnectable}
|
||||
onClick={handleHandleClick}
|
||||
>
|
||||
<div className='absolute -top-1 left-1/2 hidden -translate-x-1/2 -translate-y-full rounded-lg border-[0.5px] border-components-panel-border bg-components-tooltip-bg p-1.5 shadow-lg group-hover/handle:block'>
|
||||
<div className='system-xs-regular text-text-tertiary'>
|
||||
<div className=' whitespace-nowrap'>
|
||||
<span className='system-xs-medium text-text-secondary'>{t('workflow.common.parallelTip.click.title')}</span>
|
||||
<div className="absolute -top-1 left-1/2 hidden -translate-x-1/2 -translate-y-full rounded-lg border-[0.5px] border-components-panel-border bg-components-tooltip-bg p-1.5 shadow-lg group-hover/handle:block">
|
||||
<div className="system-xs-regular text-text-tertiary">
|
||||
<div className=" whitespace-nowrap">
|
||||
<span className="system-xs-medium text-text-secondary">{t('workflow.common.parallelTip.click.title')}</span>
|
||||
{t('workflow.common.parallelTip.click.desc')}
|
||||
</div>
|
||||
<div>
|
||||
<span className='system-xs-medium text-text-secondary'>{t('workflow.common.parallelTip.drag.title')}</span>
|
||||
<span className="system-xs-medium text-text-secondary">{t('workflow.common.parallelTip.drag.title')}</span>
|
||||
{t('workflow.common.parallelTip.drag.desc')}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -1,12 +1,12 @@
|
||||
import type { OnResize } from 'reactflow'
|
||||
import type { CommonNodeType } from '../../../types'
|
||||
import {
|
||||
memo,
|
||||
useCallback,
|
||||
} from 'react'
|
||||
import type { OnResize } from 'reactflow'
|
||||
import { NodeResizeControl } from 'reactflow'
|
||||
import { useNodesInteractions } from '../../../hooks'
|
||||
import type { CommonNodeType } from '../../../types'
|
||||
import { cn } from '@/utils/classnames'
|
||||
import { useNodesInteractions } from '../../../hooks'
|
||||
|
||||
const Icon = () => {
|
||||
return (
|
||||
@ -42,16 +42,17 @@ const NodeResizer = ({
|
||||
<div className={cn(
|
||||
'hidden group-hover:block',
|
||||
nodeData.selected && '!block',
|
||||
)}>
|
||||
)}
|
||||
>
|
||||
<NodeResizeControl
|
||||
position='bottom-right'
|
||||
className='!border-none !bg-transparent'
|
||||
position="bottom-right"
|
||||
className="!border-none !bg-transparent"
|
||||
onResize={handleResize}
|
||||
minWidth={minWidth}
|
||||
minHeight={minHeight}
|
||||
maxWidth={maxWidth}
|
||||
>
|
||||
<div className='absolute bottom-[1px] right-[1px]'>{icon}</div>
|
||||
<div className="absolute bottom-[1px] right-[1px]">{icon}</div>
|
||||
</NodeResizeControl>
|
||||
</div>
|
||||
)
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
'use client'
|
||||
import type { FC } from 'react'
|
||||
import React, { useCallback } from 'react'
|
||||
import type { VariantProps } from 'class-variance-authority'
|
||||
import type { FC } from 'react'
|
||||
import { cva } from 'class-variance-authority'
|
||||
import { cn } from '@/utils/classnames'
|
||||
import React, { useCallback } from 'react'
|
||||
import Tooltip from '@/app/components/base/tooltip'
|
||||
import { cn } from '@/utils/classnames'
|
||||
|
||||
const variants = cva([], {
|
||||
variants: {
|
||||
@ -17,8 +17,7 @@ const variants = cva([], {
|
||||
defaultVariants: {
|
||||
align: 'center',
|
||||
},
|
||||
},
|
||||
)
|
||||
})
|
||||
|
||||
type Props = {
|
||||
className?: string
|
||||
@ -59,14 +58,15 @@ const OptionCard: FC<Props> = ({
|
||||
>
|
||||
<span>{title}</span>
|
||||
{tooltip
|
||||
&& <Tooltip
|
||||
popupContent={
|
||||
<div className='w-[240px]'>
|
||||
{tooltip}
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
}
|
||||
&& (
|
||||
<Tooltip
|
||||
popupContent={(
|
||||
<div className="w-[240px]">
|
||||
{tooltip}
|
||||
</div>
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@ -3,8 +3,8 @@ import type { FC, ReactNode } from 'react'
|
||||
import React from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { FieldCollapse } from '@/app/components/workflow/nodes/_base/components/collapse'
|
||||
import TreeIndentLine from './variable/object-child-tree-panel/tree-indent-line'
|
||||
import { cn } from '@/utils/classnames'
|
||||
import TreeIndentLine from './variable/object-child-tree-panel/tree-indent-line'
|
||||
|
||||
type Props = {
|
||||
className?: string
|
||||
@ -56,17 +56,17 @@ export const VarItem: FC<VarItemProps> = ({
|
||||
return (
|
||||
<div className={cn('flex', isIndent && 'relative left-[-7px]')}>
|
||||
{isIndent && <TreeIndentLine depth={1} />}
|
||||
<div className='py-1'>
|
||||
<div className='flex'>
|
||||
<div className='flex items-center leading-[18px]'>
|
||||
<div className='code-sm-semibold text-text-secondary'>{name}</div>
|
||||
<div className='system-xs-regular ml-2 text-text-tertiary'>{type}</div>
|
||||
<div className="py-1">
|
||||
<div className="flex">
|
||||
<div className="flex items-center leading-[18px]">
|
||||
<div className="code-sm-semibold text-text-secondary">{name}</div>
|
||||
<div className="system-xs-regular ml-2 text-text-tertiary">{type}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className='system-xs-regular mt-0.5 text-text-tertiary'>
|
||||
<div className="system-xs-regular mt-0.5 text-text-tertiary">
|
||||
{description}
|
||||
{subItems && (
|
||||
<div className='ml-2 border-l border-gray-200 pl-2'>
|
||||
<div className="ml-2 border-l border-gray-200 pl-2">
|
||||
{subItems.map((item, index) => (
|
||||
<VarItem
|
||||
key={index}
|
||||
|
||||
@ -1,10 +1,14 @@
|
||||
import type {
|
||||
Node,
|
||||
OnSelectBlock,
|
||||
} from '@/app/components/workflow/types'
|
||||
import { intersection } from 'lodash-es'
|
||||
import {
|
||||
memo,
|
||||
useCallback,
|
||||
useMemo,
|
||||
} from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { intersection } from 'lodash-es'
|
||||
import BlockSelector from '@/app/components/workflow/block-selector'
|
||||
import {
|
||||
useAvailableBlocks,
|
||||
@ -12,10 +16,6 @@ import {
|
||||
useNodesInteractions,
|
||||
} from '@/app/components/workflow/hooks'
|
||||
import { useHooksStore } from '@/app/components/workflow/hooks-store'
|
||||
import type {
|
||||
Node,
|
||||
OnSelectBlock,
|
||||
} from '@/app/components/workflow/types'
|
||||
import { BlockEnum, isTriggerNode } from '@/app/components/workflow/types'
|
||||
|
||||
import { FlowType } from '@/types/common'
|
||||
@ -60,7 +60,7 @@ const ChangeBlock = ({
|
||||
|
||||
const renderTrigger = useCallback(() => {
|
||||
return (
|
||||
<div className='flex h-8 w-[232px] cursor-pointer items-center rounded-lg px-3 text-sm text-text-secondary hover:bg-state-base-hover'>
|
||||
<div className="flex h-8 w-[232px] cursor-pointer items-center rounded-lg px-3 text-sm text-text-secondary hover:bg-state-base-hover">
|
||||
{t('workflow.panel.changeBlock')}
|
||||
</div>
|
||||
)
|
||||
@ -68,14 +68,14 @@ const ChangeBlock = ({
|
||||
|
||||
return (
|
||||
<BlockSelector
|
||||
placement='bottom-end'
|
||||
placement="bottom-end"
|
||||
offset={{
|
||||
mainAxis: -36,
|
||||
crossAxis: 4,
|
||||
}}
|
||||
onSelect={handleSelect}
|
||||
trigger={renderTrigger}
|
||||
popupClassName='min-w-[240px]'
|
||||
popupClassName="min-w-[240px]"
|
||||
availableBlocksTypes={availableNodes}
|
||||
showStartTab={showStartTab}
|
||||
ignoreNodeIds={ignoreNodeIds}
|
||||
|
||||
@ -1,17 +1,17 @@
|
||||
import type { OffsetOptions } from '@floating-ui/react'
|
||||
import type { Node } from '@/app/components/workflow/types'
|
||||
import { RiMoreFill } from '@remixicon/react'
|
||||
import {
|
||||
memo,
|
||||
useCallback,
|
||||
useState,
|
||||
} from 'react'
|
||||
import { RiMoreFill } from '@remixicon/react'
|
||||
import type { OffsetOptions } from '@floating-ui/react'
|
||||
import PanelOperatorPopup from './panel-operator-popup'
|
||||
import {
|
||||
PortalToFollowElem,
|
||||
PortalToFollowElemContent,
|
||||
PortalToFollowElemTrigger,
|
||||
} from '@/app/components/base/portal-to-follow-elem'
|
||||
import type { Node } from '@/app/components/workflow/types'
|
||||
import PanelOperatorPopup from './panel-operator-popup'
|
||||
|
||||
type PanelOperatorProps = {
|
||||
id: string
|
||||
@ -44,7 +44,7 @@ const PanelOperator = ({
|
||||
|
||||
return (
|
||||
<PortalToFollowElem
|
||||
placement='bottom-end'
|
||||
placement="bottom-end"
|
||||
offset={offset}
|
||||
open={open}
|
||||
onOpenChange={handleOpenChange}
|
||||
@ -58,10 +58,10 @@ const PanelOperator = ({
|
||||
${triggerClassName}
|
||||
`}
|
||||
>
|
||||
<RiMoreFill className={'h-4 w-4 text-text-tertiary'} />
|
||||
<RiMoreFill className="h-4 w-4 text-text-tertiary" />
|
||||
</div>
|
||||
</PortalToFollowElemTrigger>
|
||||
<PortalToFollowElemContent className='z-[11]'>
|
||||
<PortalToFollowElemContent className="z-[11]">
|
||||
<PanelOperatorPopup
|
||||
id={id}
|
||||
data={data}
|
||||
|
||||
@ -1,13 +1,11 @@
|
||||
import type { Node } from '@/app/components/workflow/types'
|
||||
import {
|
||||
memo,
|
||||
useMemo,
|
||||
} from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useEdges } from 'reactflow'
|
||||
import ChangeBlock from './change-block'
|
||||
import {
|
||||
canRunBySingle,
|
||||
} from '@/app/components/workflow/utils'
|
||||
import { CollectionType } from '@/app/components/tools/types'
|
||||
import {
|
||||
useNodeDataUpdate,
|
||||
useNodeMetaData,
|
||||
@ -16,11 +14,13 @@ import {
|
||||
useNodesSyncDraft,
|
||||
} from '@/app/components/workflow/hooks'
|
||||
import ShortcutsName from '@/app/components/workflow/shortcuts-name'
|
||||
import type { Node } from '@/app/components/workflow/types'
|
||||
import { BlockEnum } from '@/app/components/workflow/types'
|
||||
import { CollectionType } from '@/app/components/tools/types'
|
||||
import {
|
||||
canRunBySingle,
|
||||
} from '@/app/components/workflow/utils'
|
||||
import { useAllWorkflowTools } from '@/service/use-tools'
|
||||
import { canFindTool } from '@/utils'
|
||||
import ChangeBlock from './change-block'
|
||||
|
||||
type PanelOperatorPopupProps = {
|
||||
id: string
|
||||
@ -53,17 +53,18 @@ const PanelOperatorPopup = ({
|
||||
const { data: workflowTools } = useAllWorkflowTools()
|
||||
const isWorkflowTool = data.type === BlockEnum.Tool && data.provider_type === CollectionType.workflow
|
||||
const workflowAppId = useMemo(() => {
|
||||
if (!isWorkflowTool || !workflowTools || !data.provider_id) return undefined
|
||||
if (!isWorkflowTool || !workflowTools || !data.provider_id)
|
||||
return undefined
|
||||
const workflowTool = workflowTools.find(item => canFindTool(item.id, data.provider_id))
|
||||
return workflowTool?.workflow_app_id
|
||||
}, [isWorkflowTool, workflowTools, data.provider_id])
|
||||
|
||||
return (
|
||||
<div className='w-[240px] rounded-lg border-[0.5px] border-components-panel-border bg-components-panel-bg shadow-xl'>
|
||||
<div className="w-[240px] rounded-lg border-[0.5px] border-components-panel-border bg-components-panel-bg shadow-xl">
|
||||
{
|
||||
(showChangeBlock || canRunBySingle(data.type, isChildNode)) && (
|
||||
<>
|
||||
<div className='p-1'>
|
||||
<div className="p-1">
|
||||
{
|
||||
canRunBySingle(data.type, isChildNode) && (
|
||||
<div
|
||||
@ -92,7 +93,7 @@ const PanelOperatorPopup = ({
|
||||
)
|
||||
}
|
||||
</div>
|
||||
<div className='h-px bg-divider-regular'></div>
|
||||
<div className="h-px bg-divider-regular"></div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
@ -102,9 +103,9 @@ const PanelOperatorPopup = ({
|
||||
{
|
||||
!nodeMetaData.isSingleton && (
|
||||
<>
|
||||
<div className='p-1'>
|
||||
<div className="p-1">
|
||||
<div
|
||||
className='flex h-8 cursor-pointer items-center justify-between rounded-lg px-3 text-sm text-text-secondary hover:bg-state-base-hover'
|
||||
className="flex h-8 cursor-pointer items-center justify-between rounded-lg px-3 text-sm text-text-secondary hover:bg-state-base-hover"
|
||||
onClick={() => {
|
||||
onClosePopup()
|
||||
handleNodesCopy(id)
|
||||
@ -114,7 +115,7 @@ const PanelOperatorPopup = ({
|
||||
<ShortcutsName keys={['ctrl', 'c']} />
|
||||
</div>
|
||||
<div
|
||||
className='flex h-8 cursor-pointer items-center justify-between rounded-lg px-3 text-sm text-text-secondary hover:bg-state-base-hover'
|
||||
className="flex h-8 cursor-pointer items-center justify-between rounded-lg px-3 text-sm text-text-secondary hover:bg-state-base-hover"
|
||||
onClick={() => {
|
||||
onClosePopup()
|
||||
handleNodesDuplicate(id)
|
||||
@ -124,14 +125,14 @@ const PanelOperatorPopup = ({
|
||||
<ShortcutsName keys={['ctrl', 'd']} />
|
||||
</div>
|
||||
</div>
|
||||
<div className='h-px bg-divider-regular'></div>
|
||||
<div className="h-px bg-divider-regular"></div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
{
|
||||
!nodeMetaData.isUndeletable && (
|
||||
<>
|
||||
<div className='p-1'>
|
||||
<div className="p-1">
|
||||
<div
|
||||
className={`
|
||||
flex h-8 cursor-pointer items-center justify-between rounded-lg px-3 text-sm text-text-secondary
|
||||
@ -143,7 +144,7 @@ const PanelOperatorPopup = ({
|
||||
<ShortcutsName keys={['del']} />
|
||||
</div>
|
||||
</div>
|
||||
<div className='h-px bg-divider-regular'></div>
|
||||
<div className="h-px bg-divider-regular"></div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
@ -153,43 +154,45 @@ const PanelOperatorPopup = ({
|
||||
{
|
||||
isWorkflowTool && workflowAppId && (
|
||||
<>
|
||||
<div className='p-1'>
|
||||
<div className="p-1">
|
||||
<a
|
||||
href={`/app/${workflowAppId}/workflow`}
|
||||
target='_blank'
|
||||
className='flex h-8 cursor-pointer items-center rounded-lg px-3 text-sm text-text-secondary hover:bg-state-base-hover'
|
||||
target="_blank"
|
||||
className="flex h-8 cursor-pointer items-center rounded-lg px-3 text-sm text-text-secondary hover:bg-state-base-hover"
|
||||
>
|
||||
{t('workflow.panel.openWorkflow')}
|
||||
</a>
|
||||
</div>
|
||||
<div className='h-px bg-divider-regular'></div>
|
||||
<div className="h-px bg-divider-regular"></div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
{
|
||||
showHelpLink && nodeMetaData.helpLinkUri && (
|
||||
<>
|
||||
<div className='p-1'>
|
||||
<div className="p-1">
|
||||
<a
|
||||
href={nodeMetaData.helpLinkUri}
|
||||
target='_blank'
|
||||
className='flex h-8 cursor-pointer items-center rounded-lg px-3 text-sm text-text-secondary hover:bg-state-base-hover'
|
||||
target="_blank"
|
||||
className="flex h-8 cursor-pointer items-center rounded-lg px-3 text-sm text-text-secondary hover:bg-state-base-hover"
|
||||
>
|
||||
{t('workflow.panel.helpLink')}
|
||||
</a>
|
||||
</div>
|
||||
<div className='h-px bg-divider-regular'></div>
|
||||
<div className="h-px bg-divider-regular"></div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
<div className='p-1'>
|
||||
<div className='px-3 py-2 text-xs text-text-tertiary'>
|
||||
<div className='mb-1 flex h-[22px] items-center font-medium'>
|
||||
<div className="p-1">
|
||||
<div className="px-3 py-2 text-xs text-text-tertiary">
|
||||
<div className="mb-1 flex h-[22px] items-center font-medium">
|
||||
{t('workflow.panel.about').toLocaleUpperCase()}
|
||||
</div>
|
||||
<div className='mb-1 leading-[18px] text-text-secondary'>{nodeMetaData.description}</div>
|
||||
<div className='leading-[18px]'>
|
||||
{t('workflow.panel.createdBy')} {nodeMetaData.author}
|
||||
<div className="mb-1 leading-[18px] text-text-secondary">{nodeMetaData.description}</div>
|
||||
<div className="leading-[18px]">
|
||||
{t('workflow.panel.createdBy')}
|
||||
{' '}
|
||||
{nodeMetaData.author}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -1,41 +1,41 @@
|
||||
'use client'
|
||||
import type { FC, ReactNode } from 'react'
|
||||
import React, { useCallback, useRef } from 'react'
|
||||
import {
|
||||
RiDeleteBinLine,
|
||||
} from '@remixicon/react'
|
||||
import copy from 'copy-to-clipboard'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useBoolean } from 'ahooks'
|
||||
import { BlockEnum, EditionType } from '../../../../types'
|
||||
import type {
|
||||
ModelConfig,
|
||||
Node,
|
||||
NodeOutPutVar,
|
||||
Variable,
|
||||
} from '../../../../types'
|
||||
import {
|
||||
RiDeleteBinLine,
|
||||
} from '@remixicon/react'
|
||||
import { useBoolean } from 'ahooks'
|
||||
import copy from 'copy-to-clipboard'
|
||||
import React, { useCallback, useRef } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import ActionButton from '@/app/components/base/action-button'
|
||||
|
||||
import Wrap from '../editor/wrap'
|
||||
import { CodeLanguage } from '../../../code/types'
|
||||
import PromptGeneratorBtn from '../../../llm/components/prompt-generator-btn'
|
||||
import { cn } from '@/utils/classnames'
|
||||
import ToggleExpandBtn from '@/app/components/workflow/nodes/_base/components/toggle-expand-btn'
|
||||
import useToggleExpend from '@/app/components/workflow/nodes/_base/hooks/use-toggle-expend'
|
||||
import PromptEditor from '@/app/components/base/prompt-editor'
|
||||
import {
|
||||
Copy,
|
||||
CopyCheck,
|
||||
} from '@/app/components/base/icons/src/vender/line/files'
|
||||
import { useEventEmitterContextContext } from '@/context/event-emitter'
|
||||
import { PROMPT_EDITOR_INSERT_QUICKLY } from '@/app/components/base/prompt-editor/plugins/update-block'
|
||||
import { Variable02 } from '@/app/components/base/icons/src/vender/solid/development'
|
||||
import ActionButton from '@/app/components/base/action-button'
|
||||
import Tooltip from '@/app/components/base/tooltip'
|
||||
import CodeEditor from '@/app/components/workflow/nodes/_base/components/editor/code-editor/editor-support-vars'
|
||||
import Switch from '@/app/components/base/switch'
|
||||
import { Jinja } from '@/app/components/base/icons/src/vender/workflow'
|
||||
import { useStore } from '@/app/components/workflow/store'
|
||||
import PromptEditor from '@/app/components/base/prompt-editor'
|
||||
import { PROMPT_EDITOR_INSERT_QUICKLY } from '@/app/components/base/prompt-editor/plugins/update-block'
|
||||
import Switch from '@/app/components/base/switch'
|
||||
import Tooltip from '@/app/components/base/tooltip'
|
||||
import { useWorkflowVariableType } from '@/app/components/workflow/hooks'
|
||||
import CodeEditor from '@/app/components/workflow/nodes/_base/components/editor/code-editor/editor-support-vars'
|
||||
import ToggleExpandBtn from '@/app/components/workflow/nodes/_base/components/toggle-expand-btn'
|
||||
import useToggleExpend from '@/app/components/workflow/nodes/_base/hooks/use-toggle-expend'
|
||||
import { useStore } from '@/app/components/workflow/store'
|
||||
import { useEventEmitterContextContext } from '@/context/event-emitter'
|
||||
import { cn } from '@/utils/classnames'
|
||||
import { BlockEnum, EditionType } from '../../../../types'
|
||||
import { CodeLanguage } from '../../../code/types'
|
||||
import PromptGeneratorBtn from '../../../llm/components/prompt-generator-btn'
|
||||
import Wrap from '../editor/wrap'
|
||||
|
||||
type Props = {
|
||||
className?: string
|
||||
@ -158,39 +158,43 @@ const Editor: FC<Props> = ({
|
||||
<div ref={ref} className={cn(isFocus ? (gradientBorder && 'bg-gradient-to-r from-components-input-border-active-prompt-1 to-components-input-border-active-prompt-2') : 'bg-transparent', isExpand && 'h-full', '!rounded-[9px] p-0.5', containerClassName)}>
|
||||
<div className={cn(isFocus ? 'bg-background-default' : 'bg-components-input-bg-normal', isExpand && 'flex h-full flex-col', 'rounded-lg', containerClassName)}>
|
||||
<div className={cn('flex items-center justify-between pl-3 pr-2 pt-1', headerClassName)}>
|
||||
<div className='flex gap-2'>
|
||||
<div className={cn('text-xs font-semibold uppercase leading-4 text-text-secondary', titleClassName)}>{title} {required && <span className='text-text-destructive'>*</span>}</div>
|
||||
<div className="flex gap-2">
|
||||
<div className={cn('text-xs font-semibold uppercase leading-4 text-text-secondary', titleClassName)}>
|
||||
{title}
|
||||
{' '}
|
||||
{required && <span className="text-text-destructive">*</span>}
|
||||
</div>
|
||||
{titleTooltip && <Tooltip popupContent={titleTooltip} />}
|
||||
</div>
|
||||
<div className='flex items-center'>
|
||||
<div className='text-xs font-medium leading-[18px] text-text-tertiary'>{value?.length || 0}</div>
|
||||
<div className="flex items-center">
|
||||
<div className="text-xs font-medium leading-[18px] text-text-tertiary">{value?.length || 0}</div>
|
||||
{isSupportPromptGenerator && (
|
||||
<PromptGeneratorBtn
|
||||
nodeId={nodeId!}
|
||||
editorId={editorId}
|
||||
className='ml-[5px]'
|
||||
className="ml-[5px]"
|
||||
onGenerated={onGenerated}
|
||||
modelConfig={modelConfig}
|
||||
currentPrompt={value}
|
||||
/>
|
||||
)}
|
||||
|
||||
<div className='ml-2 mr-2 h-3 w-px bg-divider-regular'></div>
|
||||
<div className="ml-2 mr-2 h-3 w-px bg-divider-regular"></div>
|
||||
{/* Operations */}
|
||||
<div className='flex items-center space-x-[2px]'>
|
||||
<div className="flex items-center space-x-[2px]">
|
||||
{isSupportJinja && (
|
||||
<Tooltip
|
||||
popupContent={
|
||||
popupContent={(
|
||||
<div>
|
||||
<div>{t('workflow.common.enableJinja')}</div>
|
||||
<a className='text-text-accent' target='_blank' href='https://jinja.palletsprojects.com/en/2.10.x/'>{t('workflow.common.learnMore')}</a>
|
||||
<a className="text-text-accent" target="_blank" href="https://jinja.palletsprojects.com/en/2.10.x/">{t('workflow.common.learnMore')}</a>
|
||||
</div>
|
||||
}
|
||||
)}
|
||||
>
|
||||
<div className={cn(editionType === EditionType.jinja2 && 'border-components-button-ghost-bg-hover bg-components-button-ghost-bg-hover', 'flex h-[22px] items-center space-x-0.5 rounded-[5px] border border-transparent px-1.5 hover:border-components-button-ghost-bg-hover')}>
|
||||
<Jinja className='h-3 w-6 text-text-quaternary' />
|
||||
<Jinja className="h-3 w-6 text-text-quaternary" />
|
||||
<Switch
|
||||
size='sm'
|
||||
size="sm"
|
||||
defaultValue={editionType === EditionType.jinja2}
|
||||
onChange={(checked) => {
|
||||
onEditionTypeChange?.(checked ? EditionType.jinja2 : EditionType.basic)
|
||||
@ -205,27 +209,26 @@ const Editor: FC<Props> = ({
|
||||
popupContent={`${t('workflow.common.insertVarTip')}`}
|
||||
>
|
||||
<ActionButton onClick={handleInsertVariable}>
|
||||
<Variable02 className='h-4 w-4' />
|
||||
<Variable02 className="h-4 w-4" />
|
||||
</ActionButton>
|
||||
</Tooltip>
|
||||
)}
|
||||
{showRemove && (
|
||||
<ActionButton onClick={onRemove}>
|
||||
<RiDeleteBinLine className='h-4 w-4' />
|
||||
<RiDeleteBinLine className="h-4 w-4" />
|
||||
</ActionButton>
|
||||
)}
|
||||
{!isCopied
|
||||
? (
|
||||
<ActionButton onClick={handleCopy}>
|
||||
<Copy className='h-4 w-4' />
|
||||
</ActionButton>
|
||||
)
|
||||
<ActionButton onClick={handleCopy}>
|
||||
<Copy className="h-4 w-4" />
|
||||
</ActionButton>
|
||||
)
|
||||
: (
|
||||
<ActionButton>
|
||||
<CopyCheck className='h-4 w-4' />
|
||||
</ActionButton>
|
||||
)
|
||||
}
|
||||
<ActionButton>
|
||||
<CopyCheck className="h-4 w-4" />
|
||||
</ActionButton>
|
||||
)}
|
||||
<ToggleExpandBtn isExpand={isExpand} onExpandChange={setIsExpand} />
|
||||
</div>
|
||||
|
||||
@ -236,83 +239,83 @@ const Editor: FC<Props> = ({
|
||||
<div className={cn('pb-2', isExpand && 'flex grow flex-col')}>
|
||||
{!(isSupportJinja && editionType === EditionType.jinja2)
|
||||
? (
|
||||
<div className={cn(isExpand ? 'grow' : 'max-h-[536px]', 'relative min-h-[56px] overflow-y-auto px-3', editorContainerClassName)}>
|
||||
<PromptEditor
|
||||
key={controlPromptEditorRerenderKey}
|
||||
placeholder={placeholder}
|
||||
placeholderClassName={placeholderClassName}
|
||||
instanceId={instanceId}
|
||||
compact
|
||||
className={cn('min-h-[56px]', inputClassName)}
|
||||
style={isExpand ? { height: editorExpandHeight - 5 } : {}}
|
||||
value={value}
|
||||
contextBlock={{
|
||||
show: justVar ? false : isShowContext,
|
||||
selectable: !hasSetBlockStatus?.context,
|
||||
canNotAddContext: true,
|
||||
}}
|
||||
historyBlock={{
|
||||
show: justVar ? false : isShowHistory,
|
||||
selectable: !hasSetBlockStatus?.history,
|
||||
history: {
|
||||
user: 'Human',
|
||||
assistant: 'Assistant',
|
||||
},
|
||||
}}
|
||||
queryBlock={{
|
||||
show: false, // use [sys.query] instead of query block
|
||||
selectable: false,
|
||||
}}
|
||||
workflowVariableBlock={{
|
||||
show: true,
|
||||
variables: nodesOutputVars || [],
|
||||
getVarType: getVarType as any,
|
||||
workflowNodesMap: availableNodes.reduce((acc, node) => {
|
||||
acc[node.id] = {
|
||||
title: node.data.title,
|
||||
type: node.data.type,
|
||||
width: node.width,
|
||||
height: node.height,
|
||||
position: node.position,
|
||||
}
|
||||
if (node.data.type === BlockEnum.Start) {
|
||||
acc.sys = {
|
||||
title: t('workflow.blocks.start'),
|
||||
type: BlockEnum.Start,
|
||||
<div className={cn(isExpand ? 'grow' : 'max-h-[536px]', 'relative min-h-[56px] overflow-y-auto px-3', editorContainerClassName)}>
|
||||
<PromptEditor
|
||||
key={controlPromptEditorRerenderKey}
|
||||
placeholder={placeholder}
|
||||
placeholderClassName={placeholderClassName}
|
||||
instanceId={instanceId}
|
||||
compact
|
||||
className={cn('min-h-[56px]', inputClassName)}
|
||||
style={isExpand ? { height: editorExpandHeight - 5 } : {}}
|
||||
value={value}
|
||||
contextBlock={{
|
||||
show: justVar ? false : isShowContext,
|
||||
selectable: !hasSetBlockStatus?.context,
|
||||
canNotAddContext: true,
|
||||
}}
|
||||
historyBlock={{
|
||||
show: justVar ? false : isShowHistory,
|
||||
selectable: !hasSetBlockStatus?.history,
|
||||
history: {
|
||||
user: 'Human',
|
||||
assistant: 'Assistant',
|
||||
},
|
||||
}}
|
||||
queryBlock={{
|
||||
show: false, // use [sys.query] instead of query block
|
||||
selectable: false,
|
||||
}}
|
||||
workflowVariableBlock={{
|
||||
show: true,
|
||||
variables: nodesOutputVars || [],
|
||||
getVarType: getVarType as any,
|
||||
workflowNodesMap: availableNodes.reduce((acc, node) => {
|
||||
acc[node.id] = {
|
||||
title: node.data.title,
|
||||
type: node.data.type,
|
||||
width: node.width,
|
||||
height: node.height,
|
||||
position: node.position,
|
||||
}
|
||||
}
|
||||
return acc
|
||||
}, {} as any),
|
||||
showManageInputField: !!pipelineId,
|
||||
onManageInputField: () => setShowInputFieldPanel?.(true),
|
||||
}}
|
||||
onChange={onChange}
|
||||
onBlur={setBlur}
|
||||
onFocus={setFocus}
|
||||
editable={!readOnly}
|
||||
isSupportFileVar={isSupportFileVar}
|
||||
/>
|
||||
{/* to patch Editor not support dynamic change editable status */}
|
||||
{readOnly && <div className='absolute inset-0 z-10'></div>}
|
||||
</div>
|
||||
)
|
||||
if (node.data.type === BlockEnum.Start) {
|
||||
acc.sys = {
|
||||
title: t('workflow.blocks.start'),
|
||||
type: BlockEnum.Start,
|
||||
}
|
||||
}
|
||||
return acc
|
||||
}, {} as any),
|
||||
showManageInputField: !!pipelineId,
|
||||
onManageInputField: () => setShowInputFieldPanel?.(true),
|
||||
}}
|
||||
onChange={onChange}
|
||||
onBlur={setBlur}
|
||||
onFocus={setFocus}
|
||||
editable={!readOnly}
|
||||
isSupportFileVar={isSupportFileVar}
|
||||
/>
|
||||
{/* to patch Editor not support dynamic change editable status */}
|
||||
{readOnly && <div className="absolute inset-0 z-10"></div>}
|
||||
</div>
|
||||
)
|
||||
: (
|
||||
<div className={cn(isExpand ? 'grow' : 'max-h-[536px]', 'relative min-h-[56px] overflow-y-auto px-3', editorContainerClassName)}>
|
||||
<CodeEditor
|
||||
availableVars={nodesOutputVars || []}
|
||||
varList={varList}
|
||||
onAddVar={handleAddVariable}
|
||||
isInNode
|
||||
readOnly={readOnly}
|
||||
language={CodeLanguage.python3}
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
noWrapper
|
||||
isExpand={isExpand}
|
||||
className={inputClassName}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<div className={cn(isExpand ? 'grow' : 'max-h-[536px]', 'relative min-h-[56px] overflow-y-auto px-3', editorContainerClassName)}>
|
||||
<CodeEditor
|
||||
availableVars={nodesOutputVars || []}
|
||||
varList={varList}
|
||||
onAddVar={handleAddVariable}
|
||||
isInNode
|
||||
readOnly={readOnly}
|
||||
language={CodeLanguage.python3}
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
noWrapper
|
||||
isExpand={isExpand}
|
||||
className={inputClassName}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -1,13 +1,14 @@
|
||||
'use client'
|
||||
import type { FC } from 'react'
|
||||
import React from 'react'
|
||||
import {
|
||||
VariableLabelInText,
|
||||
} from '@/app/components/workflow/nodes/_base/components/variable/variable-label'
|
||||
import { cn } from '@/utils/classnames'
|
||||
import { useWorkflow } from '../../../hooks'
|
||||
import { BlockEnum } from '../../../types'
|
||||
import { getNodeInfoById, isSystemVar } from './variable/utils'
|
||||
import {
|
||||
VariableLabelInText,
|
||||
} from '@/app/components/workflow/nodes/_base/components/variable/variable-label'
|
||||
|
||||
type Props = {
|
||||
nodeId: string
|
||||
value: string
|
||||
@ -29,29 +30,31 @@ const ReadonlyInputWithSelectVar: FC<Props> = ({
|
||||
|
||||
const res = (() => {
|
||||
const vars: string[] = []
|
||||
const strWithVarPlaceholder = value.replaceAll(/{{#([^#]*)#}}/g, (_match, p1) => {
|
||||
const strWithVarPlaceholder = value.replaceAll(/\{\{#([^#]*)#\}\}/g, (_match, p1) => {
|
||||
vars.push(p1)
|
||||
return VAR_PLACEHOLDER
|
||||
})
|
||||
|
||||
const html: React.JSX.Element[] = strWithVarPlaceholder.split(VAR_PLACEHOLDER).map((str, index) => {
|
||||
if (!vars[index])
|
||||
return <span className='relative top-[-3px] leading-[16px]' key={index}>{str}</span>
|
||||
return <span className="relative top-[-3px] leading-[16px]" key={index}>{str}</span>
|
||||
|
||||
const value = vars[index].split('.')
|
||||
const isSystem = isSystemVar(value)
|
||||
const node = (isSystem ? startNode : getNodeInfoById(availableNodes, value[0]))?.data
|
||||
const isShowAPart = value.length > 2
|
||||
|
||||
return (<span key={index}>
|
||||
<span className='relative top-[-3px] leading-[16px]'>{str}</span>
|
||||
<VariableLabelInText
|
||||
nodeTitle={node?.title}
|
||||
nodeType={node?.type}
|
||||
notShowFullPath={isShowAPart}
|
||||
variables={value}
|
||||
/>
|
||||
</span>)
|
||||
return (
|
||||
<span key={index}>
|
||||
<span className="relative top-[-3px] leading-[16px]">{str}</span>
|
||||
<VariableLabelInText
|
||||
nodeTitle={node?.title}
|
||||
nodeType={node?.type}
|
||||
notShowFullPath={isShowAPart}
|
||||
variables={value}
|
||||
/>
|
||||
</span>
|
||||
)
|
||||
})
|
||||
return html
|
||||
})()
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
'use client'
|
||||
import type { FC } from 'react'
|
||||
import React from 'react'
|
||||
import { RiDeleteBinLine } from '@remixicon/react'
|
||||
import React from 'react'
|
||||
import ActionButton from '@/app/components/base/action-button'
|
||||
|
||||
type Props = {
|
||||
@ -13,8 +13,8 @@ const Remove: FC<Props> = ({
|
||||
onClick,
|
||||
}) => {
|
||||
return (
|
||||
<ActionButton size='l' className='group shrink-0 hover:!bg-state-destructive-hover' onClick={onClick}>
|
||||
<RiDeleteBinLine className='h-4 w-4 text-text-tertiary group-hover:text-text-destructive' />
|
||||
<ActionButton size="l" className="group shrink-0 hover:!bg-state-destructive-hover" onClick={onClick}>
|
||||
<RiDeleteBinLine className="h-4 w-4 text-text-tertiary group-hover:text-text-destructive" />
|
||||
</ActionButton>
|
||||
)
|
||||
}
|
||||
|
||||
@ -1,12 +1,12 @@
|
||||
import type { WorkflowRetryConfig } from './types'
|
||||
import type { NodeTracing } from '@/types/workflow'
|
||||
import {
|
||||
useCallback,
|
||||
useState,
|
||||
} from 'react'
|
||||
import type { WorkflowRetryConfig } from './types'
|
||||
import {
|
||||
useNodeDataUpdate,
|
||||
} from '@/app/components/workflow/hooks'
|
||||
import type { NodeTracing } from '@/types/workflow'
|
||||
|
||||
export const useRetryConfig = (
|
||||
id: string,
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
import { useMemo } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import type { Node } from '@/app/components/workflow/types'
|
||||
import {
|
||||
RiAlertFill,
|
||||
RiCheckboxCircleFill,
|
||||
RiLoader2Line,
|
||||
} from '@remixicon/react'
|
||||
import type { Node } from '@/app/components/workflow/types'
|
||||
import { useMemo } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { NodeRunningStatus } from '@/app/components/workflow/types'
|
||||
import { cn } from '@/utils/classnames'
|
||||
|
||||
@ -38,14 +38,15 @@ const RetryOnNode = ({
|
||||
return null
|
||||
|
||||
return (
|
||||
<div className='mb-1 px-3'>
|
||||
<div className="mb-1 px-3">
|
||||
<div className={cn(
|
||||
'system-xs-medium-uppercase flex items-center justify-between rounded-md border-[0.5px] border-transparent bg-workflow-block-parma-bg px-[5px] py-1 text-text-tertiary',
|
||||
isRunning && 'border-state-accent-active bg-state-accent-hover text-text-accent',
|
||||
isSuccessful && 'border-state-success-active bg-state-success-hover text-text-success',
|
||||
(isException || isFailed) && 'border-state-warning-active bg-state-warning-hover text-text-warning',
|
||||
)}>
|
||||
<div className='flex items-center'>
|
||||
)}
|
||||
>
|
||||
<div className="flex items-center">
|
||||
{
|
||||
showDefault && (
|
||||
t('workflow.nodes.common.retry.retryTimes', { times: retry_config.max_retries })
|
||||
@ -54,7 +55,7 @@ const RetryOnNode = ({
|
||||
{
|
||||
isRunning && (
|
||||
<>
|
||||
<RiLoader2Line className='mr-1 h-3.5 w-3.5 animate-spin' />
|
||||
<RiLoader2Line className="mr-1 h-3.5 w-3.5 animate-spin" />
|
||||
{t('workflow.nodes.common.retry.retrying')}
|
||||
</>
|
||||
)
|
||||
@ -62,7 +63,7 @@ const RetryOnNode = ({
|
||||
{
|
||||
isSuccessful && (
|
||||
<>
|
||||
<RiCheckboxCircleFill className='mr-1 h-3.5 w-3.5' />
|
||||
<RiCheckboxCircleFill className="mr-1 h-3.5 w-3.5" />
|
||||
{t('workflow.nodes.common.retry.retrySuccessful')}
|
||||
</>
|
||||
)
|
||||
@ -70,7 +71,7 @@ const RetryOnNode = ({
|
||||
{
|
||||
(isFailed || isException) && (
|
||||
<>
|
||||
<RiAlertFill className='mr-1 h-3.5 w-3.5' />
|
||||
<RiAlertFill className="mr-1 h-3.5 w-3.5" />
|
||||
{t('workflow.nodes.common.retry.retryFailed')}
|
||||
</>
|
||||
)
|
||||
@ -79,7 +80,9 @@ const RetryOnNode = ({
|
||||
{
|
||||
!showDefault && !!data._retryIndex && (
|
||||
<div>
|
||||
{data._retryIndex}/{data.retry_config?.max_retries}
|
||||
{data._retryIndex}
|
||||
/
|
||||
{data.retry_config?.max_retries}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@ -1,13 +1,13 @@
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useRetryConfig } from './hooks'
|
||||
import s from './style.module.css'
|
||||
import Switch from '@/app/components/base/switch'
|
||||
import Slider from '@/app/components/base/slider'
|
||||
import Input from '@/app/components/base/input'
|
||||
import type {
|
||||
Node,
|
||||
} from '@/app/components/workflow/types'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import Input from '@/app/components/base/input'
|
||||
import Slider from '@/app/components/base/slider'
|
||||
import Switch from '@/app/components/base/switch'
|
||||
import Split from '@/app/components/workflow/nodes/_base/components/split'
|
||||
import { useRetryConfig } from './hooks'
|
||||
import s from './style.module.css'
|
||||
|
||||
type RetryOnPanelProps = Pick<Node, 'id' | 'data'>
|
||||
const RetryOnPanel = ({
|
||||
@ -52,10 +52,10 @@ const RetryOnPanel = ({
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className='pt-2'>
|
||||
<div className='flex h-10 items-center justify-between px-4 py-2'>
|
||||
<div className='flex items-center'>
|
||||
<div className='system-sm-semibold-uppercase mr-0.5 text-text-secondary'>{t('workflow.nodes.common.retry.retryOnFailure')}</div>
|
||||
<div className="pt-2">
|
||||
<div className="flex h-10 items-center justify-between px-4 py-2">
|
||||
<div className="flex items-center">
|
||||
<div className="system-sm-semibold-uppercase mr-0.5 text-text-secondary">{t('workflow.nodes.common.retry.retryOnFailure')}</div>
|
||||
</div>
|
||||
<Switch
|
||||
defaultValue={retry_config?.retry_enabled}
|
||||
@ -64,45 +64,43 @@ const RetryOnPanel = ({
|
||||
</div>
|
||||
{
|
||||
retry_config?.retry_enabled && (
|
||||
<div className='px-4 pb-2'>
|
||||
<div className='mb-1 flex w-full items-center'>
|
||||
<div className='system-xs-medium-uppercase mr-2 grow text-text-secondary'>{t('workflow.nodes.common.retry.maxRetries')}</div>
|
||||
<div className="px-4 pb-2">
|
||||
<div className="mb-1 flex w-full items-center">
|
||||
<div className="system-xs-medium-uppercase mr-2 grow text-text-secondary">{t('workflow.nodes.common.retry.maxRetries')}</div>
|
||||
<Slider
|
||||
className='mr-3 w-[108px]'
|
||||
className="mr-3 w-[108px]"
|
||||
value={retry_config?.max_retries || 3}
|
||||
onChange={handleMaxRetriesChange}
|
||||
min={1}
|
||||
max={10}
|
||||
/>
|
||||
<Input
|
||||
type='number'
|
||||
wrapperClassName='w-[100px]'
|
||||
type="number"
|
||||
wrapperClassName="w-[100px]"
|
||||
value={retry_config?.max_retries || 3}
|
||||
onChange={e =>
|
||||
handleMaxRetriesChange(Number.parseInt(e.currentTarget.value, 10) || 3)
|
||||
}
|
||||
handleMaxRetriesChange(Number.parseInt(e.currentTarget.value, 10) || 3)}
|
||||
min={1}
|
||||
max={10}
|
||||
unit={t('workflow.nodes.common.retry.times') || ''}
|
||||
className={s.input}
|
||||
/>
|
||||
</div>
|
||||
<div className='flex items-center'>
|
||||
<div className='system-xs-medium-uppercase mr-2 grow text-text-secondary'>{t('workflow.nodes.common.retry.retryInterval')}</div>
|
||||
<div className="flex items-center">
|
||||
<div className="system-xs-medium-uppercase mr-2 grow text-text-secondary">{t('workflow.nodes.common.retry.retryInterval')}</div>
|
||||
<Slider
|
||||
className='mr-3 w-[108px]'
|
||||
className="mr-3 w-[108px]"
|
||||
value={retry_config?.retry_interval || 1000}
|
||||
onChange={handleRetryIntervalChange}
|
||||
min={100}
|
||||
max={5000}
|
||||
/>
|
||||
<Input
|
||||
type='number'
|
||||
wrapperClassName='w-[100px]'
|
||||
type="number"
|
||||
wrapperClassName="w-[100px]"
|
||||
value={retry_config?.retry_interval || 1000}
|
||||
onChange={e =>
|
||||
handleRetryIntervalChange(Number.parseInt(e.currentTarget.value, 10) || 1000)
|
||||
}
|
||||
handleRetryIntervalChange(Number.parseInt(e.currentTarget.value, 10) || 1000)}
|
||||
min={100}
|
||||
max={5000}
|
||||
unit={t('workflow.nodes.common.retry.ms') || ''}
|
||||
@ -113,7 +111,7 @@ const RetryOnPanel = ({
|
||||
)
|
||||
}
|
||||
</div>
|
||||
<Split className='mx-4 mt-2' />
|
||||
<Split className="mx-4 mt-2" />
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
@ -1,10 +1,11 @@
|
||||
'use client'
|
||||
import type { FC } from 'react'
|
||||
import React from 'react'
|
||||
import { useBoolean, useClickAway } from 'ahooks'
|
||||
import { cn } from '@/utils/classnames'
|
||||
import React from 'react'
|
||||
import { ChevronSelectorVertical } from '@/app/components/base/icons/src/vender/line/arrows'
|
||||
import { Check } from '@/app/components/base/icons/src/vender/line/general'
|
||||
import { cn } from '@/utils/classnames'
|
||||
|
||||
type Item = {
|
||||
value: string
|
||||
label: string
|
||||
@ -55,21 +56,22 @@ const TypeSelector: FC<Props> = ({
|
||||
<div className={cn(!trigger && !noLeft && 'left-[-8px]', 'relative select-none', className)} ref={ref}>
|
||||
{trigger
|
||||
? (
|
||||
<div
|
||||
onClick={toggleShow}
|
||||
className={cn(!readonly && 'cursor-pointer')}
|
||||
>
|
||||
{trigger}
|
||||
</div>
|
||||
)
|
||||
<div
|
||||
onClick={toggleShow}
|
||||
className={cn(!readonly && 'cursor-pointer')}
|
||||
>
|
||||
{trigger}
|
||||
</div>
|
||||
)
|
||||
: (
|
||||
<div
|
||||
onClick={toggleShow}
|
||||
className={cn(showOption && 'bg-state-base-hover', 'flex h-5 cursor-pointer items-center rounded-md pl-1 pr-0.5 text-xs font-semibold text-text-secondary hover:bg-state-base-hover')}>
|
||||
<div className={cn('text-sm font-semibold', uppercase && 'uppercase', noValue && 'text-text-tertiary', triggerClassName)}>{!noValue ? item?.label : placeholder}</div>
|
||||
{!readonly && <DropDownIcon className='h-3 w-3 ' />}
|
||||
</div>
|
||||
)}
|
||||
<div
|
||||
onClick={toggleShow}
|
||||
className={cn(showOption && 'bg-state-base-hover', 'flex h-5 cursor-pointer items-center rounded-md pl-1 pr-0.5 text-xs font-semibold text-text-secondary hover:bg-state-base-hover')}
|
||||
>
|
||||
<div className={cn('text-sm font-semibold', uppercase && 'uppercase', noValue && 'text-text-tertiary', triggerClassName)}>{!noValue ? item?.label : placeholder}</div>
|
||||
{!readonly && <DropDownIcon className="h-3 w-3 " />}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{(showOption && !readonly) && (
|
||||
<div className={cn('absolute top-[24px] z-10 w-[120px] select-none rounded-lg border border-components-panel-border bg-components-panel-bg p-1 shadow-lg', popupClassName)}>
|
||||
@ -83,13 +85,11 @@ const TypeSelector: FC<Props> = ({
|
||||
className={cn(itemClassName, uppercase && 'uppercase', 'flex h-[30px] min-w-[44px] cursor-pointer items-center justify-between rounded-lg px-3 text-[13px] font-medium text-text-secondary hover:bg-state-base-hover')}
|
||||
>
|
||||
<div>{item.label}</div>
|
||||
{showChecked && item.value === value && <Check className='h-4 w-4 text-text-primary' />}
|
||||
{showChecked && item.value === value && <Check className="h-4 w-4 text-text-primary" />}
|
||||
</div>
|
||||
))
|
||||
}
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@ -1,7 +1,8 @@
|
||||
import type { ComponentProps, PropsWithChildren, ReactNode } from 'react'
|
||||
import { memo } from 'react'
|
||||
import Tooltip from '@/app/components/base/tooltip'
|
||||
import Indicator from '@/app/components/header/indicator'
|
||||
import { cn } from '@/utils/classnames'
|
||||
import { type ComponentProps, type PropsWithChildren, type ReactNode, memo } from 'react'
|
||||
|
||||
export type SettingItemProps = PropsWithChildren<{
|
||||
label: string
|
||||
@ -12,17 +13,19 @@ export type SettingItemProps = PropsWithChildren<{
|
||||
export const SettingItem = memo(({ label, children, status, tooltip }: SettingItemProps) => {
|
||||
const indicator: ComponentProps<typeof Indicator>['color'] = status === 'error' ? 'red' : status === 'warning' ? 'yellow' : undefined
|
||||
const needTooltip = ['error', 'warning'].includes(status as any)
|
||||
return <div className='relative flex items-center justify-between space-x-1 rounded-md bg-workflow-block-parma-bg px-1.5 py-1 text-xs font-normal'>
|
||||
<div className={cn('system-xs-medium-uppercase max-w-full shrink-0 truncate text-text-tertiary', !!children && 'max-w-[100px]')}>
|
||||
{label}
|
||||
</div>
|
||||
<Tooltip popupContent={tooltip} disabled={!needTooltip}>
|
||||
<div className='system-xs-medium truncate text-right text-text-secondary'>
|
||||
{children}
|
||||
return (
|
||||
<div className="relative flex items-center justify-between space-x-1 rounded-md bg-workflow-block-parma-bg px-1.5 py-1 text-xs font-normal">
|
||||
<div className={cn('system-xs-medium-uppercase max-w-full shrink-0 truncate text-text-tertiary', !!children && 'max-w-[100px]')}>
|
||||
{label}
|
||||
</div>
|
||||
</Tooltip>
|
||||
{indicator && <Indicator color={indicator} className='absolute -right-0.5 -top-0.5' />}
|
||||
</div>
|
||||
<Tooltip popupContent={tooltip} disabled={!needTooltip}>
|
||||
<div className="system-xs-medium truncate text-right text-text-secondary">
|
||||
{children}
|
||||
</div>
|
||||
</Tooltip>
|
||||
{indicator && <Indicator color={indicator} className="absolute -right-0.5 -top-0.5" />}
|
||||
</div>
|
||||
)
|
||||
})
|
||||
|
||||
SettingItem.displayName = 'SettingItem'
|
||||
|
||||
@ -1,8 +1,9 @@
|
||||
'use client'
|
||||
import type { FC } from 'react'
|
||||
import React from 'react'
|
||||
import { cn } from '@/utils/classnames'
|
||||
import VarHighlight from '@/app/components/app/configuration/base/var-highlight'
|
||||
import { cn } from '@/utils/classnames'
|
||||
|
||||
type Props = {
|
||||
isFocus?: boolean
|
||||
onFocus?: () => void
|
||||
@ -46,20 +47,21 @@ const SupportVarInput: FC<Props> = ({
|
||||
<div
|
||||
className={
|
||||
cn(wrapClassName, 'flex h-full w-full')
|
||||
} onClick={onFocus}
|
||||
}
|
||||
onClick={onFocus}
|
||||
>
|
||||
{(isFocus && !readonly && children)
|
||||
? (
|
||||
children
|
||||
)
|
||||
children
|
||||
)
|
||||
: (
|
||||
<div
|
||||
className={cn(textClassName, 'h-full w-0 grow truncate whitespace-nowrap')}
|
||||
title={value}
|
||||
>
|
||||
{renderSafeContent(value || '')}
|
||||
</div>
|
||||
)}
|
||||
<div
|
||||
className={cn(textClassName, 'h-full w-0 grow truncate whitespace-nowrap')}
|
||||
title={value}
|
||||
>
|
||||
{renderSafeContent(value || '')}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@ -1,20 +1,20 @@
|
||||
'use client'
|
||||
|
||||
import Badge from '@/app/components/base/badge'
|
||||
import Tooltip from '@/app/components/base/tooltip'
|
||||
import PluginVersionPicker from '@/app/components/plugins/update-plugin/plugin-version-picker'
|
||||
import type { FC, ReactNode } from 'react'
|
||||
import { RiArrowLeftRightLine, RiExternalLinkLine } from '@remixicon/react'
|
||||
import type { ReactNode } from 'react'
|
||||
import { type FC, useCallback, useState } from 'react'
|
||||
import { useBoolean } from 'ahooks'
|
||||
import { useCheckInstalled, useUpdatePackageFromMarketPlace } from '@/service/use-plugins'
|
||||
import { cn } from '@/utils/classnames'
|
||||
import PluginMutationModel from '@/app/components/plugins/plugin-mutation-model'
|
||||
import Link from 'next/link'
|
||||
import { useCallback, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import Badge from '@/app/components/base/badge'
|
||||
import { Badge as Badge2, BadgeState } from '@/app/components/base/badge/index'
|
||||
import Tooltip from '@/app/components/base/tooltip'
|
||||
import useGetIcon from '@/app/components/plugins/install-plugin/base/use-get-icon'
|
||||
import { pluginManifestToCardPluginProps } from '@/app/components/plugins/install-plugin/utils'
|
||||
import { Badge as Badge2, BadgeState } from '@/app/components/base/badge/index'
|
||||
import Link from 'next/link'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import PluginMutationModel from '@/app/components/plugins/plugin-mutation-model'
|
||||
import PluginVersionPicker from '@/app/components/plugins/update-plugin/plugin-version-picker'
|
||||
import { useCheckInstalled, useUpdatePackageFromMarketPlace } from '@/service/use-plugins'
|
||||
import { cn } from '@/utils/classnames'
|
||||
import { getMarketplaceUrl } from '@/utils/var'
|
||||
|
||||
export type SwitchPluginVersionProps = {
|
||||
@ -31,8 +31,8 @@ export const SwitchPluginVersion: FC<SwitchPluginVersionProps> = (props) => {
|
||||
const [isShow, setIsShow] = useState(false)
|
||||
const [isShowUpdateModal, { setTrue: showUpdateModal, setFalse: hideUpdateModal }] = useBoolean(false)
|
||||
const [target, setTarget] = useState<{
|
||||
version: string,
|
||||
pluginUniqueIden: string;
|
||||
version: string
|
||||
pluginUniqueIden: string
|
||||
}>()
|
||||
const pluginDetails = useCheckInstalled({
|
||||
pluginIds: [pluginId],
|
||||
@ -58,7 +58,8 @@ export const SwitchPluginVersion: FC<SwitchPluginVersionProps> = (props) => {
|
||||
onSuccess() {
|
||||
handleUpdatedFromMarketplace()
|
||||
},
|
||||
})
|
||||
},
|
||||
)
|
||||
}
|
||||
const { t } = useTranslation()
|
||||
|
||||
@ -66,67 +67,75 @@ export const SwitchPluginVersion: FC<SwitchPluginVersionProps> = (props) => {
|
||||
if (!uniqueIdentifier || !pluginId)
|
||||
return null
|
||||
|
||||
return <Tooltip popupContent={!isShow && !isShowUpdateModal && tooltip} triggerMethod='hover'>
|
||||
<div className={cn('flex w-fit items-center justify-center', className)} onClick={e => e.stopPropagation()}>
|
||||
{isShowUpdateModal && pluginDetail && <PluginMutationModel
|
||||
onCancel={hideUpdateModal}
|
||||
plugin={pluginManifestToCardPluginProps({
|
||||
...pluginDetail.declaration,
|
||||
icon: icon!,
|
||||
})}
|
||||
mutation={mutation}
|
||||
mutate={install}
|
||||
confirmButtonText={t('workflow.nodes.agent.installPlugin.install')}
|
||||
cancelButtonText={t('workflow.nodes.agent.installPlugin.cancel')}
|
||||
modelTitle={t('workflow.nodes.agent.installPlugin.title')}
|
||||
description={t('workflow.nodes.agent.installPlugin.desc')}
|
||||
cardTitleLeft={<>
|
||||
<Badge2 className='mx-1' size="s" state={BadgeState.Warning}>
|
||||
{`${pluginDetail.version} -> ${target!.version}`}
|
||||
</Badge2>
|
||||
</>}
|
||||
modalBottomLeft={
|
||||
<Link
|
||||
className='flex items-center justify-center gap-1'
|
||||
href={getMarketplaceUrl(`/plugins/${pluginDetail.declaration.author}/${pluginDetail.declaration.name}`)}
|
||||
target='_blank'
|
||||
>
|
||||
<span className='system-xs-regular text-xs text-text-accent'>
|
||||
{t('workflow.nodes.agent.installPlugin.changelog')}
|
||||
</span>
|
||||
<RiExternalLinkLine className='size-3 text-text-accent' />
|
||||
</Link>
|
||||
}
|
||||
/>}
|
||||
{pluginDetail && <PluginVersionPicker
|
||||
isShow={isShow}
|
||||
onShowChange={setIsShow}
|
||||
pluginID={pluginId}
|
||||
currentVersion={pluginDetail.version}
|
||||
onSelect={(state) => {
|
||||
setTarget({
|
||||
pluginUniqueIden: state.unique_identifier,
|
||||
version: state.version,
|
||||
})
|
||||
showUpdateModal()
|
||||
}}
|
||||
trigger={
|
||||
<Badge
|
||||
className={cn(
|
||||
'mx-1 flex hover:bg-state-base-hover',
|
||||
isShow && 'bg-state-base-hover',
|
||||
)}
|
||||
uppercase={true}
|
||||
text={
|
||||
return (
|
||||
<Tooltip popupContent={!isShow && !isShowUpdateModal && tooltip} triggerMethod="hover">
|
||||
<div className={cn('flex w-fit items-center justify-center', className)} onClick={e => e.stopPropagation()}>
|
||||
{isShowUpdateModal && pluginDetail && (
|
||||
<PluginMutationModel
|
||||
onCancel={hideUpdateModal}
|
||||
plugin={pluginManifestToCardPluginProps({
|
||||
...pluginDetail.declaration,
|
||||
icon: icon!,
|
||||
})}
|
||||
mutation={mutation}
|
||||
mutate={install}
|
||||
confirmButtonText={t('workflow.nodes.agent.installPlugin.install')}
|
||||
cancelButtonText={t('workflow.nodes.agent.installPlugin.cancel')}
|
||||
modelTitle={t('workflow.nodes.agent.installPlugin.title')}
|
||||
description={t('workflow.nodes.agent.installPlugin.desc')}
|
||||
cardTitleLeft={(
|
||||
<>
|
||||
<div>{pluginDetail.version}</div>
|
||||
<RiArrowLeftRightLine className='ml-1 h-3 w-3 text-text-tertiary' />
|
||||
<Badge2 className="mx-1" size="s" state={BadgeState.Warning}>
|
||||
{`${pluginDetail.version} -> ${target!.version}`}
|
||||
</Badge2>
|
||||
</>
|
||||
}
|
||||
hasRedCornerMark={true}
|
||||
)}
|
||||
modalBottomLeft={(
|
||||
<Link
|
||||
className="flex items-center justify-center gap-1"
|
||||
href={getMarketplaceUrl(`/plugins/${pluginDetail.declaration.author}/${pluginDetail.declaration.name}`)}
|
||||
target="_blank"
|
||||
>
|
||||
<span className="system-xs-regular text-xs text-text-accent">
|
||||
{t('workflow.nodes.agent.installPlugin.changelog')}
|
||||
</span>
|
||||
<RiExternalLinkLine className="size-3 text-text-accent" />
|
||||
</Link>
|
||||
)}
|
||||
/>
|
||||
}
|
||||
/>}
|
||||
</div>
|
||||
</Tooltip>
|
||||
)}
|
||||
{pluginDetail && (
|
||||
<PluginVersionPicker
|
||||
isShow={isShow}
|
||||
onShowChange={setIsShow}
|
||||
pluginID={pluginId}
|
||||
currentVersion={pluginDetail.version}
|
||||
onSelect={(state) => {
|
||||
setTarget({
|
||||
pluginUniqueIden: state.unique_identifier,
|
||||
version: state.version,
|
||||
})
|
||||
showUpdateModal()
|
||||
}}
|
||||
trigger={(
|
||||
<Badge
|
||||
className={cn(
|
||||
'mx-1 flex hover:bg-state-base-hover',
|
||||
isShow && 'bg-state-base-hover',
|
||||
)}
|
||||
uppercase={true}
|
||||
text={(
|
||||
<>
|
||||
<div>{pluginDetail.version}</div>
|
||||
<RiArrowLeftRightLine className="ml-1 h-3 w-3 text-text-tertiary" />
|
||||
</>
|
||||
)}
|
||||
hasRedCornerMark={true}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</Tooltip>
|
||||
)
|
||||
}
|
||||
|
||||
@ -3,8 +3,8 @@ import {
|
||||
useCallback,
|
||||
useState,
|
||||
} from 'react'
|
||||
import Textarea from 'react-textarea-autosize'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import Textarea from 'react-textarea-autosize'
|
||||
|
||||
type TitleInputProps = {
|
||||
value: string
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
'use client'
|
||||
import type { FC } from 'react'
|
||||
import React, { useCallback } from 'react'
|
||||
import {
|
||||
RiCollapseDiagonalLine,
|
||||
RiExpandDiagonalLine,
|
||||
} from '@remixicon/react'
|
||||
import React, { useCallback } from 'react'
|
||||
import ActionButton from '@/app/components/base/action-button'
|
||||
|
||||
type Props = {
|
||||
@ -23,7 +23,7 @@ const ExpandBtn: FC<Props> = ({
|
||||
const Icon = isExpand ? RiCollapseDiagonalLine : RiExpandDiagonalLine
|
||||
return (
|
||||
<ActionButton onClick={handleToggle}>
|
||||
<Icon className='h-4 w-4' />
|
||||
<Icon className="h-4 w-4" />
|
||||
</ActionButton>
|
||||
)
|
||||
}
|
||||
|
||||
@ -1,18 +1,18 @@
|
||||
import { useCallback, useMemo } from 'react'
|
||||
import { useNodes, useReactFlow, useStoreApi } from 'reactflow'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import type {
|
||||
CommonNodeType,
|
||||
Node,
|
||||
ValueSelector,
|
||||
VarType,
|
||||
} from '@/app/components/workflow/types'
|
||||
import { BlockEnum } from '@/app/components/workflow/types'
|
||||
import { useCallback, useMemo } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useNodes, useReactFlow, useStoreApi } from 'reactflow'
|
||||
import { getNodeInfoById, isConversationVar, isENV, isGlobalVar, isRagVariableVar, isSystemVar } from '@/app/components/workflow/nodes/_base/components/variable/utils'
|
||||
import { isExceptionVariable } from '@/app/components/workflow/utils'
|
||||
import {
|
||||
VariableLabelInSelect,
|
||||
} from '@/app/components/workflow/nodes/_base/components/variable/variable-label'
|
||||
import { BlockEnum } from '@/app/components/workflow/types'
|
||||
import { isExceptionVariable } from '@/app/components/workflow/utils'
|
||||
|
||||
type VariableTagProps = {
|
||||
valueSelector: ValueSelector
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
'use client'
|
||||
import type { FC } from 'react'
|
||||
import type { NodeOutPutVar, ValueSelector, Var } from '@/app/components/workflow/types'
|
||||
import React from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import VarReferenceVars from './var-reference-vars'
|
||||
import type { NodeOutPutVar, ValueSelector, Var } from '@/app/components/workflow/types'
|
||||
import ListEmpty from '@/app/components/base/list-empty'
|
||||
import VarReferenceVars from './var-reference-vars'
|
||||
|
||||
type Props = {
|
||||
vars: NodeOutPutVar[]
|
||||
@ -19,21 +19,24 @@ const AssignedVarReferencePopup: FC<Props> = ({
|
||||
const { t } = useTranslation()
|
||||
// max-h-[300px] overflow-y-auto todo: use portal to handle long list
|
||||
return (
|
||||
<div className='bg-components-panel-bg-bur w-[352px] rounded-lg border-[0.5px] border-components-panel-border p-1 shadow-lg' >
|
||||
<div className="bg-components-panel-bg-bur w-[352px] rounded-lg border-[0.5px] border-components-panel-border p-1 shadow-lg">
|
||||
{(!vars || vars.length === 0)
|
||||
? <ListEmpty
|
||||
title={t('workflow.nodes.assigner.noAssignedVars') || ''}
|
||||
description={t('workflow.nodes.assigner.assignedVarsDescription')}
|
||||
/>
|
||||
: <VarReferenceVars
|
||||
searchBoxClassName='mt-1'
|
||||
vars={vars}
|
||||
onChange={onChange}
|
||||
itemWidth={itemWidth}
|
||||
isSupportFileVar
|
||||
/>
|
||||
}
|
||||
</div >
|
||||
? (
|
||||
<ListEmpty
|
||||
title={t('workflow.nodes.assigner.noAssignedVars') || ''}
|
||||
description={t('workflow.nodes.assigner.assignedVarsDescription')}
|
||||
/>
|
||||
)
|
||||
: (
|
||||
<VarReferenceVars
|
||||
searchBoxClassName="mt-1"
|
||||
vars={vars}
|
||||
onChange={onChange}
|
||||
itemWidth={itemWidth}
|
||||
isSupportFileVar
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
export default React.memo(AssignedVarReferencePopup)
|
||||
|
||||
@ -1,12 +1,12 @@
|
||||
'use client'
|
||||
import type { FC } from 'react'
|
||||
import React, { useCallback } from 'react'
|
||||
import type { CredentialFormSchema, CredentialFormSchemaNumberInput, CredentialFormSchemaSelect } from '@/app/components/header/account-setting/model-provider-page/declarations'
|
||||
import type { Var } from '@/app/components/workflow/types'
|
||||
import React, { useCallback } from 'react'
|
||||
import { SimpleSelect } from '@/app/components/base/select'
|
||||
import { FormTypeEnum } from '@/app/components/header/account-setting/model-provider-page/declarations'
|
||||
import { useLanguage } from '@/app/components/header/account-setting/model-provider-page/hooks'
|
||||
import { VarType as VarKindType } from '@/app/components/workflow/nodes/tool/types'
|
||||
import type { Var } from '@/app/components/workflow/types'
|
||||
import { SimpleSelect } from '@/app/components/base/select'
|
||||
|
||||
type Props = {
|
||||
schema: Partial<CredentialFormSchema>
|
||||
@ -42,8 +42,8 @@ const ConstantField: FC<Props> = ({
|
||||
<>
|
||||
{(schema.type === FormTypeEnum.select || schema.type === FormTypeEnum.dynamicSelect) && (
|
||||
<SimpleSelect
|
||||
wrapperClassName='w-full !h-8'
|
||||
className='flex items-center'
|
||||
wrapperClassName="w-full !h-8"
|
||||
className="flex items-center"
|
||||
disabled={readonly}
|
||||
defaultValue={value}
|
||||
items={(schema as CredentialFormSchemaSelect).options.map(option => ({ value: option.value, name: option.label[language] || option.label.en_US }))}
|
||||
@ -55,8 +55,8 @@ const ConstantField: FC<Props> = ({
|
||||
)}
|
||||
{schema.type === FormTypeEnum.textNumber && (
|
||||
<input
|
||||
type='number'
|
||||
className='h-8 w-full overflow-hidden rounded-lg bg-workflow-block-parma-bg p-2 text-[13px] font-normal leading-8 text-text-secondary placeholder:text-gray-400 focus:outline-none'
|
||||
type="number"
|
||||
className="h-8 w-full overflow-hidden rounded-lg bg-workflow-block-parma-bg p-2 text-[13px] font-normal leading-8 text-text-secondary placeholder:text-gray-400 focus:outline-none"
|
||||
value={value}
|
||||
onChange={handleStaticChange}
|
||||
readOnly={readonly}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { RiAddLine } from '@remixicon/react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
|
||||
type ManageInputFieldProps = {
|
||||
onManage: () => void
|
||||
@ -11,22 +11,22 @@ const ManageInputField = ({
|
||||
const { t } = useTranslation()
|
||||
|
||||
return (
|
||||
<div className='flex items-center border-t border-divider-subtle pt-1'>
|
||||
<div className="flex items-center border-t border-divider-subtle pt-1">
|
||||
<div
|
||||
className='flex h-8 grow cursor-pointer items-center px-3'
|
||||
className="flex h-8 grow cursor-pointer items-center px-3"
|
||||
onClick={onManage}
|
||||
>
|
||||
<RiAddLine className='mr-1 h-4 w-4 text-text-tertiary' />
|
||||
<RiAddLine className="mr-1 h-4 w-4 text-text-tertiary" />
|
||||
<div
|
||||
className='system-xs-medium truncate text-text-tertiary'
|
||||
title='Create user input field'
|
||||
className="system-xs-medium truncate text-text-tertiary"
|
||||
title="Create user input field"
|
||||
>
|
||||
{t('pipeline.inputField.create')}
|
||||
</div>
|
||||
</div>
|
||||
<div className='mx-1 h-3 w-[1px] shrink-0 bg-divider-regular'></div>
|
||||
<div className="mx-1 h-3 w-[1px] shrink-0 bg-divider-regular"></div>
|
||||
<div
|
||||
className='system-xs-medium flex h-8 shrink-0 cursor-pointer items-center justify-center px-3 text-text-tertiary'
|
||||
className="system-xs-medium flex h-8 shrink-0 cursor-pointer items-center justify-center px-3 text-text-tertiary"
|
||||
onClick={onManage}
|
||||
>
|
||||
{t('pipeline.inputField.manage')}
|
||||
|
||||
@ -7,7 +7,7 @@ function matchTheSchemaType(scheme: AnyObj, target: AnyObj): boolean {
|
||||
const isMatch = (schema: AnyObj, t: AnyObj): boolean => {
|
||||
const oSchema = isObj(schema)
|
||||
const oT = isObj(t)
|
||||
if(!oSchema)
|
||||
if (!oSchema)
|
||||
return true
|
||||
if (!oT) { // ignore the object without type
|
||||
// deep find oSchema has type
|
||||
@ -24,14 +24,18 @@ function matchTheSchemaType(scheme: AnyObj, target: AnyObj): boolean {
|
||||
const ty = (t as any).type
|
||||
const isTypeValueObj = isObj(tx)
|
||||
|
||||
if(!isTypeValueObj) // caution: type can be object, so that it would not be compare by value
|
||||
if (tx !== ty) return false
|
||||
if (!isTypeValueObj) { // caution: type can be object, so that it would not be compare by value
|
||||
if (tx !== ty)
|
||||
return false
|
||||
}
|
||||
|
||||
// recurse into all keys
|
||||
const keys = new Set([...Object.keys(schema as object), ...Object.keys(t as object)])
|
||||
for (const k of keys) {
|
||||
if (k === 'type' && !isTypeValueObj) continue // already checked
|
||||
if (!isMatch((schema as any)[k], (t as any)[k])) return false
|
||||
if (k === 'type' && !isTypeValueObj)
|
||||
continue // already checked
|
||||
if (!isMatch((schema as any)[k], (t as any)[k]))
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
@ -1,22 +1,22 @@
|
||||
'use client'
|
||||
import type { FC } from 'react'
|
||||
import type { Field as FieldType } from '../../../../../llm/types'
|
||||
import type { ValueSelector } from '@/app/components/workflow/types'
|
||||
import { RiMoreFill } from '@remixicon/react'
|
||||
import React from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import Tooltip from '@/app/components/base/tooltip'
|
||||
import { cn } from '@/utils/classnames'
|
||||
import { Type } from '../../../../../llm/types'
|
||||
import { getFieldType } from '../../../../../llm/utils'
|
||||
import type { Field as FieldType } from '../../../../../llm/types'
|
||||
import { cn } from '@/utils/classnames'
|
||||
import TreeIndentLine from '../tree-indent-line'
|
||||
import { RiMoreFill } from '@remixicon/react'
|
||||
import Tooltip from '@/app/components/base/tooltip'
|
||||
import type { ValueSelector } from '@/app/components/workflow/types'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
|
||||
const MAX_DEPTH = 10
|
||||
|
||||
type Props = {
|
||||
valueSelector: ValueSelector
|
||||
name: string,
|
||||
payload: FieldType,
|
||||
name: string
|
||||
payload: FieldType
|
||||
depth?: number
|
||||
readonly?: boolean
|
||||
onSelect?: (valueSelector: ValueSelector) => void
|
||||
@ -43,15 +43,17 @@ const Field: FC<Props> = ({
|
||||
className={cn('flex items-center justify-between rounded-md pr-2', !readonly && 'hover:bg-state-base-hover', depth !== MAX_DEPTH + 1 && 'cursor-pointer')}
|
||||
onMouseDown={() => !readonly && onSelect?.([...valueSelector, name])}
|
||||
>
|
||||
<div className='flex grow items-stretch'>
|
||||
<div className="flex grow items-stretch">
|
||||
<TreeIndentLine depth={depth} />
|
||||
{depth === MAX_DEPTH + 1 ? (
|
||||
<RiMoreFill className='h-3 w-3 text-text-tertiary' />
|
||||
) : (<div className={cn('system-sm-medium h-6 w-0 grow truncate leading-6 text-text-secondary', isHighlight && 'text-text-accent')}>{name}</div>)}
|
||||
{depth === MAX_DEPTH + 1
|
||||
? (
|
||||
<RiMoreFill className="h-3 w-3 text-text-tertiary" />
|
||||
)
|
||||
: (<div className={cn('system-sm-medium h-6 w-0 grow truncate leading-6 text-text-secondary', isHighlight && 'text-text-accent')}>{name}</div>)}
|
||||
|
||||
</div>
|
||||
{depth < MAX_DEPTH + 1 && (
|
||||
<div className='system-xs-regular ml-2 shrink-0 text-text-tertiary'>{getFieldType(payload)}</div>
|
||||
<div className="system-xs-regular ml-2 shrink-0 text-text-tertiary">{getFieldType(payload)}</div>
|
||||
)}
|
||||
</div>
|
||||
</Tooltip>
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
'use client'
|
||||
import type { FC } from 'react'
|
||||
import React, { useRef } from 'react'
|
||||
import type { StructuredOutput } from '../../../../../llm/types'
|
||||
import Field from './field'
|
||||
import { cn } from '@/utils/classnames'
|
||||
import { useHover } from 'ahooks'
|
||||
import type { ValueSelector } from '@/app/components/workflow/types'
|
||||
import { useHover } from 'ahooks'
|
||||
import React, { useRef } from 'react'
|
||||
import { cn } from '@/utils/classnames'
|
||||
import Field from './field'
|
||||
|
||||
type Props = {
|
||||
className?: string
|
||||
@ -42,17 +42,17 @@ export const PickerPanelMain: FC<Props> = ({
|
||||
return (
|
||||
<div className={cn(className)} ref={ref}>
|
||||
{/* Root info */}
|
||||
<div className='flex items-center justify-between px-2 py-1'>
|
||||
<div className='flex'>
|
||||
<div className="flex items-center justify-between px-2 py-1">
|
||||
<div className="flex">
|
||||
{root.nodeName && (
|
||||
<>
|
||||
<div className='system-sm-medium max-w-[100px] truncate text-text-tertiary'>{root.nodeName}</div>
|
||||
<div className='system-sm-medium text-text-tertiary'>.</div>
|
||||
<div className="system-sm-medium max-w-[100px] truncate text-text-tertiary">{root.nodeName}</div>
|
||||
<div className="system-sm-medium text-text-tertiary">.</div>
|
||||
</>
|
||||
)}
|
||||
<div className='system-sm-medium text-text-secondary'>{root.attrName}</div>
|
||||
<div className="system-sm-medium text-text-secondary">{root.attrName}</div>
|
||||
</div>
|
||||
<div className='system-xs-regular ml-2 truncate text-text-tertiary' title={root.attrAlias || 'object'}>{root.attrAlias || 'object'}</div>
|
||||
<div className="system-xs-regular ml-2 truncate text-text-tertiary" title={root.attrAlias || 'object'}>{root.attrAlias || 'object'}</div>
|
||||
</div>
|
||||
{fieldNames.map(name => (
|
||||
<Field
|
||||
|
||||
@ -1,20 +1,20 @@
|
||||
'use client'
|
||||
import { cn } from '@/utils/classnames'
|
||||
import type { FC } from 'react'
|
||||
import type { Field as FieldType } from '../../../../../llm/types'
|
||||
import { RiArrowDropDownLine } from '@remixicon/react'
|
||||
import { useBoolean } from 'ahooks'
|
||||
import type { FC } from 'react'
|
||||
import React from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import type { Field as FieldType } from '../../../../../llm/types'
|
||||
import { cn } from '@/utils/classnames'
|
||||
import { Type } from '../../../../../llm/types'
|
||||
import { getFieldType } from '../../../../../llm/utils'
|
||||
import TreeIndentLine from '../tree-indent-line'
|
||||
|
||||
type Props = {
|
||||
name: string,
|
||||
payload: FieldType,
|
||||
required: boolean,
|
||||
depth?: number,
|
||||
name: string
|
||||
payload: FieldType
|
||||
required: boolean
|
||||
depth?: number
|
||||
rootClassName?: string
|
||||
}
|
||||
|
||||
@ -36,8 +36,8 @@ const Field: FC<Props> = ({
|
||||
<div>
|
||||
<div className={cn('flex pr-2')}>
|
||||
<TreeIndentLine depth={depth} />
|
||||
<div className='w-0 grow'>
|
||||
<div className='relative flex select-none'>
|
||||
<div className="w-0 grow">
|
||||
<div className="relative flex select-none">
|
||||
{hasChildren && (
|
||||
<RiArrowDropDownLine
|
||||
className={cn('absolute left-[-18px] top-[50%] h-4 w-4 translate-y-[-50%] cursor-pointer bg-components-panel-bg text-text-tertiary', fold && 'rotate-[270deg] text-text-accent')}
|
||||
@ -45,20 +45,20 @@ const Field: FC<Props> = ({
|
||||
/>
|
||||
)}
|
||||
<div className={cn('system-sm-medium ml-[7px] h-6 truncate leading-6 text-text-secondary', isRoot && rootClassName)}>{name}</div>
|
||||
<div className='system-xs-regular ml-3 shrink-0 leading-6 text-text-tertiary'>
|
||||
<div className="system-xs-regular ml-3 shrink-0 leading-6 text-text-tertiary">
|
||||
{getFieldType(payload)}
|
||||
{(payload.schemaType && payload.schemaType !== 'file' && ` (${payload.schemaType})`)}
|
||||
</div>
|
||||
{required && <div className='system-2xs-medium-uppercase ml-3 leading-6 text-text-warning'>{t('app.structOutput.required')}</div>}
|
||||
{required && <div className="system-2xs-medium-uppercase ml-3 leading-6 text-text-warning">{t('app.structOutput.required')}</div>}
|
||||
</div>
|
||||
{payload.description && (
|
||||
<div className='ml-[7px] flex'>
|
||||
<div className='system-xs-regular w-0 grow truncate text-text-tertiary'>{payload.description}</div>
|
||||
<div className="ml-[7px] flex">
|
||||
<div className="system-xs-regular w-0 grow truncate text-text-tertiary">{payload.description}</div>
|
||||
</div>
|
||||
)}
|
||||
{hasEnum && (
|
||||
<div className='ml-[7px] flex'>
|
||||
<div className='system-xs-regular w-0 grow text-text-quaternary'>
|
||||
<div className="ml-[7px] flex">
|
||||
<div className="system-xs-regular w-0 grow text-text-quaternary">
|
||||
{payload.enum!.map((value, index) => (
|
||||
<span key={index}>
|
||||
{typeof value === 'string' ? `"${value}"` : value}
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
'use client'
|
||||
import type { FC } from 'react'
|
||||
import React from 'react'
|
||||
import type { StructuredOutput } from '../../../../../llm/types'
|
||||
import Field from './field'
|
||||
import React from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import Field from './field'
|
||||
|
||||
type Props = {
|
||||
payload: StructuredOutput
|
||||
@ -23,7 +23,7 @@ const ShowPanel: FC<Props> = ({
|
||||
},
|
||||
}
|
||||
return (
|
||||
<div className='relative left-[-7px]'>
|
||||
<div className="relative left-[-7px]">
|
||||
{Object.keys(schema.schema.properties!).map(name => (
|
||||
<Field
|
||||
key={name}
|
||||
|
||||
@ -4,8 +4,8 @@ import React from 'react'
|
||||
import { cn } from '@/utils/classnames'
|
||||
|
||||
type Props = {
|
||||
depth?: number,
|
||||
className?: string,
|
||||
depth?: number
|
||||
className?: string
|
||||
}
|
||||
|
||||
const TreeIndentLine: FC<Props> = ({
|
||||
|
||||
@ -1,17 +1,17 @@
|
||||
'use client'
|
||||
import type { FC } from 'react'
|
||||
import React, { useCallback, useState } from 'react'
|
||||
import { produce } from 'immer'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import type { OutputVar } from '../../../code/types'
|
||||
import type { ToastHandle } from '@/app/components/base/toast'
|
||||
import type { VarType } from '@/app/components/workflow/types'
|
||||
import { useDebounceFn } from 'ahooks'
|
||||
import { produce } from 'immer'
|
||||
import React, { useCallback, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import Input from '@/app/components/base/input'
|
||||
import Toast from '@/app/components/base/toast'
|
||||
import { checkKeys, replaceSpaceWithUnderscoreInVarNameInput } from '@/utils/var'
|
||||
import RemoveButton from '../remove-button'
|
||||
import VarTypePicker from './var-type-picker'
|
||||
import Input from '@/app/components/base/input'
|
||||
import type { VarType } from '@/app/components/workflow/types'
|
||||
import { checkKeys, replaceSpaceWithUnderscoreInVarNameInput } from '@/utils/var'
|
||||
import type { ToastHandle } from '@/app/components/base/toast'
|
||||
import Toast from '@/app/components/base/toast'
|
||||
import { useDebounceFn } from 'ahooks'
|
||||
|
||||
type Props = {
|
||||
readonly: boolean
|
||||
@ -93,14 +93,14 @@ const OutputVarList: FC<Props> = ({
|
||||
}, [onRemove])
|
||||
|
||||
return (
|
||||
<div className='space-y-2'>
|
||||
<div className="space-y-2">
|
||||
{list.map((item, index) => (
|
||||
<div className='flex items-center space-x-1' key={index}>
|
||||
<div className="flex items-center space-x-1" key={index}>
|
||||
<Input
|
||||
readOnly={readonly}
|
||||
value={item.variable}
|
||||
onChange={handleVarNameChange(index)}
|
||||
wrapperClassName='grow'
|
||||
wrapperClassName="grow"
|
||||
/>
|
||||
<VarTypePicker
|
||||
readonly={readonly}
|
||||
@ -108,7 +108,7 @@ const OutputVarList: FC<Props> = ({
|
||||
onChange={handleVarTypeChange(index)}
|
||||
/>
|
||||
<RemoveButton
|
||||
className='!bg-gray-100 !p-2 hover:!bg-gray-200'
|
||||
className="!bg-gray-100 !p-2 hover:!bg-gray-200"
|
||||
onClick={handleVarRemove(index)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@ -1,10 +1,11 @@
|
||||
import type { AnyObj } from './match-schema-type'
|
||||
import type { SchemaTypeDefinition } from '@/service/use-common'
|
||||
import { useSchemaTypeDefinitions } from '@/service/use-common'
|
||||
import type { AnyObj } from './match-schema-type'
|
||||
import matchTheSchemaType from './match-schema-type'
|
||||
|
||||
export const getMatchedSchemaType = (obj: AnyObj, schemaTypeDefinitions?: SchemaTypeDefinition[]): string => {
|
||||
if(!schemaTypeDefinitions || obj === undefined || obj === null) return ''
|
||||
if (!schemaTypeDefinitions || obj === undefined || obj === null)
|
||||
return ''
|
||||
const matched = schemaTypeDefinitions.find(def => matchTheSchemaType(obj, def.schema))
|
||||
return matched ? matched.name : ''
|
||||
}
|
||||
|
||||
@ -1,32 +1,26 @@
|
||||
import { produce } from 'immer'
|
||||
import { isArray, uniq } from 'lodash-es'
|
||||
import type { CodeNodeType } from '../../../code/types'
|
||||
import type { EndNodeType } from '../../../end/types'
|
||||
import type { AgentNodeType } from '../../../agent/types'
|
||||
import type { AnswerNodeType } from '../../../answer/types'
|
||||
import {
|
||||
type LLMNodeType,
|
||||
type StructuredOutput,
|
||||
Type,
|
||||
} from '../../../llm/types'
|
||||
import type { KnowledgeRetrievalNodeType } from '../../../knowledge-retrieval/types'
|
||||
import type { IfElseNodeType } from '../../../if-else/types'
|
||||
import type { TemplateTransformNodeType } from '../../../template-transform/types'
|
||||
import type { QuestionClassifierNodeType } from '../../../question-classifier/types'
|
||||
import type { HttpNodeType } from '../../../http/types'
|
||||
import { VarType as ToolVarType } from '../../../tool/types'
|
||||
import type { ToolNodeType } from '../../../tool/types'
|
||||
import type { ParameterExtractorNodeType } from '../../../parameter-extractor/types'
|
||||
import type { IterationNodeType } from '../../../iteration/types'
|
||||
import type { LoopNodeType } from '../../../loop/types'
|
||||
import type { ListFilterNodeType } from '../../../list-operator/types'
|
||||
import { OUTPUT_FILE_SUB_VARIABLES } from '../../../constants'
|
||||
import type { CodeNodeType } from '../../../code/types'
|
||||
import type { DocExtractorNodeType } from '../../../document-extractor/types'
|
||||
import {
|
||||
BlockEnum,
|
||||
InputVarType,
|
||||
VarType,
|
||||
} from '@/app/components/workflow/types'
|
||||
import type { EndNodeType } from '../../../end/types'
|
||||
import type { HttpNodeType } from '../../../http/types'
|
||||
import type { IfElseNodeType } from '../../../if-else/types'
|
||||
import type { IterationNodeType } from '../../../iteration/types'
|
||||
import type { KnowledgeRetrievalNodeType } from '../../../knowledge-retrieval/types'
|
||||
import type { ListFilterNodeType } from '../../../list-operator/types'
|
||||
import type { LLMNodeType, StructuredOutput } from '../../../llm/types'
|
||||
import type { LoopNodeType } from '../../../loop/types'
|
||||
import type { ParameterExtractorNodeType } from '../../../parameter-extractor/types'
|
||||
import type { QuestionClassifierNodeType } from '../../../question-classifier/types'
|
||||
import type { TemplateTransformNodeType } from '../../../template-transform/types'
|
||||
import type { ToolNodeType } from '../../../tool/types'
|
||||
import type { DataSourceNodeType } from '@/app/components/workflow/nodes/data-source/types'
|
||||
import type { CaseItem, Condition } from '@/app/components/workflow/nodes/if-else/types'
|
||||
import type { Field as StructField } from '@/app/components/workflow/nodes/llm/types'
|
||||
import type { StartNodeType } from '@/app/components/workflow/nodes/start/types'
|
||||
import type { PluginTriggerNodeType } from '@/app/components/workflow/nodes/trigger-plugin/types'
|
||||
import type { WebhookTriggerNodeType } from '@/app/components/workflow/nodes/trigger-webhook/types'
|
||||
import type { VariableAssignerNodeType } from '@/app/components/workflow/nodes/variable-assigner/types'
|
||||
import type {
|
||||
ConversationVariable,
|
||||
EnvironmentVariable,
|
||||
@ -36,16 +30,15 @@ import type {
|
||||
ValueSelector,
|
||||
Var,
|
||||
} from '@/app/components/workflow/types'
|
||||
import type { VariableAssignerNodeType } from '@/app/components/workflow/nodes/variable-assigner/types'
|
||||
import type { Field as StructField } from '@/app/components/workflow/nodes/llm/types'
|
||||
import type { PromptItem } from '@/models/debug'
|
||||
import type { RAGPipelineVariable } from '@/models/pipeline'
|
||||
import type { WebhookTriggerNodeType } from '@/app/components/workflow/nodes/trigger-webhook/types'
|
||||
import type { PluginTriggerNodeType } from '@/app/components/workflow/nodes/trigger-plugin/types'
|
||||
import PluginTriggerNodeDefault from '@/app/components/workflow/nodes/trigger-plugin/default'
|
||||
import type { CaseItem, Condition } from '@/app/components/workflow/nodes/if-else/types'
|
||||
import type { SchemaTypeDefinition } from '@/service/use-common'
|
||||
import { produce } from 'immer'
|
||||
import { isArray, uniq } from 'lodash-es'
|
||||
import {
|
||||
AGENT_OUTPUT_STRUCT,
|
||||
FILE_STRUCT,
|
||||
getGlobalVars,
|
||||
HTTP_REQUEST_OUTPUT_STRUCT,
|
||||
KNOWLEDGE_RETRIEVAL_OUTPUT_STRUCT,
|
||||
LLM_OUTPUT_STRUCT,
|
||||
@ -54,23 +47,31 @@ import {
|
||||
SUPPORT_OUTPUT_VARS_NODE,
|
||||
TEMPLATE_TRANSFORM_OUTPUT_STRUCT,
|
||||
TOOL_OUTPUT_STRUCT,
|
||||
getGlobalVars,
|
||||
} from '@/app/components/workflow/constants'
|
||||
import ToolNodeDefault from '@/app/components/workflow/nodes/tool/default'
|
||||
import DataSourceNodeDefault from '@/app/components/workflow/nodes/data-source/default'
|
||||
import type { DataSourceNodeType } from '@/app/components/workflow/nodes/data-source/types'
|
||||
import type { PromptItem } from '@/models/debug'
|
||||
import ToolNodeDefault from '@/app/components/workflow/nodes/tool/default'
|
||||
import PluginTriggerNodeDefault from '@/app/components/workflow/nodes/trigger-plugin/default'
|
||||
import {
|
||||
BlockEnum,
|
||||
InputVarType,
|
||||
VarType,
|
||||
} from '@/app/components/workflow/types'
|
||||
import { VAR_REGEX } from '@/config'
|
||||
import type { AgentNodeType } from '../../../agent/types'
|
||||
import type { SchemaTypeDefinition } from '@/service/use-common'
|
||||
import { AppModeEnum } from '@/types/app'
|
||||
import { OUTPUT_FILE_SUB_VARIABLES } from '../../../constants'
|
||||
import {
|
||||
|
||||
Type,
|
||||
} from '../../../llm/types'
|
||||
import { VarType as ToolVarType } from '../../../tool/types'
|
||||
|
||||
export const isSystemVar = (valueSelector: ValueSelector) => {
|
||||
return valueSelector[0] === 'sys' || valueSelector[1] === 'sys'
|
||||
}
|
||||
|
||||
export const isGlobalVar = (valueSelector: ValueSelector) => {
|
||||
if (!isSystemVar(valueSelector)) return false
|
||||
if (!isSystemVar(valueSelector))
|
||||
return false
|
||||
const second = valueSelector[1]
|
||||
|
||||
if (['query', 'files'].includes(second))
|
||||
@ -87,7 +88,8 @@ export const isConversationVar = (valueSelector: ValueSelector) => {
|
||||
}
|
||||
|
||||
export const isRagVariableVar = (valueSelector: ValueSelector) => {
|
||||
if (!valueSelector) return false
|
||||
if (!valueSelector)
|
||||
return false
|
||||
return valueSelector[0] === 'rag'
|
||||
}
|
||||
|
||||
@ -247,8 +249,7 @@ const findExceptVarInObject = (
|
||||
isFile?: boolean,
|
||||
): Var => {
|
||||
const { children } = obj
|
||||
const isStructuredOutput = !!(children as StructuredOutput)?.schema
|
||||
?.properties
|
||||
const isStructuredOutput = !!(children as StructuredOutput)?.schema?.properties
|
||||
|
||||
let childrenResult: Var[] | StructuredOutput | undefined
|
||||
|
||||
@ -281,9 +282,12 @@ const findExceptVarInObject = (
|
||||
if (
|
||||
(item.type === VarType.object || item.type === VarType.file)
|
||||
&& itemChildren
|
||||
)
|
||||
) {
|
||||
passesFilter = itemHasValidChildren || filterVar(item, currSelector)
|
||||
else passesFilter = itemHasValidChildren
|
||||
}
|
||||
else {
|
||||
passesFilter = itemHasValidChildren
|
||||
}
|
||||
|
||||
return {
|
||||
item,
|
||||
@ -294,7 +298,8 @@ const findExceptVarInObject = (
|
||||
.filter(({ passesFilter }) => passesFilter)
|
||||
.map(({ item, filteredObj }) => {
|
||||
const { children: itemChildren } = item
|
||||
if (!itemChildren || !filteredObj) return item
|
||||
if (!itemChildren || !filteredObj)
|
||||
return item
|
||||
|
||||
return {
|
||||
...item,
|
||||
@ -415,11 +420,11 @@ const formatItem = (
|
||||
const { outputs } = data as CodeNodeType
|
||||
res.vars = outputs
|
||||
? Object.keys(outputs).map((key) => {
|
||||
return {
|
||||
variable: key,
|
||||
type: outputs[key].type,
|
||||
}
|
||||
})
|
||||
return {
|
||||
variable: key,
|
||||
type: outputs[key].type,
|
||||
}
|
||||
})
|
||||
: []
|
||||
break
|
||||
}
|
||||
@ -562,7 +567,8 @@ const formatItem = (
|
||||
}
|
||||
|
||||
case BlockEnum.ListFilter: {
|
||||
if (!(data as ListFilterNodeType).var_type) break
|
||||
if (!(data as ListFilterNodeType).var_type)
|
||||
break
|
||||
|
||||
res.vars = [
|
||||
{
|
||||
@ -690,12 +696,14 @@ const formatItem = (
|
||||
(() => {
|
||||
const variableArr = v.variable.split('.')
|
||||
const [first] = variableArr
|
||||
if (isSpecialVar(first)) return variableArr
|
||||
if (isSpecialVar(first))
|
||||
return variableArr
|
||||
|
||||
return [...selector, ...variableArr]
|
||||
})(),
|
||||
)
|
||||
if (isCurrentMatched) return true
|
||||
if (isCurrentMatched)
|
||||
return true
|
||||
|
||||
const isFile = v.type === VarType.file
|
||||
const children = (() => {
|
||||
@ -710,7 +718,8 @@ const formatItem = (
|
||||
}
|
||||
return v.children
|
||||
})()
|
||||
if (!children) return false
|
||||
if (!children)
|
||||
return false
|
||||
|
||||
const obj = findExceptVarInObject(
|
||||
isFile ? { ...v, children } : v,
|
||||
@ -737,7 +746,8 @@ const formatItem = (
|
||||
return v
|
||||
})()
|
||||
|
||||
if (!children) return v
|
||||
if (!children)
|
||||
return v
|
||||
|
||||
return findExceptVarInObject(
|
||||
isFile ? { ...v, children } : v,
|
||||
@ -813,14 +823,22 @@ export const toNodeOutputVars = (
|
||||
}
|
||||
// Sort nodes in reverse chronological order (most recent first)
|
||||
const sortedNodes = [...nodes].sort((a, b) => {
|
||||
if (a.data.type === BlockEnum.Start) return 1
|
||||
if (b.data.type === BlockEnum.Start) return -1
|
||||
if (a.data.type === 'env') return 1
|
||||
if (b.data.type === 'env') return -1
|
||||
if (a.data.type === 'conversation') return 1
|
||||
if (b.data.type === 'conversation') return -1
|
||||
if (a.data.type === 'global') return 1
|
||||
if (b.data.type === 'global') return -1
|
||||
if (a.data.type === BlockEnum.Start)
|
||||
return 1
|
||||
if (b.data.type === BlockEnum.Start)
|
||||
return -1
|
||||
if (a.data.type === 'env')
|
||||
return 1
|
||||
if (b.data.type === 'env')
|
||||
return -1
|
||||
if (a.data.type === 'conversation')
|
||||
return 1
|
||||
if (b.data.type === 'conversation')
|
||||
return -1
|
||||
if (a.data.type === 'global')
|
||||
return 1
|
||||
if (b.data.type === 'global')
|
||||
return -1
|
||||
// sort nodes by x position
|
||||
return (b.position?.x || 0) - (a.position?.x || 0)
|
||||
})
|
||||
@ -872,8 +890,8 @@ const getIterationItemType = ({
|
||||
valueSelector,
|
||||
beforeNodesOutputVars,
|
||||
}: {
|
||||
valueSelector: ValueSelector;
|
||||
beforeNodesOutputVars: NodeOutPutVar[];
|
||||
valueSelector: ValueSelector
|
||||
beforeNodesOutputVars: NodeOutPutVar[]
|
||||
}): VarType => {
|
||||
const outputVarNodeId = valueSelector[0]
|
||||
const isSystem = isSystemVar(valueSelector)
|
||||
@ -883,7 +901,8 @@ const getIterationItemType = ({
|
||||
? beforeNodesOutputVars.find(v => v.isStartNode)
|
||||
: beforeNodesOutputVars.find(v => v.nodeId === outputVarNodeId)
|
||||
|
||||
if (!targetVar) return VarType.string
|
||||
if (!targetVar)
|
||||
return VarType.string
|
||||
|
||||
let arrayType: VarType = VarType.string
|
||||
|
||||
@ -899,7 +918,8 @@ const getIterationItemType = ({
|
||||
const isLast = i === valueSelector.length - 1
|
||||
curr = Array.isArray(curr) ? curr.find(v => v.variable === key) : []
|
||||
|
||||
if (isLast) arrayType = curr?.type
|
||||
if (isLast)
|
||||
arrayType = curr?.type
|
||||
else if (curr?.type === VarType.object || curr?.type === VarType.file)
|
||||
curr = curr.children || []
|
||||
}
|
||||
@ -927,8 +947,8 @@ const getLoopItemType = ({
|
||||
valueSelector,
|
||||
beforeNodesOutputVars,
|
||||
}: {
|
||||
valueSelector: ValueSelector;
|
||||
beforeNodesOutputVars: NodeOutPutVar[];
|
||||
valueSelector: ValueSelector
|
||||
beforeNodesOutputVars: NodeOutPutVar[]
|
||||
}): VarType => {
|
||||
const outputVarNodeId = valueSelector[0]
|
||||
const isSystem = isSystemVar(valueSelector)
|
||||
@ -936,7 +956,8 @@ const getLoopItemType = ({
|
||||
const targetVar = isSystem
|
||||
? beforeNodesOutputVars.find(v => v.isStartNode)
|
||||
: beforeNodesOutputVars.find(v => v.nodeId === outputVarNodeId)
|
||||
if (!targetVar) return VarType.string
|
||||
if (!targetVar)
|
||||
return VarType.string
|
||||
|
||||
let arrayType: VarType = VarType.string
|
||||
|
||||
@ -993,21 +1014,22 @@ export const getVarType = ({
|
||||
schemaTypeDefinitions,
|
||||
preferSchemaType,
|
||||
}: {
|
||||
valueSelector: ValueSelector;
|
||||
parentNode?: Node | null;
|
||||
isIterationItem?: boolean;
|
||||
isLoopItem?: boolean;
|
||||
availableNodes: any[];
|
||||
isChatMode: boolean;
|
||||
isConstant?: boolean;
|
||||
environmentVariables?: EnvironmentVariable[];
|
||||
conversationVariables?: ConversationVariable[];
|
||||
ragVariables?: RAGPipelineVariable[];
|
||||
allPluginInfoList: Record<string, ToolWithProvider[]>;
|
||||
schemaTypeDefinitions?: SchemaTypeDefinition[];
|
||||
preferSchemaType?: boolean;
|
||||
valueSelector: ValueSelector
|
||||
parentNode?: Node | null
|
||||
isIterationItem?: boolean
|
||||
isLoopItem?: boolean
|
||||
availableNodes: any[]
|
||||
isChatMode: boolean
|
||||
isConstant?: boolean
|
||||
environmentVariables?: EnvironmentVariable[]
|
||||
conversationVariables?: ConversationVariable[]
|
||||
ragVariables?: RAGPipelineVariable[]
|
||||
allPluginInfoList: Record<string, ToolWithProvider[]>
|
||||
schemaTypeDefinitions?: SchemaTypeDefinition[]
|
||||
preferSchemaType?: boolean
|
||||
}): VarType => {
|
||||
if (isConstant) return VarType.string
|
||||
if (isConstant)
|
||||
return VarType.string
|
||||
|
||||
const beforeNodesOutputVars = toNodeOutputVars(
|
||||
availableNodes,
|
||||
@ -1035,7 +1057,8 @@ export const getVarType = ({
|
||||
})
|
||||
return itemType
|
||||
}
|
||||
if (valueSelector[1] === 'index') return VarType.number
|
||||
if (valueSelector[1] === 'index')
|
||||
return VarType.number
|
||||
}
|
||||
|
||||
const isLoopInnerVar = parentNode?.data.type === BlockEnum.Loop
|
||||
@ -1053,7 +1076,8 @@ export const getVarType = ({
|
||||
})
|
||||
return itemType
|
||||
}
|
||||
if (valueSelector[1] === 'index') return VarType.number
|
||||
if (valueSelector[1] === 'index')
|
||||
return VarType.number
|
||||
}
|
||||
|
||||
const isGlobal = isGlobalVar(valueSelector)
|
||||
@ -1070,16 +1094,20 @@ export const getVarType = ({
|
||||
})
|
||||
|
||||
const targetVarNodeId = (() => {
|
||||
if (isInStartNodeSysVar) return startNode?.id
|
||||
if (isGlobal) return 'global'
|
||||
if (isInNodeRagVariable) return valueSelector[1]
|
||||
if (isInStartNodeSysVar)
|
||||
return startNode?.id
|
||||
if (isGlobal)
|
||||
return 'global'
|
||||
if (isInNodeRagVariable)
|
||||
return valueSelector[1]
|
||||
return valueSelector[0]
|
||||
})()
|
||||
const targetVar = beforeNodesOutputVars.find(
|
||||
v => v.nodeId === targetVarNodeId,
|
||||
)
|
||||
|
||||
if (!targetVar) return VarType.string
|
||||
if (!targetVar)
|
||||
return VarType.string
|
||||
|
||||
let type: VarType = VarType.string
|
||||
let curr: any = targetVar.vars
|
||||
@ -1091,12 +1119,15 @@ export const getVarType = ({
|
||||
}
|
||||
else {
|
||||
const targetVar = curr.find((v: any) => {
|
||||
if (isInNodeRagVariable) return v.variable === valueSelector.join('.')
|
||||
if (isInNodeRagVariable)
|
||||
return v.variable === valueSelector.join('.')
|
||||
return v.variable === valueSelector[1]
|
||||
})
|
||||
if (!targetVar) return VarType.string
|
||||
if (!targetVar)
|
||||
return VarType.string
|
||||
|
||||
if (isInNodeRagVariable) return targetVar.type
|
||||
if (isInNodeRagVariable)
|
||||
return targetVar.type
|
||||
|
||||
const isStructuredOutputVar = !!targetVar.children?.schema?.properties
|
||||
if (isStructuredOutputVar) {
|
||||
@ -1109,10 +1140,12 @@ export const getVarType = ({
|
||||
let currProperties = targetVar.children.schema;
|
||||
(valueSelector as ValueSelector).slice(2).forEach((key, i) => {
|
||||
const isLast = i === valueSelector.length - 3
|
||||
if (!currProperties) return
|
||||
if (!currProperties)
|
||||
return
|
||||
|
||||
currProperties = currProperties.properties[key]
|
||||
if (isLast) type = structTypeToVarType(currProperties?.type)
|
||||
if (isLast)
|
||||
type = structTypeToVarType(currProperties?.type)
|
||||
})
|
||||
return type
|
||||
}
|
||||
@ -1148,20 +1181,20 @@ export const toNodeAvailableVars = ({
|
||||
allPluginInfoList,
|
||||
schemaTypeDefinitions,
|
||||
}: {
|
||||
parentNode?: Node | null;
|
||||
t?: any;
|
||||
parentNode?: Node | null
|
||||
t?: any
|
||||
// to get those nodes output vars
|
||||
beforeNodes: Node[];
|
||||
isChatMode: boolean;
|
||||
beforeNodes: Node[]
|
||||
isChatMode: boolean
|
||||
// env
|
||||
environmentVariables?: EnvironmentVariable[];
|
||||
environmentVariables?: EnvironmentVariable[]
|
||||
// chat var
|
||||
conversationVariables?: ConversationVariable[];
|
||||
conversationVariables?: ConversationVariable[]
|
||||
// rag variables
|
||||
ragVariables?: RAGPipelineVariable[];
|
||||
filterVar: (payload: Var, selector: ValueSelector) => boolean;
|
||||
allPluginInfoList: Record<string, ToolWithProvider[]>;
|
||||
schemaTypeDefinitions?: SchemaTypeDefinition[];
|
||||
ragVariables?: RAGPipelineVariable[]
|
||||
filterVar: (payload: Var, selector: ValueSelector) => boolean
|
||||
allPluginInfoList: Record<string, ToolWithProvider[]>
|
||||
schemaTypeDefinitions?: SchemaTypeDefinition[]
|
||||
}): NodeOutPutVar[] => {
|
||||
const beforeNodesOutputVars = toNodeOutputVars(
|
||||
beforeNodes,
|
||||
@ -1190,13 +1223,13 @@ export const toNodeAvailableVars = ({
|
||||
const itemChildren
|
||||
= itemType === VarType.file
|
||||
? {
|
||||
children: OUTPUT_FILE_SUB_VARIABLES.map((key) => {
|
||||
return {
|
||||
variable: key,
|
||||
type: key === 'size' ? VarType.number : VarType.string,
|
||||
}
|
||||
}),
|
||||
}
|
||||
children: OUTPUT_FILE_SUB_VARIABLES.map((key) => {
|
||||
return {
|
||||
variable: key,
|
||||
type: key === 'size' ? VarType.number : VarType.string,
|
||||
}
|
||||
}),
|
||||
}
|
||||
: {}
|
||||
const iterationVar = {
|
||||
nodeId: iterationNode?.id,
|
||||
@ -1216,24 +1249,28 @@ export const toNodeAvailableVars = ({
|
||||
const iterationIndex = beforeNodesOutputVars.findIndex(
|
||||
v => v.nodeId === iterationNode?.id,
|
||||
)
|
||||
if (iterationIndex > -1) beforeNodesOutputVars.splice(iterationIndex, 1)
|
||||
if (iterationIndex > -1)
|
||||
beforeNodesOutputVars.splice(iterationIndex, 1)
|
||||
beforeNodesOutputVars.unshift(iterationVar)
|
||||
}
|
||||
return beforeNodesOutputVars
|
||||
}
|
||||
|
||||
export const getNodeInfoById = (nodes: any, id: string) => {
|
||||
if (!isArray(nodes)) return
|
||||
if (!isArray(nodes))
|
||||
return
|
||||
return nodes.find((node: any) => node.id === id)
|
||||
}
|
||||
|
||||
const matchNotSystemVars = (prompts: string[]) => {
|
||||
if (!prompts) return []
|
||||
if (!prompts)
|
||||
return []
|
||||
|
||||
const allVars: string[] = []
|
||||
prompts.forEach((prompt) => {
|
||||
VAR_REGEX.lastIndex = 0
|
||||
if (typeof prompt !== 'string') return
|
||||
if (typeof prompt !== 'string')
|
||||
return
|
||||
allVars.push(...(prompt.match(VAR_REGEX) || []))
|
||||
})
|
||||
const uniqVars = uniq(allVars).map(v =>
|
||||
@ -1247,9 +1284,11 @@ const replaceOldVarInText = (
|
||||
oldVar: ValueSelector,
|
||||
newVar: ValueSelector,
|
||||
) => {
|
||||
if (!text || typeof text !== 'string') return text
|
||||
if (!text || typeof text !== 'string')
|
||||
return text
|
||||
|
||||
if (!newVar || newVar.length === 0) return text
|
||||
if (!newVar || newVar.length === 0)
|
||||
return text
|
||||
|
||||
return text.replaceAll(
|
||||
`{{#${oldVar.join('.')}#}}`,
|
||||
@ -1308,7 +1347,8 @@ export const getNodeUsedVars = (node: Node): ValueSelector[] => {
|
||||
.flatMap(c => c.conditions || [])
|
||||
.flatMap((c) => {
|
||||
const selectors: ValueSelector[] = []
|
||||
if (c.variable_selector) selectors.push(c.variable_selector)
|
||||
if (c.variable_selector)
|
||||
selectors.push(c.variable_selector)
|
||||
// Handle sub-variable conditions
|
||||
if (c.sub_variable_condition && c.sub_variable_condition.conditions) {
|
||||
selectors.push(
|
||||
@ -1391,7 +1431,7 @@ export const getNodeUsedVars = (node: Node): ValueSelector[] => {
|
||||
payload.datasource_parameters[key].type === ToolVarType.variable,
|
||||
)
|
||||
.map(key => payload.datasource_parameters[key].value as string)
|
||||
|| []
|
||||
|| []
|
||||
res = [...(mixVars as ValueSelector[]), ...(vars as any)]
|
||||
break
|
||||
}
|
||||
@ -1436,7 +1476,8 @@ export const getNodeUsedVars = (node: Node): ValueSelector[] => {
|
||||
case BlockEnum.Agent: {
|
||||
const payload = data as AgentNodeType
|
||||
const valueSelectors: ValueSelector[] = []
|
||||
if (!payload.agent_parameters) break
|
||||
if (!payload.agent_parameters)
|
||||
break
|
||||
|
||||
Object.keys(payload.agent_parameters || {}).forEach((key) => {
|
||||
const { value } = payload.agent_parameters![key]
|
||||
@ -1490,7 +1531,8 @@ export const getNodeUsedVarPassToServerKey = (
|
||||
return undefined
|
||||
}
|
||||
const targetVar = findConditionInCases((data as IfElseNodeType).cases || [])
|
||||
if (targetVar) res = `#${valueSelector.join('.')}#`
|
||||
if (targetVar)
|
||||
res = `#${valueSelector.join('.')}#`
|
||||
break
|
||||
}
|
||||
case BlockEnum.Code: {
|
||||
@ -1500,7 +1542,8 @@ export const getNodeUsedVarPassToServerKey = (
|
||||
&& v.value_selector
|
||||
&& v.value_selector.join('.') === valueSelector.join('.'),
|
||||
)
|
||||
if (targetVar) res = targetVar.variable
|
||||
if (targetVar)
|
||||
res = targetVar.variable
|
||||
break
|
||||
}
|
||||
case BlockEnum.TemplateTransform: {
|
||||
@ -1510,7 +1553,8 @@ export const getNodeUsedVarPassToServerKey = (
|
||||
&& v.value_selector
|
||||
&& v.value_selector.join('.') === valueSelector.join('.'),
|
||||
)
|
||||
if (targetVar) res = targetVar.variable
|
||||
if (targetVar)
|
||||
res = targetVar.variable
|
||||
break
|
||||
}
|
||||
case BlockEnum.QuestionClassifier: {
|
||||
@ -1552,7 +1596,8 @@ export const findUsedVarNodes = (
|
||||
const res: Node[] = []
|
||||
availableNodes.forEach((node) => {
|
||||
const vars = getNodeUsedVars(node)
|
||||
if (vars.find(v => v.join('.') === varSelector.join('.'))) res.push(node)
|
||||
if (vars.find(v => v.join('.') === varSelector.join('.')))
|
||||
res.push(node)
|
||||
})
|
||||
return res
|
||||
}
|
||||
@ -1626,8 +1671,9 @@ export const updateNodeVars = (
|
||||
if (
|
||||
payload.context?.variable_selector?.join('.')
|
||||
=== oldVarSelector.join('.')
|
||||
)
|
||||
) {
|
||||
payload.context.variable_selector = newVarSelector
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
@ -1661,8 +1707,9 @@ export const updateNodeVars = (
|
||||
if (
|
||||
subC.variable_selector?.join('.')
|
||||
=== oldVarSelector.join('.')
|
||||
)
|
||||
) {
|
||||
subC.variable_selector = newVarSelector
|
||||
}
|
||||
return subC
|
||||
})
|
||||
}
|
||||
@ -1820,7 +1867,8 @@ export const updateNodeVars = (
|
||||
const payload = data as VariableAssignerNodeType
|
||||
if (payload.variables) {
|
||||
payload.variables = payload.variables.map((v) => {
|
||||
if (v.join('.') === oldVarSelector.join('.')) v = newVarSelector
|
||||
if (v.join('.') === oldVarSelector.join('.'))
|
||||
v = newVarSelector
|
||||
return v
|
||||
})
|
||||
}
|
||||
@ -1831,7 +1879,8 @@ export const updateNodeVars = (
|
||||
const payload = data as VariableAssignerNodeType
|
||||
if (payload.variables) {
|
||||
payload.variables = payload.variables.map((v) => {
|
||||
if (v.join('.') === oldVarSelector.join('.')) v = newVarSelector
|
||||
if (v.join('.') === oldVarSelector.join('.'))
|
||||
v = newVarSelector
|
||||
return v
|
||||
})
|
||||
}
|
||||
@ -1882,11 +1931,11 @@ const varToValueSelectorList = (
|
||||
parentValueSelector: ValueSelector,
|
||||
res: ValueSelector[],
|
||||
) => {
|
||||
if (!v.variable) return
|
||||
if (!v.variable)
|
||||
return
|
||||
|
||||
res.push([...parentValueSelector, v.variable])
|
||||
const isStructuredOutput = !!(v.children as StructuredOutput)?.schema
|
||||
?.properties
|
||||
const isStructuredOutput = !!(v.children as StructuredOutput)?.schema?.properties
|
||||
|
||||
if ((v.children as Var[])?.length > 0) {
|
||||
(v.children as Var[]).forEach((child) => {
|
||||
@ -1897,8 +1946,7 @@ const varToValueSelectorList = (
|
||||
Object.keys(
|
||||
(v.children as StructuredOutput)?.schema?.properties || {},
|
||||
).forEach((key) => {
|
||||
const type = (v.children as StructuredOutput)?.schema?.properties[key]
|
||||
.type
|
||||
const type = (v.children as StructuredOutput)?.schema?.properties[key].type
|
||||
const isArray = type === Type.array
|
||||
const arrayType = (v.children as StructuredOutput)?.schema?.properties[
|
||||
key
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
'use client'
|
||||
import type { FC } from 'react'
|
||||
import React from 'react'
|
||||
import type { Field, StructuredOutput, TypeWithArray } from '../../../llm/types'
|
||||
import { Type } from '../../../llm/types'
|
||||
import { PickerPanelMain as Panel } from '@/app/components/workflow/nodes/_base/components/variable/object-child-tree-panel/picker'
|
||||
import React from 'react'
|
||||
import BlockIcon from '@/app/components/workflow/block-icon'
|
||||
import { PickerPanelMain as Panel } from '@/app/components/workflow/nodes/_base/components/variable/object-child-tree-panel/picker'
|
||||
import { BlockEnum } from '@/app/components/workflow/types'
|
||||
import { Type } from '../../../llm/types'
|
||||
|
||||
type Props = {
|
||||
nodeName: string
|
||||
@ -35,20 +35,20 @@ const VarFullPathPanel: FC<Props> = ({
|
||||
type: isLast ? varType : Type.object,
|
||||
properties: {},
|
||||
} as Field
|
||||
current = current.properties[name] as { type: Type.object; properties: { [key: string]: Field; }; required: never[]; additionalProperties: false; }
|
||||
current = current.properties[name] as { type: Type.object, properties: { [key: string]: Field }, required: never[], additionalProperties: false }
|
||||
}
|
||||
return {
|
||||
schema,
|
||||
}
|
||||
})()
|
||||
return (
|
||||
<div className='w-[280px] rounded-xl border-[0.5px] border-components-panel-border bg-components-panel-bg-blur pb-0 shadow-lg backdrop-blur-[5px]'>
|
||||
<div className='flex space-x-1 border-b-[0.5px] border-divider-subtle p-3 pb-2 '>
|
||||
<BlockIcon size='xs' type={nodeType} />
|
||||
<div className='system-xs-medium w-0 grow truncate text-text-secondary'>{nodeName}</div>
|
||||
<div className="w-[280px] rounded-xl border-[0.5px] border-components-panel-border bg-components-panel-bg-blur pb-0 shadow-lg backdrop-blur-[5px]">
|
||||
<div className="flex space-x-1 border-b-[0.5px] border-divider-subtle p-3 pb-2 ">
|
||||
<BlockIcon size="xs" type={nodeType} />
|
||||
<div className="system-xs-medium w-0 grow truncate text-text-secondary">{nodeName}</div>
|
||||
</div>
|
||||
<Panel
|
||||
className='px-1 pb-3 pt-2'
|
||||
className="px-1 pb-3 pt-2"
|
||||
root={{ attrName: path[0] }}
|
||||
payload={schema}
|
||||
readonly
|
||||
|
||||
@ -1,21 +1,21 @@
|
||||
'use client'
|
||||
import type { FC } from 'react'
|
||||
import type { ToastHandle } from '@/app/components/base/toast'
|
||||
import type { ValueSelector, Var, Variable } from '@/app/components/workflow/types'
|
||||
import { RiDraggable } from '@remixicon/react'
|
||||
import { useDebounceFn } from 'ahooks'
|
||||
import { produce } from 'immer'
|
||||
import React, { useCallback, useMemo, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { produce } from 'immer'
|
||||
import RemoveButton from '../remove-button'
|
||||
import VarReferencePicker from './var-reference-picker'
|
||||
import Input from '@/app/components/base/input'
|
||||
import type { ValueSelector, Var, Variable } from '@/app/components/workflow/types'
|
||||
import { VarType as VarKindType } from '@/app/components/workflow/nodes/tool/types'
|
||||
import { checkKeys, replaceSpaceWithUnderscoreInVarNameInput } from '@/utils/var'
|
||||
import type { ToastHandle } from '@/app/components/base/toast'
|
||||
import Toast from '@/app/components/base/toast'
|
||||
import { ReactSortable } from 'react-sortablejs'
|
||||
import { v4 as uuid4 } from 'uuid'
|
||||
import { RiDraggable } from '@remixicon/react'
|
||||
import Input from '@/app/components/base/input'
|
||||
import Toast from '@/app/components/base/toast'
|
||||
import { VarType as VarKindType } from '@/app/components/workflow/nodes/tool/types'
|
||||
import { cn } from '@/utils/classnames'
|
||||
import { useDebounceFn } from 'ahooks'
|
||||
import { checkKeys, replaceSpaceWithUnderscoreInVarNameInput } from '@/utils/var'
|
||||
import RemoveButton from '../remove-button'
|
||||
import VarReferencePicker from './var-reference-picker'
|
||||
|
||||
type Props = {
|
||||
nodeId: string
|
||||
@ -131,11 +131,11 @@ const VarList: FC<Props> = ({
|
||||
|
||||
return (
|
||||
<ReactSortable
|
||||
className='space-y-2'
|
||||
className="space-y-2"
|
||||
list={listWithIds}
|
||||
setList={(list) => { onChange(list.map(item => item.variable)) }}
|
||||
handle='.handle'
|
||||
ghostClass='opacity-50'
|
||||
handle=".handle"
|
||||
ghostClass="opacity-50"
|
||||
animation={150}
|
||||
>
|
||||
{list.map((variable, index) => {
|
||||
@ -147,7 +147,7 @@ const VarList: FC<Props> = ({
|
||||
return (
|
||||
<div className={cn('flex items-center space-x-1', 'group relative')} key={index}>
|
||||
<Input
|
||||
wrapperClassName='w-[120px]'
|
||||
wrapperClassName="w-[120px]"
|
||||
disabled={readonly}
|
||||
value={variable.variable}
|
||||
onChange={handleVarNameChange(index)}
|
||||
@ -157,7 +157,7 @@ const VarList: FC<Props> = ({
|
||||
nodeId={nodeId}
|
||||
readonly={readonly}
|
||||
isShowNodeName
|
||||
className='grow'
|
||||
className="grow"
|
||||
value={variable.variable_type === VarKindType.constant ? (variable.value || '') : (variable.value_selector || [])}
|
||||
isSupportConstantValue={isSupportConstantValue}
|
||||
onChange={handleVarReferenceChange(index)}
|
||||
@ -167,12 +167,15 @@ const VarList: FC<Props> = ({
|
||||
isSupportFileVar={isSupportFileVar}
|
||||
/>
|
||||
{!readonly && (
|
||||
<RemoveButton onClick={handleVarRemove(index)}/>
|
||||
<RemoveButton onClick={handleVarRemove(index)} />
|
||||
)}
|
||||
{canDrag && (
|
||||
<RiDraggable className={cn(
|
||||
'handle absolute -left-4 top-2.5 hidden h-3 w-3 cursor-pointer text-text-quaternary',
|
||||
'group-hover:block',
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
{canDrag && <RiDraggable className={cn(
|
||||
'handle absolute -left-4 top-2.5 hidden h-3 w-3 cursor-pointer text-text-quaternary',
|
||||
'group-hover:block',
|
||||
)} />}
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
|
||||
@ -1,7 +1,9 @@
|
||||
'use client'
|
||||
import type { FC } from 'react'
|
||||
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import type { CredentialFormSchema, CredentialFormSchemaSelect, FormOption } from '@/app/components/header/account-setting/model-provider-page/declarations'
|
||||
import type { Tool } from '@/app/components/tools/types'
|
||||
import type { TriggerWithProvider } from '@/app/components/workflow/block-selector/types'
|
||||
import type { CommonNodeType, Node, NodeOutPutVar, ToolWithProvider, ValueSelector, Var } from '@/app/components/workflow/types'
|
||||
import {
|
||||
RiArrowDownSLine,
|
||||
RiCloseLine,
|
||||
@ -10,23 +12,16 @@ import {
|
||||
RiMoreLine,
|
||||
} from '@remixicon/react'
|
||||
import { produce } from 'immer'
|
||||
import { noop } from 'lodash-es'
|
||||
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import {
|
||||
useNodes,
|
||||
useReactFlow,
|
||||
useStoreApi,
|
||||
} from 'reactflow'
|
||||
import RemoveButton from '../remove-button'
|
||||
import useAvailableVarList from '../../hooks/use-available-var-list'
|
||||
import VarReferencePopup from './var-reference-popup'
|
||||
import { getNodeInfoById, isConversationVar, isENV, isGlobalVar, isRagVariableVar, isSystemVar, removeFileVars, varTypeToStructType } from './utils'
|
||||
import ConstantField from './constant-field'
|
||||
import { cn } from '@/utils/classnames'
|
||||
import type { CommonNodeType, Node, NodeOutPutVar, ToolWithProvider, ValueSelector, Var } from '@/app/components/workflow/types'
|
||||
import type { TriggerWithProvider } from '@/app/components/workflow/block-selector/types'
|
||||
import type { CredentialFormSchemaSelect } from '@/app/components/header/account-setting/model-provider-page/declarations'
|
||||
import { type CredentialFormSchema, type FormOption, FormTypeEnum } from '@/app/components/header/account-setting/model-provider-page/declarations'
|
||||
import { BlockEnum } from '@/app/components/workflow/types'
|
||||
import { VarBlockIcon } from '@/app/components/workflow/block-icon'
|
||||
import Badge from '@/app/components/base/badge'
|
||||
import AddButton from '@/app/components/base/button/add-button'
|
||||
import { Line3 } from '@/app/components/base/icons/src/public/common'
|
||||
import { Variable02 } from '@/app/components/base/icons/src/vender/solid/development'
|
||||
import {
|
||||
@ -34,23 +29,28 @@ import {
|
||||
PortalToFollowElemContent,
|
||||
PortalToFollowElemTrigger,
|
||||
} from '@/app/components/base/portal-to-follow-elem'
|
||||
import Tooltip from '@/app/components/base/tooltip'
|
||||
import { FormTypeEnum } from '@/app/components/header/account-setting/model-provider-page/declarations'
|
||||
import { VarBlockIcon } from '@/app/components/workflow/block-icon'
|
||||
import { VAR_SHOW_NAME_MAP } from '@/app/components/workflow/constants'
|
||||
import {
|
||||
useIsChatMode,
|
||||
useWorkflowVariables,
|
||||
} from '@/app/components/workflow/hooks'
|
||||
import { VarType as VarKindType } from '@/app/components/workflow/nodes/tool/types'
|
||||
// import type { BaseResource, BaseResourceProvider } from '@/app/components/workflow/nodes/_base/types'
|
||||
import TypeSelector from '@/app/components/workflow/nodes/_base/components/selector'
|
||||
import AddButton from '@/app/components/base/button/add-button'
|
||||
import Badge from '@/app/components/base/badge'
|
||||
import Tooltip from '@/app/components/base/tooltip'
|
||||
import { isExceptionVariable } from '@/app/components/workflow/utils'
|
||||
import VarFullPathPanel from './var-full-path-panel'
|
||||
import { noop } from 'lodash-es'
|
||||
import type { Tool } from '@/app/components/tools/types'
|
||||
import { useFetchDynamicOptions } from '@/service/use-plugins'
|
||||
import { VariableIconWithColor } from '@/app/components/workflow/nodes/_base/components/variable/variable-label'
|
||||
import { VAR_SHOW_NAME_MAP } from '@/app/components/workflow/constants'
|
||||
import { VarType as VarKindType } from '@/app/components/workflow/nodes/tool/types'
|
||||
import { BlockEnum } from '@/app/components/workflow/types'
|
||||
import { isExceptionVariable } from '@/app/components/workflow/utils'
|
||||
import { useFetchDynamicOptions } from '@/service/use-plugins'
|
||||
import { cn } from '@/utils/classnames'
|
||||
import useAvailableVarList from '../../hooks/use-available-var-list'
|
||||
import RemoveButton from '../remove-button'
|
||||
import ConstantField from './constant-field'
|
||||
import { getNodeInfoById, isConversationVar, isENV, isGlobalVar, isRagVariableVar, isSystemVar, removeFileVars, varTypeToStructType } from './utils'
|
||||
import VarFullPathPanel from './var-full-path-panel'
|
||||
import VarReferencePopup from './var-reference-popup'
|
||||
|
||||
const TRIGGER_DEFAULT_WIDTH = 227
|
||||
|
||||
@ -207,7 +207,7 @@ const VarReferencePicker: FC<Props> = ({
|
||||
if (!hasValue)
|
||||
return ''
|
||||
const showName = VAR_SHOW_NAME_MAP[(value as ValueSelector).join('.')]
|
||||
if(showName)
|
||||
if (showName)
|
||||
return showName
|
||||
|
||||
const isSystem = isSystemVar(value as ValueSelector)
|
||||
@ -336,7 +336,8 @@ const VarReferencePicker: FC<Props> = ({
|
||||
path={(value as ValueSelector).slice(1)}
|
||||
varType={varTypeToStructType(type)}
|
||||
nodeType={outputVarNode?.type}
|
||||
/>)
|
||||
/>
|
||||
)
|
||||
}
|
||||
if (!isValidVar && hasValue)
|
||||
return t('workflow.errorMsg.invalidVariable')
|
||||
@ -347,7 +348,10 @@ const VarReferencePicker: FC<Props> = ({
|
||||
const [dynamicOptions, setDynamicOptions] = useState<FormOption[] | null>(null)
|
||||
const [isLoading, setIsLoading] = useState(false)
|
||||
const { mutateAsync: fetchDynamicOptions } = useFetchDynamicOptions(
|
||||
currentProvider?.plugin_id || '', currentProvider?.name || '', currentTool?.name || '', (schema as CredentialFormSchemaSelect)?.variable || '',
|
||||
currentProvider?.plugin_id || '',
|
||||
currentProvider?.name || '',
|
||||
currentTool?.name || '',
|
||||
(schema as CredentialFormSchemaSelect)?.variable || '',
|
||||
'tool',
|
||||
)
|
||||
const handleFetchDynamicOptions = async () => {
|
||||
@ -398,11 +402,16 @@ const VarReferencePicker: FC<Props> = ({
|
||||
}, [schema, dynamicOptions, isLoading, value])
|
||||
|
||||
const variableCategory = useMemo(() => {
|
||||
if (isEnv) return 'environment'
|
||||
if (isChatVar) return 'conversation'
|
||||
if (isGlobal) return 'global'
|
||||
if (isLoopVar) return 'loop'
|
||||
if (isRagVar) return 'rag'
|
||||
if (isEnv)
|
||||
return 'environment'
|
||||
if (isChatVar)
|
||||
return 'conversation'
|
||||
if (isGlobal)
|
||||
return 'global'
|
||||
if (isLoopVar)
|
||||
return 'loop'
|
||||
if (isRagVar)
|
||||
return 'rag'
|
||||
return 'system'
|
||||
}, [isEnv, isChatVar, isGlobal, isLoopVar, isRagVar])
|
||||
|
||||
@ -413,166 +422,210 @@ const VarReferencePicker: FC<Props> = ({
|
||||
onOpenChange={setOpen}
|
||||
placement={isAddBtnTrigger ? 'bottom-end' : 'bottom-start'}
|
||||
>
|
||||
<WrapElem onClick={() => {
|
||||
if (readonly)
|
||||
return
|
||||
if (!isConstant)
|
||||
setOpen(!open)
|
||||
else
|
||||
setControlFocus(Date.now())
|
||||
}} className='group/picker-trigger-wrap relative !flex'>
|
||||
<WrapElem
|
||||
onClick={() => {
|
||||
if (readonly)
|
||||
return
|
||||
if (!isConstant)
|
||||
setOpen(!open)
|
||||
else
|
||||
setControlFocus(Date.now())
|
||||
}}
|
||||
className="group/picker-trigger-wrap relative !flex"
|
||||
>
|
||||
<>
|
||||
{isAddBtnTrigger
|
||||
? (
|
||||
<div>
|
||||
<AddButton onClick={noop}></AddButton>
|
||||
</div>
|
||||
)
|
||||
: (<div ref={!isSupportConstantValue ? triggerRef : null} className={cn((open || isFocus) ? 'border-gray-300' : 'border-gray-100', 'group/wrap relative flex h-8 w-full items-center', !isSupportConstantValue && 'rounded-lg bg-components-input-bg-normal p-1', isInTable && 'border-none bg-transparent', readonly && 'bg-components-input-bg-disabled')}>
|
||||
{isSupportConstantValue
|
||||
? <div onClick={(e) => {
|
||||
e.stopPropagation()
|
||||
setOpen(false)
|
||||
setControlFocus(Date.now())
|
||||
}} className='mr-1 flex h-full items-center space-x-1'>
|
||||
<TypeSelector
|
||||
noLeft
|
||||
trigger={
|
||||
<div className='radius-md flex h-8 items-center bg-components-input-bg-normal px-2'>
|
||||
<div className='system-sm-regular mr-1 text-components-input-text-filled'>{varKindTypes.find(item => item.value === varKindType)?.label}</div>
|
||||
<RiArrowDownSLine className='h-4 w-4 text-text-quaternary' />
|
||||
</div>
|
||||
}
|
||||
popupClassName='top-8'
|
||||
readonly={readonly}
|
||||
value={varKindType}
|
||||
options={varKindTypes}
|
||||
onChange={handleVarKindTypeChange}
|
||||
showChecked
|
||||
/>
|
||||
<div>
|
||||
<AddButton onClick={noop}></AddButton>
|
||||
</div>
|
||||
: (!hasValue && <div className='ml-1.5 mr-1'>
|
||||
<Variable02 className={`h-4 w-4 ${readonly ? 'text-components-input-text-disabled' : 'text-components-input-text-placeholder'}`} />
|
||||
</div>)}
|
||||
{isConstant
|
||||
? (
|
||||
<ConstantField
|
||||
value={value as string}
|
||||
onChange={onChange as ((value: string | number, varKindType: VarKindType, varInfo?: Var) => void)}
|
||||
schema={schemaWithDynamicSelect as CredentialFormSchema}
|
||||
readonly={readonly}
|
||||
isLoading={isLoading}
|
||||
/>
|
||||
)
|
||||
: (
|
||||
<VarPickerWrap
|
||||
onClick={() => {
|
||||
if (readonly)
|
||||
return
|
||||
if (!isConstant)
|
||||
setOpen(!open)
|
||||
else
|
||||
setControlFocus(Date.now())
|
||||
}}
|
||||
className='h-full grow'
|
||||
>
|
||||
<div ref={isSupportConstantValue ? triggerRef : null} className={cn('h-full', isSupportConstantValue && 'flex items-center rounded-lg bg-components-panel-bg py-1 pl-1')}>
|
||||
<Tooltip noDecoration={isShowAPart} popupContent={tooltipPopup}>
|
||||
<div className={cn('h-full items-center rounded-[5px] px-1.5', hasValue ? 'inline-flex bg-components-badge-white-to-dark' : 'flex')}>
|
||||
{hasValue
|
||||
? (
|
||||
<>
|
||||
{isShowNodeName && !isEnv && !isChatVar && !isGlobal && !isRagVar && (
|
||||
<div className='flex items-center' onClick={(e) => {
|
||||
if (e.metaKey || e.ctrlKey) {
|
||||
e.stopPropagation()
|
||||
handleVariableJump(outputVarNode?.id)
|
||||
}
|
||||
}}>
|
||||
<div className='h-3 px-[1px]'>
|
||||
{outputVarNode?.type && <VarBlockIcon
|
||||
className='!text-text-primary'
|
||||
type={outputVarNode.type}
|
||||
/>}
|
||||
</div>
|
||||
<div className='mx-0.5 truncate text-xs font-medium text-text-secondary' title={outputVarNode?.title} style={{
|
||||
maxWidth: maxNodeNameWidth,
|
||||
}}>{outputVarNode?.title}</div>
|
||||
<Line3 className='mr-0.5'></Line3>
|
||||
</div>
|
||||
)}
|
||||
{isShowAPart && (
|
||||
<div className='flex items-center'>
|
||||
<RiMoreLine className='h-3 w-3 text-text-secondary' />
|
||||
<Line3 className='mr-0.5 text-divider-deep'></Line3>
|
||||
</div>
|
||||
)}
|
||||
<div className='flex items-center text-text-accent'>
|
||||
{isLoading && <RiLoader4Line className='h-3.5 w-3.5 animate-spin text-text-secondary' />}
|
||||
<VariableIconWithColor
|
||||
variables={value as ValueSelector}
|
||||
variableCategory={variableCategory}
|
||||
isExceptionVariable={isException}
|
||||
/>
|
||||
<div className={cn('ml-0.5 truncate text-xs font-medium', isEnv && '!text-text-secondary', isChatVar && 'text-util-colors-teal-teal-700', isException && 'text-text-warning', isGlobal && 'text-util-colors-orange-orange-600')} title={varName} style={{
|
||||
maxWidth: maxVarNameWidth,
|
||||
}}>{varName}</div>
|
||||
</div>
|
||||
<div className='system-xs-regular ml-0.5 truncate text-center capitalize text-text-tertiary' title={type} style={{
|
||||
maxWidth: maxTypeWidth,
|
||||
}}>{type}</div>
|
||||
{!isValidVar && <RiErrorWarningFill className='ml-0.5 h-3 w-3 text-text-destructive' />}
|
||||
</>
|
||||
)
|
||||
: <div className={`overflow-hidden ${readonly ? 'text-components-input-text-disabled' : 'text-components-input-text-placeholder'} system-sm-regular text-ellipsis`}>
|
||||
{isLoading ? (
|
||||
<div className='flex items-center'>
|
||||
<RiLoader4Line className='mr-1 h-3.5 w-3.5 animate-spin text-text-secondary' />
|
||||
<span>{placeholder ?? t('workflow.common.setVarValuePlaceholder')}</span>
|
||||
</div>
|
||||
) : (
|
||||
placeholder ?? t('workflow.common.setVarValuePlaceholder')
|
||||
)}
|
||||
</div>}
|
||||
)
|
||||
: (
|
||||
<div ref={!isSupportConstantValue ? triggerRef : null} className={cn((open || isFocus) ? 'border-gray-300' : 'border-gray-100', 'group/wrap relative flex h-8 w-full items-center', !isSupportConstantValue && 'rounded-lg bg-components-input-bg-normal p-1', isInTable && 'border-none bg-transparent', readonly && 'bg-components-input-bg-disabled')}>
|
||||
{isSupportConstantValue
|
||||
? (
|
||||
<div
|
||||
onClick={(e) => {
|
||||
e.stopPropagation()
|
||||
setOpen(false)
|
||||
setControlFocus(Date.now())
|
||||
}}
|
||||
className="mr-1 flex h-full items-center space-x-1"
|
||||
>
|
||||
<TypeSelector
|
||||
noLeft
|
||||
trigger={(
|
||||
<div className="radius-md flex h-8 items-center bg-components-input-bg-normal px-2">
|
||||
<div className="system-sm-regular mr-1 text-components-input-text-filled">{varKindTypes.find(item => item.value === varKindType)?.label}</div>
|
||||
<RiArrowDownSLine className="h-4 w-4 text-text-quaternary" />
|
||||
</div>
|
||||
)}
|
||||
popupClassName="top-8"
|
||||
readonly={readonly}
|
||||
value={varKindType}
|
||||
options={varKindTypes}
|
||||
onChange={handleVarKindTypeChange}
|
||||
showChecked
|
||||
/>
|
||||
</div>
|
||||
</Tooltip>
|
||||
</div>
|
||||
)
|
||||
: (!hasValue && (
|
||||
<div className="ml-1.5 mr-1">
|
||||
<Variable02 className={`h-4 w-4 ${readonly ? 'text-components-input-text-disabled' : 'text-components-input-text-placeholder'}`} />
|
||||
</div>
|
||||
))}
|
||||
{isConstant
|
||||
? (
|
||||
<ConstantField
|
||||
value={value as string}
|
||||
onChange={onChange as ((value: string | number, varKindType: VarKindType, varInfo?: Var) => void)}
|
||||
schema={schemaWithDynamicSelect as CredentialFormSchema}
|
||||
readonly={readonly}
|
||||
isLoading={isLoading}
|
||||
/>
|
||||
)
|
||||
: (
|
||||
<VarPickerWrap
|
||||
onClick={() => {
|
||||
if (readonly)
|
||||
return
|
||||
if (!isConstant)
|
||||
setOpen(!open)
|
||||
else
|
||||
setControlFocus(Date.now())
|
||||
}}
|
||||
className="h-full grow"
|
||||
>
|
||||
<div ref={isSupportConstantValue ? triggerRef : null} className={cn('h-full', isSupportConstantValue && 'flex items-center rounded-lg bg-components-panel-bg py-1 pl-1')}>
|
||||
<Tooltip noDecoration={isShowAPart} popupContent={tooltipPopup}>
|
||||
<div className={cn('h-full items-center rounded-[5px] px-1.5', hasValue ? 'inline-flex bg-components-badge-white-to-dark' : 'flex')}>
|
||||
{hasValue
|
||||
? (
|
||||
<>
|
||||
{isShowNodeName && !isEnv && !isChatVar && !isGlobal && !isRagVar && (
|
||||
<div
|
||||
className="flex items-center"
|
||||
onClick={(e) => {
|
||||
if (e.metaKey || e.ctrlKey) {
|
||||
e.stopPropagation()
|
||||
handleVariableJump(outputVarNode?.id)
|
||||
}
|
||||
}}
|
||||
>
|
||||
<div className="h-3 px-[1px]">
|
||||
{outputVarNode?.type && (
|
||||
<VarBlockIcon
|
||||
className="!text-text-primary"
|
||||
type={outputVarNode.type}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<div
|
||||
className="mx-0.5 truncate text-xs font-medium text-text-secondary"
|
||||
title={outputVarNode?.title}
|
||||
style={{
|
||||
maxWidth: maxNodeNameWidth,
|
||||
}}
|
||||
>
|
||||
{outputVarNode?.title}
|
||||
</div>
|
||||
<Line3 className="mr-0.5"></Line3>
|
||||
</div>
|
||||
)}
|
||||
{isShowAPart && (
|
||||
<div className="flex items-center">
|
||||
<RiMoreLine className="h-3 w-3 text-text-secondary" />
|
||||
<Line3 className="mr-0.5 text-divider-deep"></Line3>
|
||||
</div>
|
||||
)}
|
||||
<div className="flex items-center text-text-accent">
|
||||
{isLoading && <RiLoader4Line className="h-3.5 w-3.5 animate-spin text-text-secondary" />}
|
||||
<VariableIconWithColor
|
||||
variables={value as ValueSelector}
|
||||
variableCategory={variableCategory}
|
||||
isExceptionVariable={isException}
|
||||
/>
|
||||
<div
|
||||
className={cn('ml-0.5 truncate text-xs font-medium', isEnv && '!text-text-secondary', isChatVar && 'text-util-colors-teal-teal-700', isException && 'text-text-warning', isGlobal && 'text-util-colors-orange-orange-600')}
|
||||
title={varName}
|
||||
style={{
|
||||
maxWidth: maxVarNameWidth,
|
||||
}}
|
||||
>
|
||||
{varName}
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className="system-xs-regular ml-0.5 truncate text-center capitalize text-text-tertiary"
|
||||
title={type}
|
||||
style={{
|
||||
maxWidth: maxTypeWidth,
|
||||
}}
|
||||
>
|
||||
{type}
|
||||
</div>
|
||||
{!isValidVar && <RiErrorWarningFill className="ml-0.5 h-3 w-3 text-text-destructive" />}
|
||||
</>
|
||||
)
|
||||
: (
|
||||
<div className={`overflow-hidden ${readonly ? 'text-components-input-text-disabled' : 'text-components-input-text-placeholder'} system-sm-regular text-ellipsis`}>
|
||||
{isLoading
|
||||
? (
|
||||
<div className="flex items-center">
|
||||
<RiLoader4Line className="mr-1 h-3.5 w-3.5 animate-spin text-text-secondary" />
|
||||
<span>{placeholder ?? t('workflow.common.setVarValuePlaceholder')}</span>
|
||||
</div>
|
||||
)
|
||||
: (
|
||||
placeholder ?? t('workflow.common.setVarValuePlaceholder')
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</Tooltip>
|
||||
</div>
|
||||
|
||||
</VarPickerWrap>
|
||||
)}
|
||||
{(hasValue && !readonly && !isInTable) && (<div
|
||||
className='group invisible absolute right-1 top-[50%] h-5 translate-y-[-50%] cursor-pointer rounded-md p-1 hover:bg-state-base-hover group-hover/wrap:visible'
|
||||
onClick={handleClearVar}
|
||||
>
|
||||
<RiCloseLine className='h-3.5 w-3.5 text-text-tertiary group-hover:text-text-secondary' />
|
||||
</div>)}
|
||||
{!hasValue && valueTypePlaceHolder && (
|
||||
<Badge
|
||||
className=' absolute right-1 top-[50%] translate-y-[-50%] capitalize'
|
||||
text={valueTypePlaceHolder}
|
||||
uppercase={false}
|
||||
/>
|
||||
</VarPickerWrap>
|
||||
)}
|
||||
{(hasValue && !readonly && !isInTable) && (
|
||||
<div
|
||||
className="group invisible absolute right-1 top-[50%] h-5 translate-y-[-50%] cursor-pointer rounded-md p-1 hover:bg-state-base-hover group-hover/wrap:visible"
|
||||
onClick={handleClearVar}
|
||||
>
|
||||
<RiCloseLine className="h-3.5 w-3.5 text-text-tertiary group-hover:text-text-secondary" />
|
||||
</div>
|
||||
)}
|
||||
{!hasValue && valueTypePlaceHolder && (
|
||||
<Badge
|
||||
className=" absolute right-1 top-[50%] translate-y-[-50%] capitalize"
|
||||
text={valueTypePlaceHolder}
|
||||
uppercase={false}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>)}
|
||||
{!readonly && isInTable && (
|
||||
<RemoveButton
|
||||
className='absolute right-1 top-0.5 hidden group-hover/picker-trigger-wrap:block'
|
||||
className="absolute right-1 top-0.5 hidden group-hover/picker-trigger-wrap:block"
|
||||
onClick={() => onRemove?.()}
|
||||
/>
|
||||
)}
|
||||
|
||||
{!hasValue && typePlaceHolder && (
|
||||
<Badge
|
||||
className='absolute right-2 top-1.5'
|
||||
className="absolute right-2 top-1.5"
|
||||
text={typePlaceHolder}
|
||||
uppercase={false}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
</WrapElem>
|
||||
<PortalToFollowElemContent style={{
|
||||
zIndex: zIndex || 100,
|
||||
}} className='mt-1'>
|
||||
<PortalToFollowElemContent
|
||||
style={{
|
||||
zIndex: zIndex || 100,
|
||||
}}
|
||||
className="mt-1"
|
||||
>
|
||||
{!isConstant && (
|
||||
<VarReferencePopup
|
||||
vars={outputVars}
|
||||
@ -586,7 +639,7 @@ const VarReferencePicker: FC<Props> = ({
|
||||
)}
|
||||
</PortalToFollowElemContent>
|
||||
</PortalToFollowElem>
|
||||
</div >
|
||||
</div>
|
||||
)
|
||||
}
|
||||
export default React.memo(VarReferencePicker)
|
||||
|
||||
@ -1,12 +1,12 @@
|
||||
'use client'
|
||||
import type { FC } from 'react'
|
||||
import type { NodeOutPutVar, ValueSelector, Var } from '@/app/components/workflow/types'
|
||||
import React, { useMemo } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import VarReferenceVars from './var-reference-vars'
|
||||
import type { NodeOutPutVar, ValueSelector, Var } from '@/app/components/workflow/types'
|
||||
import ListEmpty from '@/app/components/base/list-empty'
|
||||
import { useStore } from '@/app/components/workflow/store'
|
||||
import { useDocLink } from '@/context/i18n'
|
||||
import VarReferenceVars from './var-reference-vars'
|
||||
|
||||
type Props = {
|
||||
vars: NodeOutPutVar[]
|
||||
@ -33,48 +33,59 @@ const VarReferencePopup: FC<Props> = ({
|
||||
const docLink = useDocLink()
|
||||
// max-h-[300px] overflow-y-auto todo: use portal to handle long list
|
||||
return (
|
||||
<div className='space-y-1 rounded-lg border border-components-panel-border bg-components-panel-bg p-1 shadow-lg' style={{
|
||||
width: itemWidth || 228,
|
||||
}}>
|
||||
<div
|
||||
className="space-y-1 rounded-lg border border-components-panel-border bg-components-panel-bg p-1 shadow-lg"
|
||||
style={{
|
||||
width: itemWidth || 228,
|
||||
}}
|
||||
>
|
||||
{((!vars || vars.length === 0) && popupFor)
|
||||
? (popupFor === 'toAssigned'
|
||||
? (
|
||||
<ListEmpty
|
||||
title={t('workflow.variableReference.noAvailableVars') || ''}
|
||||
description={<div className='system-xs-regular text-text-tertiary'>
|
||||
{t('workflow.variableReference.noVarsForOperation')}
|
||||
</div>}
|
||||
? (
|
||||
<ListEmpty
|
||||
title={t('workflow.variableReference.noAvailableVars') || ''}
|
||||
description={(
|
||||
<div className="system-xs-regular text-text-tertiary">
|
||||
{t('workflow.variableReference.noVarsForOperation')}
|
||||
</div>
|
||||
)}
|
||||
/>
|
||||
)
|
||||
: (
|
||||
<ListEmpty
|
||||
title={t('workflow.variableReference.noAssignedVars') || ''}
|
||||
description={(
|
||||
<div className="system-xs-regular text-text-tertiary">
|
||||
{t('workflow.variableReference.assignedVarsDescription')}
|
||||
<a
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="text-text-accent-secondary"
|
||||
href={docLink('/guides/workflow/variables#conversation-variables', {
|
||||
'zh-Hans': '/guides/workflow/variables#会话变量',
|
||||
'ja-JP': '/guides/workflow/variables#会話変数',
|
||||
})}
|
||||
>
|
||||
{t('workflow.variableReference.conversationVars')}
|
||||
</a>
|
||||
</div>
|
||||
)}
|
||||
/>
|
||||
))
|
||||
: (
|
||||
<VarReferenceVars
|
||||
searchBoxClassName="mt-1"
|
||||
vars={vars}
|
||||
onChange={onChange}
|
||||
itemWidth={itemWidth}
|
||||
isSupportFileVar={isSupportFileVar}
|
||||
zIndex={zIndex}
|
||||
showManageInputField={showManageRagInputFields}
|
||||
onManageInputField={() => setShowInputFieldPanel?.(true)}
|
||||
preferSchemaType={preferSchemaType}
|
||||
/>
|
||||
)
|
||||
: (
|
||||
<ListEmpty
|
||||
title={t('workflow.variableReference.noAssignedVars') || ''}
|
||||
description={<div className='system-xs-regular text-text-tertiary'>
|
||||
{t('workflow.variableReference.assignedVarsDescription')}
|
||||
<a target='_blank' rel='noopener noreferrer'
|
||||
className='text-text-accent-secondary'
|
||||
href={docLink('/guides/workflow/variables#conversation-variables', {
|
||||
'zh-Hans': '/guides/workflow/variables#会话变量',
|
||||
'ja-JP': '/guides/workflow/variables#会話変数',
|
||||
})}>
|
||||
{t('workflow.variableReference.conversationVars')}
|
||||
</a>
|
||||
</div>}
|
||||
/>
|
||||
))
|
||||
: <VarReferenceVars
|
||||
searchBoxClassName='mt-1'
|
||||
vars={vars}
|
||||
onChange={onChange}
|
||||
itemWidth={itemWidth}
|
||||
isSupportFileVar={isSupportFileVar}
|
||||
zIndex={zIndex}
|
||||
showManageInputField={showManageRagInputFields}
|
||||
onManageInputField={() => setShowInputFieldPanel?.(true)}
|
||||
preferSchemaType={preferSchemaType}
|
||||
/>
|
||||
}
|
||||
</div >
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
export default React.memo(VarReferencePopup)
|
||||
|
||||
@ -1,29 +1,30 @@
|
||||
'use client'
|
||||
import type { FC } from 'react'
|
||||
import React, { useEffect, useMemo, useRef, useState } from 'react'
|
||||
import type { StructuredOutput } from '../../../llm/types'
|
||||
import type { Field } from '@/app/components/workflow/nodes/llm/types'
|
||||
import type { NodeOutPutVar, ValueSelector, Var } from '@/app/components/workflow/types'
|
||||
import { useHover } from 'ahooks'
|
||||
import { noop } from 'lodash-es'
|
||||
import React, { useEffect, useMemo, useRef, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { cn } from '@/utils/classnames'
|
||||
import { type NodeOutPutVar, type ValueSelector, type Var, VarType } from '@/app/components/workflow/types'
|
||||
import { ChevronRight } from '@/app/components/base/icons/src/vender/line/arrows'
|
||||
import { CodeAssistant, MagicEdit } from '@/app/components/base/icons/src/vender/line/general'
|
||||
import { Variable02 } from '@/app/components/base/icons/src/vender/solid/development'
|
||||
import Input from '@/app/components/base/input'
|
||||
import {
|
||||
PortalToFollowElem,
|
||||
PortalToFollowElemContent,
|
||||
PortalToFollowElemTrigger,
|
||||
} from '@/app/components/base/portal-to-follow-elem'
|
||||
import Input from '@/app/components/base/input'
|
||||
import { checkKeys } from '@/utils/var'
|
||||
import type { StructuredOutput } from '../../../llm/types'
|
||||
import { Type } from '../../../llm/types'
|
||||
import PickerStructurePanel from '@/app/components/workflow/nodes/_base/components/variable/object-child-tree-panel/picker'
|
||||
import { isSpecialVar, varTypeToStructType } from './utils'
|
||||
import type { Field } from '@/app/components/workflow/nodes/llm/types'
|
||||
import { noop } from 'lodash-es'
|
||||
import { CodeAssistant, MagicEdit } from '@/app/components/base/icons/src/vender/line/general'
|
||||
import ManageInputField from './manage-input-field'
|
||||
import { VariableIconWithColor } from '@/app/components/workflow/nodes/_base/components/variable/variable-label'
|
||||
import { Variable02 } from '@/app/components/base/icons/src/vender/solid/development'
|
||||
import { VAR_SHOW_NAME_MAP } from '@/app/components/workflow/constants'
|
||||
import PickerStructurePanel from '@/app/components/workflow/nodes/_base/components/variable/object-child-tree-panel/picker'
|
||||
import { VariableIconWithColor } from '@/app/components/workflow/nodes/_base/components/variable/variable-label'
|
||||
import { VarType } from '@/app/components/workflow/types'
|
||||
import { cn } from '@/utils/classnames'
|
||||
import { checkKeys } from '@/utils/var'
|
||||
import { Type } from '../../../llm/types'
|
||||
import ManageInputField from './manage-input-field'
|
||||
import { isSpecialVar, varTypeToStructType } from './utils'
|
||||
|
||||
type ItemProps = {
|
||||
nodeId: string
|
||||
@ -74,16 +75,16 @@ const Item: FC<ItemProps> = ({
|
||||
switch (variable) {
|
||||
case 'current':
|
||||
Icon = isInCodeGeneratorInstructionEditor ? CodeAssistant : MagicEdit
|
||||
return <Icon className='h-3.5 w-3.5 shrink-0 text-util-colors-violet-violet-600' />
|
||||
return <Icon className="h-3.5 w-3.5 shrink-0 text-util-colors-violet-violet-600" />
|
||||
case 'error_message':
|
||||
return <Variable02 className='h-3.5 w-3.5 shrink-0 text-util-colors-orange-dark-orange-dark-600' />
|
||||
return <Variable02 className="h-3.5 w-3.5 shrink-0 text-util-colors-orange-dark-orange-dark-600" />
|
||||
default:
|
||||
return <Variable02 className='h-3.5 w-3.5 shrink-0 text-text-accent' />
|
||||
return <Variable02 className="h-3.5 w-3.5 shrink-0 text-text-accent" />
|
||||
}
|
||||
}, [isFlat, isInCodeGeneratorInstructionEditor, itemData.variable])
|
||||
|
||||
const varName = useMemo(() => {
|
||||
if(VAR_SHOW_NAME_MAP[itemData.variable])
|
||||
if (VAR_SHOW_NAME_MAP[itemData.variable])
|
||||
return VAR_SHOW_NAME_MAP[itemData.variable]
|
||||
|
||||
if (!isFlat)
|
||||
@ -95,7 +96,8 @@ const Item: FC<ItemProps> = ({
|
||||
}, [isFlat, isInCodeGeneratorInstructionEditor, itemData.variable])
|
||||
|
||||
const objStructuredOutput: StructuredOutput | null = useMemo(() => {
|
||||
if (!isObj) return null
|
||||
if (!isObj)
|
||||
return null
|
||||
const properties: Record<string, Field> = {}
|
||||
const childrenVars = (itemData.children as Var[]) || []
|
||||
childrenVars.forEach((c) => {
|
||||
@ -160,19 +162,23 @@ const Item: FC<ItemProps> = ({
|
||||
}
|
||||
}
|
||||
const variableCategory = useMemo(() => {
|
||||
if (isEnv) return 'environment'
|
||||
if (isChatVar) return 'conversation'
|
||||
if (isLoopVar) return 'loop'
|
||||
if (isRagVariable) return 'rag'
|
||||
if (isEnv)
|
||||
return 'environment'
|
||||
if (isChatVar)
|
||||
return 'conversation'
|
||||
if (isLoopVar)
|
||||
return 'loop'
|
||||
if (isRagVariable)
|
||||
return 'rag'
|
||||
return 'system'
|
||||
}, [isEnv, isChatVar, isSys, isLoopVar, isRagVariable])
|
||||
return (
|
||||
<PortalToFollowElem
|
||||
open={open}
|
||||
onOpenChange={noop}
|
||||
placement='left-start'
|
||||
placement="left-start"
|
||||
>
|
||||
<PortalToFollowElemTrigger className='w-full'>
|
||||
<PortalToFollowElemTrigger className="w-full">
|
||||
<div
|
||||
ref={itemRef}
|
||||
className={cn(
|
||||
@ -180,43 +186,45 @@ const Item: FC<ItemProps> = ({
|
||||
isHovering && ((isObj || isStructureOutput) ? 'bg-components-panel-on-panel-item-bg-hover' : 'bg-state-base-hover'),
|
||||
'relative flex h-6 w-full cursor-pointer items-center rounded-md pl-3',
|
||||
className,
|
||||
)
|
||||
}
|
||||
)}
|
||||
onClick={handleChosen}
|
||||
onMouseDown={e => e.preventDefault()}
|
||||
>
|
||||
<div className='flex w-0 grow items-center'>
|
||||
{!isFlat && <VariableIconWithColor
|
||||
variables={itemData.variable.split('.')}
|
||||
variableCategory={variableCategory}
|
||||
isExceptionVariable={isException}
|
||||
/>}
|
||||
<div className="flex w-0 grow items-center">
|
||||
{!isFlat && (
|
||||
<VariableIconWithColor
|
||||
variables={itemData.variable.split('.')}
|
||||
variableCategory={variableCategory}
|
||||
isExceptionVariable={isException}
|
||||
/>
|
||||
)}
|
||||
{isFlat && flatVarIcon}
|
||||
|
||||
{!isEnv && !isChatVar && !isRagVariable && (
|
||||
<div title={itemData.variable} className='system-sm-medium ml-1 w-0 grow truncate text-text-secondary'>{varName}</div>
|
||||
<div title={itemData.variable} className="system-sm-medium ml-1 w-0 grow truncate text-text-secondary">{varName}</div>
|
||||
)}
|
||||
{isEnv && (
|
||||
<div title={itemData.variable} className='system-sm-medium ml-1 w-0 grow truncate text-text-secondary'>{itemData.variable.replace('env.', '')}</div>
|
||||
<div title={itemData.variable} className="system-sm-medium ml-1 w-0 grow truncate text-text-secondary">{itemData.variable.replace('env.', '')}</div>
|
||||
)}
|
||||
{isChatVar && (
|
||||
<div title={itemData.des} className='system-sm-medium ml-1 w-0 grow truncate text-text-secondary'>{itemData.variable.replace('conversation.', '')}</div>
|
||||
<div title={itemData.des} className="system-sm-medium ml-1 w-0 grow truncate text-text-secondary">{itemData.variable.replace('conversation.', '')}</div>
|
||||
)}
|
||||
{isRagVariable && (
|
||||
<div title={itemData.des} className='system-sm-medium ml-1 w-0 grow truncate text-text-secondary'>{itemData.variable.split('.').slice(-1)[0]}</div>
|
||||
<div title={itemData.des} className="system-sm-medium ml-1 w-0 grow truncate text-text-secondary">{itemData.variable.split('.').slice(-1)[0]}</div>
|
||||
)}
|
||||
</div>
|
||||
<div className='ml-1 shrink-0 text-xs font-normal capitalize text-text-tertiary'>{(preferSchemaType && itemData.schemaType) ? itemData.schemaType : itemData.type}</div>
|
||||
<div className="ml-1 shrink-0 text-xs font-normal capitalize text-text-tertiary">{(preferSchemaType && itemData.schemaType) ? itemData.schemaType : itemData.type}</div>
|
||||
{
|
||||
(isObj || isStructureOutput) && (
|
||||
<ChevronRight className={cn('ml-0.5 h-3 w-3 text-text-quaternary', isHovering && 'text-text-tertiary')} />
|
||||
)
|
||||
}
|
||||
</div >
|
||||
</PortalToFollowElemTrigger >
|
||||
</div>
|
||||
</PortalToFollowElemTrigger>
|
||||
<PortalToFollowElemContent style={{
|
||||
zIndex: zIndex || 100,
|
||||
}}>
|
||||
}}
|
||||
>
|
||||
{(isStructureOutput || isObj) && (
|
||||
<PickerStructurePanel
|
||||
root={{ nodeId, nodeName: title, attrName: itemData.variable, attrAlias: itemData.schemaType }}
|
||||
@ -228,7 +236,7 @@ const Item: FC<ItemProps> = ({
|
||||
/>
|
||||
)}
|
||||
</PortalToFollowElemContent>
|
||||
</PortalToFollowElem >
|
||||
</PortalToFollowElem>
|
||||
)
|
||||
}
|
||||
|
||||
@ -308,7 +316,7 @@ const VarReferenceVars: FC<Props> = ({
|
||||
<>
|
||||
<div className={cn('var-search-input-wrapper mx-2 mb-2 mt-2', searchBoxClassName)} onClick={e => e.stopPropagation()}>
|
||||
<Input
|
||||
className='var-search-input'
|
||||
className="var-search-input"
|
||||
showLeftIcon
|
||||
showClearIcon
|
||||
value={searchText}
|
||||
@ -320,54 +328,63 @@ const VarReferenceVars: FC<Props> = ({
|
||||
autoFocus={autoFocus}
|
||||
/>
|
||||
</div>
|
||||
<div className='relative left-[-4px] h-[0.5px] bg-black/5' style={{
|
||||
width: 'calc(100% + 8px)',
|
||||
}}></div>
|
||||
<div
|
||||
className="relative left-[-4px] h-[0.5px] bg-black/5"
|
||||
style={{
|
||||
width: 'calc(100% + 8px)',
|
||||
}}
|
||||
>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
{filteredVars.length > 0
|
||||
? <div className={cn('max-h-[85vh] overflow-y-auto', maxHeightClass)}>
|
||||
? (
|
||||
<div className={cn('max-h-[85vh] overflow-y-auto', maxHeightClass)}>
|
||||
|
||||
{
|
||||
filteredVars.map((item, i) => (
|
||||
<div key={i} className={cn(!item.isFlat && 'mt-3', i === 0 && item.isFlat && 'mt-2')}>
|
||||
{!item.isFlat && (
|
||||
<div
|
||||
className='system-xs-medium-uppercase truncate px-3 leading-[22px] text-text-tertiary'
|
||||
title={item.title}
|
||||
>{item.title}</div>
|
||||
)}
|
||||
{item.vars.map((v, j) => (
|
||||
<Item
|
||||
key={j}
|
||||
title={item.title}
|
||||
nodeId={item.nodeId}
|
||||
objPath={[]}
|
||||
itemData={v}
|
||||
onChange={onChange}
|
||||
itemWidth={itemWidth}
|
||||
isSupportFileVar={isSupportFileVar}
|
||||
isException={v.isException}
|
||||
isLoopVar={item.isLoop}
|
||||
isFlat={item.isFlat}
|
||||
isInCodeGeneratorInstructionEditor={isInCodeGeneratorInstructionEditor}
|
||||
zIndex={zIndex}
|
||||
preferSchemaType={preferSchemaType}
|
||||
/>
|
||||
))}
|
||||
{item.isFlat && !filteredVars[i + 1]?.isFlat && !!filteredVars.find(item => !item.isFlat) && (
|
||||
<div className='relative mt-[14px] flex items-center space-x-1'>
|
||||
<div className='h-0 w-3 shrink-0 border border-divider-subtle'></div>
|
||||
<div className='system-2xs-semibold-uppercase text-text-tertiary'>{t('workflow.debug.lastOutput')}</div>
|
||||
<div className='h-0 shrink-0 grow border border-divider-subtle'></div>
|
||||
{
|
||||
filteredVars.map((item, i) => (
|
||||
<div key={i} className={cn(!item.isFlat && 'mt-3', i === 0 && item.isFlat && 'mt-2')}>
|
||||
{!item.isFlat && (
|
||||
<div
|
||||
className="system-xs-medium-uppercase truncate px-3 leading-[22px] text-text-tertiary"
|
||||
title={item.title}
|
||||
>
|
||||
{item.title}
|
||||
</div>
|
||||
)}
|
||||
{item.vars.map((v, j) => (
|
||||
<Item
|
||||
key={j}
|
||||
title={item.title}
|
||||
nodeId={item.nodeId}
|
||||
objPath={[]}
|
||||
itemData={v}
|
||||
onChange={onChange}
|
||||
itemWidth={itemWidth}
|
||||
isSupportFileVar={isSupportFileVar}
|
||||
isException={v.isException}
|
||||
isLoopVar={item.isLoop}
|
||||
isFlat={item.isFlat}
|
||||
isInCodeGeneratorInstructionEditor={isInCodeGeneratorInstructionEditor}
|
||||
zIndex={zIndex}
|
||||
preferSchemaType={preferSchemaType}
|
||||
/>
|
||||
))}
|
||||
{item.isFlat && !filteredVars[i + 1]?.isFlat && !!filteredVars.find(item => !item.isFlat) && (
|
||||
<div className="relative mt-[14px] flex items-center space-x-1">
|
||||
<div className="h-0 w-3 shrink-0 border border-divider-subtle"></div>
|
||||
<div className="system-2xs-semibold-uppercase text-text-tertiary">{t('workflow.debug.lastOutput')}</div>
|
||||
<div className="h-0 shrink-0 grow border border-divider-subtle"></div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>))
|
||||
}
|
||||
</div>
|
||||
: <div className='mt-2 pl-3 text-xs font-medium uppercase leading-[18px] text-gray-500'>{t('workflow.common.noVar')}</div>}
|
||||
))
|
||||
}
|
||||
</div>
|
||||
)
|
||||
: <div className="mt-2 pl-3 text-xs font-medium uppercase leading-[18px] text-gray-500">{t('workflow.common.noVar')}</div>}
|
||||
{
|
||||
showManageInputField && (
|
||||
<ManageInputField
|
||||
|
||||
@ -1,15 +1,15 @@
|
||||
'use client'
|
||||
import type { FC } from 'react'
|
||||
import React, { useCallback, useState } from 'react'
|
||||
import { RiArrowDownSLine } from '@remixicon/react'
|
||||
import { cn } from '@/utils/classnames'
|
||||
import React, { useCallback, useState } from 'react'
|
||||
import { Check } from '@/app/components/base/icons/src/vender/line/general'
|
||||
import {
|
||||
PortalToFollowElem,
|
||||
PortalToFollowElemContent,
|
||||
PortalToFollowElemTrigger,
|
||||
} from '@/app/components/base/portal-to-follow-elem'
|
||||
import { Check } from '@/app/components/base/icons/src/vender/line/general'
|
||||
import { VarType } from '@/app/components/workflow/types'
|
||||
import { cn } from '@/utils/classnames'
|
||||
|
||||
type Props = {
|
||||
className?: string
|
||||
@ -39,27 +39,28 @@ const VarReferencePicker: FC<Props> = ({
|
||||
<PortalToFollowElem
|
||||
open={open}
|
||||
onOpenChange={setOpen}
|
||||
placement='bottom-start'
|
||||
placement="bottom-start"
|
||||
offset={4}
|
||||
>
|
||||
<PortalToFollowElemTrigger onClick={() => setOpen(!open)} className='w-[120px] cursor-pointer'>
|
||||
<div className='flex h-8 items-center justify-between rounded-lg border-0 bg-components-input-bg-normal px-2.5 text-[13px] text-text-primary'>
|
||||
<div className='w-0 grow truncate capitalize' title={value}>{value}</div>
|
||||
<RiArrowDownSLine className='h-3.5 w-3.5 shrink-0 text-text-secondary' />
|
||||
<PortalToFollowElemTrigger onClick={() => setOpen(!open)} className="w-[120px] cursor-pointer">
|
||||
<div className="flex h-8 items-center justify-between rounded-lg border-0 bg-components-input-bg-normal px-2.5 text-[13px] text-text-primary">
|
||||
<div className="w-0 grow truncate capitalize" title={value}>{value}</div>
|
||||
<RiArrowDownSLine className="h-3.5 w-3.5 shrink-0 text-text-secondary" />
|
||||
</div>
|
||||
</PortalToFollowElemTrigger>
|
||||
<PortalToFollowElemContent style={{
|
||||
zIndex: 100,
|
||||
}}>
|
||||
<div className='w-[120px] rounded-lg bg-components-panel-bg p-1 shadow-sm'>
|
||||
}}
|
||||
>
|
||||
<div className="w-[120px] rounded-lg bg-components-panel-bg p-1 shadow-sm">
|
||||
{TYPES.map(type => (
|
||||
<div
|
||||
key={type}
|
||||
className='flex h-[30px] cursor-pointer items-center justify-between rounded-lg pl-3 pr-2 text-[13px] text-text-primary hover:bg-state-base-hover'
|
||||
className="flex h-[30px] cursor-pointer items-center justify-between rounded-lg pl-3 pr-2 text-[13px] text-text-primary hover:bg-state-base-hover"
|
||||
onClick={handleChange(type)}
|
||||
>
|
||||
<div className='w-0 grow truncate capitalize'>{type}</div>
|
||||
{type === value && <Check className='h-4 w-4 shrink-0 text-text-accent' />}
|
||||
<div className="w-0 grow truncate capitalize">{type}</div>
|
||||
{type === value && <Check className="h-4 w-4 shrink-0 text-text-accent" />}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import type { VarInInspectType } from '@/types/workflow'
|
||||
import { memo } from 'react'
|
||||
import { cn } from '@/utils/classnames'
|
||||
import { useVarIcon } from '../hooks'
|
||||
import type { VarInInspectType } from '@/types/workflow'
|
||||
|
||||
export type VariableIconProps = {
|
||||
className?: string
|
||||
|
||||
@ -1,17 +1,17 @@
|
||||
import { memo } from 'react'
|
||||
import { capitalize } from 'lodash-es'
|
||||
import type { VariablePayload } from '../types'
|
||||
import {
|
||||
RiErrorWarningFill,
|
||||
RiMoreLine,
|
||||
} from '@remixicon/react'
|
||||
import type { VariablePayload } from '../types'
|
||||
import { capitalize } from 'lodash-es'
|
||||
import { memo } from 'react'
|
||||
import Tooltip from '@/app/components/base/tooltip'
|
||||
import { cn } from '@/utils/classnames'
|
||||
import { isConversationVar, isENV, isGlobalVar, isRagVariableVar } from '../../utils'
|
||||
import { useVarColor } from '../hooks'
|
||||
import VariableNodeLabel from './variable-node-label'
|
||||
import VariableIcon from './variable-icon'
|
||||
import VariableName from './variable-name'
|
||||
import { cn } from '@/utils/classnames'
|
||||
import Tooltip from '@/app/components/base/tooltip'
|
||||
import { isConversationVar, isENV, isGlobalVar, isRagVariableVar } from '../../utils'
|
||||
import VariableNodeLabel from './variable-node-label'
|
||||
|
||||
const VariableLabel = ({
|
||||
nodeType,
|
||||
@ -46,8 +46,8 @@ const VariableLabel = ({
|
||||
{
|
||||
notShowFullPath && (
|
||||
<>
|
||||
<RiMoreLine className='h-3 w-3 shrink-0 text-text-secondary' />
|
||||
<div className='system-xs-regular shrink-0 text-divider-deep'>/</div>
|
||||
<RiMoreLine className="h-3 w-3 shrink-0 text-text-secondary" />
|
||||
<div className="system-xs-regular shrink-0 text-divider-deep">/</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
@ -62,7 +62,7 @@ const VariableLabel = ({
|
||||
/>
|
||||
{
|
||||
variableType && (
|
||||
<div className='system-xs-regular shrink-0 text-text-tertiary'>
|
||||
<div className="system-xs-regular shrink-0 text-text-tertiary">
|
||||
{capitalize(variableType)}
|
||||
</div>
|
||||
)
|
||||
@ -73,7 +73,7 @@ const VariableLabel = ({
|
||||
popupContent={errorMsg}
|
||||
asChild
|
||||
>
|
||||
<RiErrorWarningFill className='h-3 w-3 shrink-0 text-text-destructive' />
|
||||
<RiErrorWarningFill className="h-3 w-3 shrink-0 text-text-destructive" />
|
||||
</Tooltip>
|
||||
)
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user