Merge branch 'feat/plugins' of https://github.com/langgenius/dify into feat/plugins
This commit is contained in:
commit
b656b7a0dd
@ -1,20 +1,18 @@
|
|||||||
'use client'
|
'use client'
|
||||||
import type { FC } from 'react'
|
import type { FC } from 'react'
|
||||||
import React, { useCallback, useEffect, useRef, useState } from 'react'
|
import React, { useCallback, useEffect, useRef, useState } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import {
|
||||||
|
RiEqualizer2Line,
|
||||||
|
} from '@remixicon/react'
|
||||||
import type { PopupProps } from './config-popup'
|
import type { PopupProps } from './config-popup'
|
||||||
import ConfigPopup from './config-popup'
|
import ConfigPopup from './config-popup'
|
||||||
import cn from '@/utils/classnames'
|
import cn from '@/utils/classnames'
|
||||||
import Button from '@/app/components/base/button'
|
|
||||||
import { Settings04 } from '@/app/components/base/icons/src/vender/line/general'
|
|
||||||
import {
|
import {
|
||||||
PortalToFollowElem,
|
PortalToFollowElem,
|
||||||
PortalToFollowElemContent,
|
PortalToFollowElemContent,
|
||||||
PortalToFollowElemTrigger,
|
PortalToFollowElemTrigger,
|
||||||
} from '@/app/components/base/portal-to-follow-elem'
|
} from '@/app/components/base/portal-to-follow-elem'
|
||||||
|
|
||||||
const I18N_PREFIX = 'app.tracing'
|
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
readOnly: boolean
|
readOnly: boolean
|
||||||
className?: string
|
className?: string
|
||||||
@ -28,7 +26,6 @@ const ConfigBtn: FC<Props> = ({
|
|||||||
controlShowPopup,
|
controlShowPopup,
|
||||||
...popupProps
|
...popupProps
|
||||||
}) => {
|
}) => {
|
||||||
const { t } = useTranslation()
|
|
||||||
const [open, doSetOpen] = useState(false)
|
const [open, doSetOpen] = useState(false)
|
||||||
const openRef = useRef(open)
|
const openRef = useRef(open)
|
||||||
const setOpen = useCallback((v: boolean) => {
|
const setOpen = useCallback((v: boolean) => {
|
||||||
@ -50,21 +47,6 @@ const ConfigBtn: FC<Props> = ({
|
|||||||
if (popupProps.readOnly && !hasConfigured)
|
if (popupProps.readOnly && !hasConfigured)
|
||||||
return null
|
return null
|
||||||
|
|
||||||
const triggerContent = hasConfigured
|
|
||||||
? (
|
|
||||||
<div className={cn(className, 'p-1 rounded-md hover:bg-black/5 cursor-pointer')}>
|
|
||||||
<Settings04 className='w-4 h-4 text-gray-500' />
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
: (
|
|
||||||
<Button variant='primary'
|
|
||||||
className={cn(className, '!h-8 !px-3 select-none')}
|
|
||||||
>
|
|
||||||
<Settings04 className='mr-1 w-4 h-4' />
|
|
||||||
<span className='text-[13px]'>{t(`${I18N_PREFIX}.config`)}</span>
|
|
||||||
</Button>
|
|
||||||
)
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PortalToFollowElem
|
<PortalToFollowElem
|
||||||
open={open}
|
open={open}
|
||||||
@ -72,11 +54,13 @@ const ConfigBtn: FC<Props> = ({
|
|||||||
placement='bottom-end'
|
placement='bottom-end'
|
||||||
offset={{
|
offset={{
|
||||||
mainAxis: 12,
|
mainAxis: 12,
|
||||||
crossAxis: hasConfigured ? 8 : 0,
|
crossAxis: hasConfigured ? 8 : 49,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<PortalToFollowElemTrigger onClick={handleTrigger}>
|
<PortalToFollowElemTrigger onClick={handleTrigger}>
|
||||||
{triggerContent}
|
<div className={cn(className, 'p-1 rounded-md')}>
|
||||||
|
<RiEqualizer2Line className='w-4 h-4 text-text-tertiary' />
|
||||||
|
</div>
|
||||||
</PortalToFollowElemTrigger>
|
</PortalToFollowElemTrigger>
|
||||||
<PortalToFollowElemContent className='z-[11]'>
|
<PortalToFollowElemContent className='z-[11]'>
|
||||||
<ConfigPopup {...popupProps} />
|
<ConfigPopup {...popupProps} />
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
'use client'
|
'use client'
|
||||||
import type { FC } from 'react'
|
import type { FC } from 'react'
|
||||||
import React, { useCallback, useEffect, useState } from 'react'
|
import React, { useCallback, useEffect, useState } from 'react'
|
||||||
|
import {
|
||||||
|
RiArrowDownDoubleLine,
|
||||||
|
} from '@remixicon/react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { usePathname } from 'next/navigation'
|
import { usePathname } from 'next/navigation'
|
||||||
import { useBoolean } from 'ahooks'
|
import { useBoolean } from 'ahooks'
|
||||||
@ -8,7 +11,6 @@ import type { LangFuseConfig, LangSmithConfig } from './type'
|
|||||||
import { TracingProvider } from './type'
|
import { TracingProvider } from './type'
|
||||||
import TracingIcon from './tracing-icon'
|
import TracingIcon from './tracing-icon'
|
||||||
import ConfigButton from './config-button'
|
import ConfigButton from './config-button'
|
||||||
import cn from '@/utils/classnames'
|
|
||||||
import { LangfuseIcon, LangsmithIcon } from '@/app/components/base/icons/src/public/tracing'
|
import { LangfuseIcon, LangsmithIcon } from '@/app/components/base/icons/src/public/tracing'
|
||||||
import Indicator from '@/app/components/header/indicator'
|
import Indicator from '@/app/components/header/indicator'
|
||||||
import { fetchTracingConfig as doFetchTracingConfig, fetchTracingStatus, updateTracingStatus } from '@/service/apps'
|
import { fetchTracingConfig as doFetchTracingConfig, fetchTracingStatus, updateTracingStatus } from '@/service/apps'
|
||||||
@ -16,6 +18,8 @@ import type { TracingStatus } from '@/models/app'
|
|||||||
import Toast from '@/app/components/base/toast'
|
import Toast from '@/app/components/base/toast'
|
||||||
import { useAppContext } from '@/context/app-context'
|
import { useAppContext } from '@/context/app-context'
|
||||||
import Loading from '@/app/components/base/loading'
|
import Loading from '@/app/components/base/loading'
|
||||||
|
import Divider from '@/app/components/base/divider'
|
||||||
|
import cn from '@/utils/classnames'
|
||||||
|
|
||||||
const I18N_PREFIX = 'app.tracing'
|
const I18N_PREFIX = 'app.tracing'
|
||||||
|
|
||||||
@ -27,7 +31,7 @@ const Title = ({
|
|||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={cn(className, 'flex items-center text-lg font-semibold text-gray-900')}>
|
<div className={cn('flex items-center system-xl-semibold text-text-primary', className)}>
|
||||||
{t('common.appMenus.overview')}
|
{t('common.appMenus.overview')}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
@ -135,43 +139,68 @@ const Panel: FC = () => {
|
|||||||
return (
|
return (
|
||||||
<div className={cn('mb-3 flex justify-between items-center')}>
|
<div className={cn('mb-3 flex justify-between items-center')}>
|
||||||
<Title className='h-[41px]' />
|
<Title className='h-[41px]' />
|
||||||
<div className='flex items-center p-2 rounded-xl border-[0.5px] border-gray-200 shadow-xs cursor-pointer hover:bg-gray-100' onClick={showPopup}>
|
<div
|
||||||
{!inUseTracingProvider
|
className={cn(
|
||||||
? <>
|
'flex items-center p-2 rounded-xl bg-background-default-dodge border-t border-l-[0.5px] border-effects-highlight shadow-xs cursor-pointer hover:bg-background-default-lighter hover:border-effects-highlight-lightmode-off',
|
||||||
<TracingIcon size='md' className='mr-2' />
|
controlShowPopup && 'bg-background-default-lighter border-effects-highlight-lightmode-off',
|
||||||
<div className='leading-5 text-sm font-semibold text-gray-700'>{t(`${I18N_PREFIX}.title`)}</div>
|
)}
|
||||||
</>
|
onClick={showPopup}
|
||||||
: <InUseProviderIcon className='ml-1 h-4' />}
|
>
|
||||||
|
{!inUseTracingProvider && (
|
||||||
{hasConfiguredTracing && (
|
<>
|
||||||
<div className='ml-4 mr-1 flex items-center'>
|
<TracingIcon size='md' />
|
||||||
<Indicator color={enabled ? 'green' : 'gray'} />
|
<div className='mx-2 system-sm-semibold text-text-secondary'>{t(`${I18N_PREFIX}.title`)}</div>
|
||||||
<div className='ml-1.5 text-xs font-semibold text-gray-500 uppercase'>
|
<div className='flex items-center' onClick={e => e.stopPropagation()}>
|
||||||
{t(`${I18N_PREFIX}.${enabled ? 'enabled' : 'disabled'}`)}
|
<ConfigButton
|
||||||
|
appId={appId}
|
||||||
|
readOnly={readOnly}
|
||||||
|
hasConfigured={false}
|
||||||
|
enabled={enabled}
|
||||||
|
onStatusChange={handleTracingEnabledChange}
|
||||||
|
chosenProvider={inUseTracingProvider}
|
||||||
|
onChooseProvider={handleChooseProvider}
|
||||||
|
langSmithConfig={langSmithConfig}
|
||||||
|
langFuseConfig={langFuseConfig}
|
||||||
|
onConfigUpdated={handleTracingConfigUpdated}
|
||||||
|
onConfigRemoved={handleTracingConfigRemoved}
|
||||||
|
controlShowPopup={controlShowPopup}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<Divider type='vertical' className='h-3.5' />
|
||||||
|
<div className='p-1 rounded-md'>
|
||||||
|
<RiArrowDownDoubleLine className='w-4 h-4 text-text-tertiary' />
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{hasConfiguredTracing && (
|
{hasConfiguredTracing && (
|
||||||
<div className='ml-2 w-px h-3.5 bg-gray-200'></div>
|
<>
|
||||||
|
<div className='ml-4 mr-1 flex items-center'>
|
||||||
|
<Indicator color={enabled ? 'green' : 'gray'} />
|
||||||
|
<div className='ml-1.5 system-xs-semibold-uppercase text-text-tertiary'>
|
||||||
|
{t(`${I18N_PREFIX}.${enabled ? 'enabled' : 'disabled'}`)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<InUseProviderIcon className='ml-1 h-4' />
|
||||||
|
<Divider type='vertical' className='h-3.5' />
|
||||||
|
<div className='flex items-center' onClick={e => e.stopPropagation()}>
|
||||||
|
<ConfigButton
|
||||||
|
appId={appId}
|
||||||
|
readOnly={readOnly}
|
||||||
|
hasConfigured
|
||||||
|
className='ml-2'
|
||||||
|
enabled={enabled}
|
||||||
|
onStatusChange={handleTracingEnabledChange}
|
||||||
|
chosenProvider={inUseTracingProvider}
|
||||||
|
onChooseProvider={handleChooseProvider}
|
||||||
|
langSmithConfig={langSmithConfig}
|
||||||
|
langFuseConfig={langFuseConfig}
|
||||||
|
onConfigUpdated={handleTracingConfigUpdated}
|
||||||
|
onConfigRemoved={handleTracingConfigRemoved}
|
||||||
|
controlShowPopup={controlShowPopup}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
)}
|
)}
|
||||||
<div className='flex items-center' onClick={e => e.stopPropagation()}>
|
|
||||||
<ConfigButton
|
|
||||||
appId={appId}
|
|
||||||
readOnly={readOnly}
|
|
||||||
hasConfigured
|
|
||||||
className='ml-2'
|
|
||||||
enabled={enabled}
|
|
||||||
onStatusChange={handleTracingEnabledChange}
|
|
||||||
chosenProvider={inUseTracingProvider}
|
|
||||||
onChooseProvider={handleChooseProvider}
|
|
||||||
langSmithConfig={langSmithConfig}
|
|
||||||
langFuseConfig={langFuseConfig}
|
|
||||||
onConfigUpdated={handleTracingConfigUpdated}
|
|
||||||
onConfigRemoved={handleTracingConfigRemoved}
|
|
||||||
controlShowPopup={controlShowPopup}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
@ -1,45 +0,0 @@
|
|||||||
'use client'
|
|
||||||
import { ChevronDoubleDownIcon } from '@heroicons/react/20/solid'
|
|
||||||
import type { FC } from 'react'
|
|
||||||
import { useTranslation } from 'react-i18next'
|
|
||||||
import React, { useCallback } from 'react'
|
|
||||||
import Tooltip from '@/app/components/base/tooltip'
|
|
||||||
|
|
||||||
const I18N_PREFIX = 'app.tracing'
|
|
||||||
|
|
||||||
type Props = {
|
|
||||||
isFold: boolean
|
|
||||||
onFoldChange: (isFold: boolean) => void
|
|
||||||
}
|
|
||||||
|
|
||||||
const ToggleFoldBtn: FC<Props> = ({
|
|
||||||
isFold,
|
|
||||||
onFoldChange,
|
|
||||||
}) => {
|
|
||||||
const { t } = useTranslation()
|
|
||||||
|
|
||||||
const handleFoldChange = useCallback((e: React.MouseEvent<HTMLDivElement>) => {
|
|
||||||
e.stopPropagation()
|
|
||||||
onFoldChange(!isFold)
|
|
||||||
}, [isFold, onFoldChange])
|
|
||||||
return (
|
|
||||||
// text-[0px] to hide spacing between tooltip elements
|
|
||||||
<div className='shrink-0 cursor-pointer text-[0px]' onClick={handleFoldChange}>
|
|
||||||
<Tooltip
|
|
||||||
popupContent={t(`${I18N_PREFIX}.${isFold ? 'expand' : 'collapse'}`)}
|
|
||||||
>
|
|
||||||
{isFold && (
|
|
||||||
<div className='p-1 rounded-md text-gray-500 hover:text-gray-800 hover:bg-black/5'>
|
|
||||||
<ChevronDoubleDownIcon className='w-4 h-4' />
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
{!isFold && (
|
|
||||||
<div className='p-2 rounded-lg text-gray-500 border-[0.5px] border-gray-200 hover:text-gray-800 hover:bg-black/5'>
|
|
||||||
<ChevronDoubleDownIcon className='w-4 h-4 transform rotate-180' />
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</Tooltip>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
export default React.memo(ToggleFoldBtn)
|
|
@ -1,5 +1,4 @@
|
|||||||
import {
|
import {
|
||||||
useCallback,
|
|
||||||
useEffect,
|
useEffect,
|
||||||
useMemo,
|
useMemo,
|
||||||
useState,
|
useState,
|
||||||
@ -15,9 +14,8 @@ import TracingPanel from '@/app/components/workflow/run/tracing-panel'
|
|||||||
import cn from '@/utils/classnames'
|
import cn from '@/utils/classnames'
|
||||||
import { CheckCircle } from '@/app/components/base/icons/src/vender/solid/general'
|
import { CheckCircle } from '@/app/components/base/icons/src/vender/solid/general'
|
||||||
import { WorkflowRunningStatus } from '@/app/components/workflow/types'
|
import { WorkflowRunningStatus } from '@/app/components/workflow/types'
|
||||||
import { useStore as useAppStore } from '@/app/components/app/store'
|
|
||||||
|
|
||||||
interface WorkflowProcessProps {
|
type WorkflowProcessProps = {
|
||||||
data: WorkflowProcess
|
data: WorkflowProcess
|
||||||
item?: ChatItem
|
item?: ChatItem
|
||||||
expand?: boolean
|
expand?: boolean
|
||||||
@ -26,7 +24,6 @@ interface WorkflowProcessProps {
|
|||||||
}
|
}
|
||||||
const WorkflowProcessItem = ({
|
const WorkflowProcessItem = ({
|
||||||
data,
|
data,
|
||||||
item,
|
|
||||||
expand = false,
|
expand = false,
|
||||||
hideInfo = false,
|
hideInfo = false,
|
||||||
hideProcessDetail = false,
|
hideProcessDetail = false,
|
||||||
@ -54,22 +51,6 @@ const WorkflowProcessItem = ({
|
|||||||
setCollapse(!expand)
|
setCollapse(!expand)
|
||||||
}, [expand])
|
}, [expand])
|
||||||
|
|
||||||
const setCurrentLogItem = useAppStore(s => s.setCurrentLogItem)
|
|
||||||
const setShowMessageLogModal = useAppStore(s => s.setShowMessageLogModal)
|
|
||||||
const setCurrentLogModalActiveTab = useAppStore(s => s.setCurrentLogModalActiveTab)
|
|
||||||
|
|
||||||
const showIterationDetail = useCallback(() => {
|
|
||||||
setCurrentLogItem(item)
|
|
||||||
setCurrentLogModalActiveTab('TRACING')
|
|
||||||
setShowMessageLogModal(true)
|
|
||||||
}, [item, setCurrentLogItem, setCurrentLogModalActiveTab, setShowMessageLogModal])
|
|
||||||
|
|
||||||
const showRetryDetail = useCallback(() => {
|
|
||||||
setCurrentLogItem(item)
|
|
||||||
setCurrentLogModalActiveTab('TRACING')
|
|
||||||
setShowMessageLogModal(true)
|
|
||||||
}, [item, setCurrentLogItem, setCurrentLogModalActiveTab, setShowMessageLogModal])
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
@ -110,8 +91,6 @@ const WorkflowProcessItem = ({
|
|||||||
{
|
{
|
||||||
<TracingPanel
|
<TracingPanel
|
||||||
list={data.tracing}
|
list={data.tracing}
|
||||||
onShowIterationDetail={showIterationDetail}
|
|
||||||
onShowRetryDetail={showRetryDetail}
|
|
||||||
hideNodeInfo={hideInfo}
|
hideNodeInfo={hideInfo}
|
||||||
hideNodeProcessDetail={hideProcessDetail}
|
hideNodeProcessDetail={hideProcessDetail}
|
||||||
/>
|
/>
|
||||||
|
@ -40,7 +40,7 @@ const ModelIcon: FC<ModelIconProps> = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={cn(
|
<div className={cn(
|
||||||
'flex items-center justify-center rounded-md border-[0.5px] border-components-panel-border-subtle bg-background-default-subtle',
|
'flex items-center justify-center rounded-md border-[0.5px] w-5 h-5 border-components-panel-border-subtle bg-background-default-subtle',
|
||||||
className,
|
className,
|
||||||
)}>
|
)}>
|
||||||
<div className='flex w-5 h-5 items-center justify-center opacity-35'>
|
<div className='flex w-5 h-5 items-center justify-center opacity-35'>
|
||||||
|
@ -26,6 +26,7 @@ import cn from '@/utils/classnames'
|
|||||||
import { useProviderContext } from '@/context/provider-context'
|
import { useProviderContext } from '@/context/provider-context'
|
||||||
import { RiEqualizer2Line } from '@remixicon/react'
|
import { RiEqualizer2Line } from '@remixicon/react'
|
||||||
import { fetchPluginInfoFromMarketPlace } from '@/service/plugins'
|
import { fetchPluginInfoFromMarketPlace } from '@/service/plugins'
|
||||||
|
import { fetchModelProviderModelList } from '@/service/common'
|
||||||
|
|
||||||
export type AgentModelTriggerProps = {
|
export type AgentModelTriggerProps = {
|
||||||
open?: boolean
|
open?: boolean
|
||||||
@ -67,11 +68,22 @@ const AgentModelTrigger: FC<AgentModelTriggerProps> = ({
|
|||||||
const [pluginInfo, setPluginInfo] = useState<PluginInfoFromMarketPlace | null>(null)
|
const [pluginInfo, setPluginInfo] = useState<PluginInfoFromMarketPlace | null>(null)
|
||||||
const [isPluginChecked, setIsPluginChecked] = useState(false)
|
const [isPluginChecked, setIsPluginChecked] = useState(false)
|
||||||
const [installed, setInstalled] = useState(false)
|
const [installed, setInstalled] = useState(false)
|
||||||
|
const [inModelList, setInModelList] = useState(false)
|
||||||
const invalidateInstalledPluginList = useInvalidateInstalledPluginList()
|
const invalidateInstalledPluginList = useInvalidateInstalledPluginList()
|
||||||
const handleOpenModal = useModelModalHandler()
|
const handleOpenModal = useModelModalHandler()
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
(async () => {
|
(async () => {
|
||||||
if (providerName && !modelProvider) {
|
if (modelId && currentProvider) {
|
||||||
|
try {
|
||||||
|
const modelsData = await fetchModelProviderModelList(`/workspaces/current/model-providers/${currentProvider?.provider}/models`)
|
||||||
|
if (modelId && modelsData.data.find(item => item.model === modelId))
|
||||||
|
setInModelList(true)
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
// pass
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (providerName) {
|
||||||
const parts = providerName.split('/')
|
const parts = providerName.split('/')
|
||||||
const org = parts[0]
|
const org = parts[0]
|
||||||
const name = parts[1]
|
const name = parts[1]
|
||||||
@ -89,7 +101,7 @@ const AgentModelTrigger: FC<AgentModelTriggerProps> = ({
|
|||||||
setIsPluginChecked(true)
|
setIsPluginChecked(true)
|
||||||
}
|
}
|
||||||
})()
|
})()
|
||||||
}, [providerName, modelProvider])
|
}, [providerName, modelId, currentProvider])
|
||||||
|
|
||||||
if (modelId && !isPluginChecked)
|
if (modelId && !isPluginChecked)
|
||||||
return null
|
return null
|
||||||
@ -121,6 +133,7 @@ const AgentModelTrigger: FC<AgentModelTriggerProps> = ({
|
|||||||
<StatusIndicators
|
<StatusIndicators
|
||||||
needsConfiguration={needsConfiguration}
|
needsConfiguration={needsConfiguration}
|
||||||
modelProvider={!!modelProvider}
|
modelProvider={!!modelProvider}
|
||||||
|
inModelList={inModelList}
|
||||||
disabled={!!disabled}
|
disabled={!!disabled}
|
||||||
pluginInfo={pluginInfo}
|
pluginInfo={pluginInfo}
|
||||||
t={t}
|
t={t}
|
||||||
|
@ -1,46 +1,73 @@
|
|||||||
import Tooltip from '@/app/components/base/tooltip'
|
import Tooltip from '@/app/components/base/tooltip'
|
||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
|
import { SwitchPluginVersion } from '@/app/components/workflow/nodes/_base/components/switch-plugin-version'
|
||||||
|
import { useInstalledPluginList } from '@/service/use-plugins'
|
||||||
import { RiErrorWarningFill } from '@remixicon/react'
|
import { RiErrorWarningFill } from '@remixicon/react'
|
||||||
|
|
||||||
type StatusIndicatorsProps = {
|
type StatusIndicatorsProps = {
|
||||||
needsConfiguration: boolean
|
needsConfiguration: boolean
|
||||||
modelProvider: boolean
|
modelProvider: boolean
|
||||||
|
inModelList: boolean
|
||||||
disabled: boolean
|
disabled: boolean
|
||||||
pluginInfo: any
|
pluginInfo: any
|
||||||
t: any
|
t: any
|
||||||
}
|
}
|
||||||
|
|
||||||
const StatusIndicators = ({ needsConfiguration, modelProvider, disabled, pluginInfo, t }: StatusIndicatorsProps) => {
|
const StatusIndicators = ({ needsConfiguration, modelProvider, inModelList, disabled, pluginInfo, t }: StatusIndicatorsProps) => {
|
||||||
|
const { data: pluginList } = useInstalledPluginList()
|
||||||
|
const renderTooltipContent = (title: string, description?: string, linkText?: string, linkHref?: string) => {
|
||||||
|
return (
|
||||||
|
<div className='flex w-[240px] max-w-[240px] gap-1 flex-col px-1 py-1.5' onClick={e => e.stopPropagation()}>
|
||||||
|
<div className='text-text-primary title-xs-semi-bold'>{title}</div>
|
||||||
|
{description && (
|
||||||
|
<div className='min-w-[200px] text-text-secondary body-xs-regular'>
|
||||||
|
{description}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{linkText && linkHref && (
|
||||||
|
<div className='text-text-accent body-xs-regular cursor-pointer z-[100]'>
|
||||||
|
<Link
|
||||||
|
href={linkHref}
|
||||||
|
onClick={(e) => {
|
||||||
|
e.stopPropagation()
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{linkText}
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
// const installedPluginUniqueIdentifier = pluginList?.plugins.find(plugin => plugin.name === pluginInfo.name)?.plugin_unique_identifier
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
{/* plugin installed and model is in model list but disabled */}
|
||||||
|
{/* plugin installed from github/local and model is not in model list */}
|
||||||
{!needsConfiguration && modelProvider && disabled && (
|
{!needsConfiguration && modelProvider && disabled && (
|
||||||
<Tooltip
|
<Tooltip
|
||||||
popupContent={t('workflow.nodes.agent.modelSelectorTooltips.deprecated')}
|
popupContent={inModelList ? t('workflow.nodes.agent.modelSelectorTooltips.deprecated')
|
||||||
|
: renderTooltipContent(
|
||||||
|
t('workflow.nodes.agent.modelNotSupport.title'),
|
||||||
|
!pluginInfo ? t('workflow.nodes.agent.modelNotSupport.desc') : t('workflow.nodes.agent.modelNotSupport.descForVersionSwitch'),
|
||||||
|
!pluginInfo ? t('workflow.nodes.agent.linkToPlugin') : '',
|
||||||
|
!pluginInfo ? '/plugins' : '',
|
||||||
|
)
|
||||||
|
}
|
||||||
asChild={false}
|
asChild={false}
|
||||||
|
needsDelay={!inModelList}
|
||||||
>
|
>
|
||||||
<RiErrorWarningFill className='w-4 h-4 text-text-destructive' />
|
{!pluginInfo ? <RiErrorWarningFill className='w-4 h-4 text-text-destructive' /> : <SwitchPluginVersion uniqueIdentifier={pluginList?.plugins.find(plugin => plugin.name === pluginInfo.name)?.plugin_unique_identifier ?? ''} />}
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
)}
|
)}
|
||||||
{!modelProvider && !pluginInfo && (
|
{!modelProvider && !pluginInfo && (
|
||||||
<Tooltip
|
<Tooltip
|
||||||
popupContent={
|
popupContent={renderTooltipContent(
|
||||||
<div className='flex w-[240px] max-w-[240px] gap-1 flex-col px-1 py-1.5'>
|
t('workflow.nodes.agent.modelNotInMarketplace.title'),
|
||||||
<div className='text-text-primary title-xs-semi-bold'>{t('workflow.nodes.agent.modelNotInMarketplace.title')}</div>
|
t('workflow.nodes.agent.modelNotInMarketplace.desc'),
|
||||||
<div className='min-w-[200px] text-text-secondary body-xs-regular'>
|
t('workflow.nodes.agent.linkToPlugin'),
|
||||||
{t('workflow.nodes.agent.modelNotInMarketplace.desc')}
|
'/plugins',
|
||||||
</div>
|
)}
|
||||||
<div className='text-text-accent body-xs-regular cursor-pointer z-[100]'>
|
|
||||||
<Link
|
|
||||||
href={'/plugins'}
|
|
||||||
onClick={(e) => {
|
|
||||||
e.stopPropagation()
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{t('workflow.nodes.agent.linkToPlugin')}
|
|
||||||
</Link>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
asChild={false}
|
asChild={false}
|
||||||
needsDelay
|
needsDelay
|
||||||
>
|
>
|
||||||
|
@ -22,11 +22,11 @@ const ModelTrigger: FC<ModelTriggerProps> = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={cn('group flex flex-grow items-center p-[3px] pl-1 h-6 gap-1 rounded-lg bg-components-input-bg-disabled cursor-pointer', className)}
|
className={cn('group flex flex-grow items-center p-[3px] pl-1 h-8 gap-1 rounded-lg bg-components-input-bg-disabled cursor-pointer', className)}
|
||||||
>
|
>
|
||||||
<div className='flex items-center py-[1px] gap-1 grow'>
|
<div className='flex items-center py-[1px] gap-1 grow'>
|
||||||
<ModelIcon
|
<ModelIcon
|
||||||
className="m-0.5 w-4 h-4"
|
className="w-4 h-4"
|
||||||
provider={currentProvider}
|
provider={currentProvider}
|
||||||
modelName={modelName}
|
modelName={modelName}
|
||||||
/>
|
/>
|
||||||
|
@ -11,7 +11,7 @@ import Placeholder from './base/placeholder'
|
|||||||
import cn from '@/utils/classnames'
|
import cn from '@/utils/classnames'
|
||||||
import { useGetLanguage } from '@/context/i18n'
|
import { useGetLanguage } from '@/context/i18n'
|
||||||
import { getLanguage } from '@/i18n/language'
|
import { getLanguage } from '@/i18n/language'
|
||||||
import { useCategories } from '../hooks'
|
import { useSingleCategories } from '../hooks'
|
||||||
import { renderI18nObject } from '@/hooks/use-i18n'
|
import { renderI18nObject } from '@/hooks/use-i18n'
|
||||||
|
|
||||||
export type Props = {
|
export type Props = {
|
||||||
@ -43,7 +43,7 @@ const Card = ({
|
|||||||
}: Props) => {
|
}: Props) => {
|
||||||
const defaultLocale = useGetLanguage()
|
const defaultLocale = useGetLanguage()
|
||||||
const locale = localeFromProps ? getLanguage(localeFromProps) : defaultLocale
|
const locale = localeFromProps ? getLanguage(localeFromProps) : defaultLocale
|
||||||
const { categoriesMap } = useCategories()
|
const { categoriesMap } = useSingleCategories()
|
||||||
const { category, type, name, org, label, brief, icon, verified } = payload
|
const { category, type, name, org, label, brief, icon, verified } = payload
|
||||||
const isBundle = !['plugin', 'model', 'tool', 'extension', 'agent_strategy'].includes(type)
|
const isBundle = !['plugin', 'model', 'tool', 'extension', 'agent_strategy'].includes(type)
|
||||||
const cornerMark = isBundle ? categoriesMap.bundle?.label : categoriesMap[category]?.label
|
const cornerMark = isBundle ? categoriesMap.bundle?.label : categoriesMap[category]?.label
|
||||||
|
@ -64,3 +64,31 @@ export const useCategories = (translateFromOut?: TFunction) => {
|
|||||||
categoriesMap,
|
categoriesMap,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const useSingleCategories = (translateFromOut?: TFunction) => {
|
||||||
|
const { t: translation } = useTranslation()
|
||||||
|
const t = translateFromOut || translation
|
||||||
|
|
||||||
|
const categories = categoryKeys.map((category) => {
|
||||||
|
if (category === 'agent') {
|
||||||
|
return {
|
||||||
|
name: 'agent_strategy',
|
||||||
|
label: t(`plugin.categorySingle.${category}`),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
name: category,
|
||||||
|
label: t(`plugin.categorySingle.${category}`),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const categoriesMap = categories.reduce((acc, category) => {
|
||||||
|
acc[category.name] = category
|
||||||
|
return acc
|
||||||
|
}, {} as Record<string, Category>)
|
||||||
|
|
||||||
|
return {
|
||||||
|
categories,
|
||||||
|
categoriesMap,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -12,6 +12,7 @@ import { useInstallPackageFromMarketPlace, useUpdatePackageFromMarketPlace } fro
|
|||||||
import checkTaskStatus from '../../base/check-task-status'
|
import checkTaskStatus from '../../base/check-task-status'
|
||||||
import useCheckInstalled from '@/app/components/plugins/install-plugin/hooks/use-check-installed'
|
import useCheckInstalled from '@/app/components/plugins/install-plugin/hooks/use-check-installed'
|
||||||
import Version from '../../base/version'
|
import Version from '../../base/version'
|
||||||
|
import { usePluginTaskList } from '@/service/use-plugins'
|
||||||
|
|
||||||
const i18nPrefix = 'plugin.installModal'
|
const i18nPrefix = 'plugin.installModal'
|
||||||
|
|
||||||
@ -50,6 +51,7 @@ const Installed: FC<Props> = ({
|
|||||||
check,
|
check,
|
||||||
stop,
|
stop,
|
||||||
} = checkTaskStatus()
|
} = checkTaskStatus()
|
||||||
|
const { handleRefetch } = usePluginTaskList()
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (hasInstalled && uniqueIdentifier === installedInfoPayload.uniqueIdentifier)
|
if (hasInstalled && uniqueIdentifier === installedInfoPayload.uniqueIdentifier)
|
||||||
@ -93,6 +95,9 @@ const Installed: FC<Props> = ({
|
|||||||
onInstalled()
|
onInstalled()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handleRefetch()
|
||||||
|
|
||||||
const { status, error } = await check({
|
const { status, error } = await check({
|
||||||
taskId,
|
taskId,
|
||||||
pluginUniqueIdentifier: uniqueIdentifier,
|
pluginUniqueIdentifier: uniqueIdentifier,
|
||||||
|
@ -22,7 +22,7 @@ import cn from '@/utils/classnames'
|
|||||||
import { API_PREFIX, MARKETPLACE_URL_PREFIX } from '@/config'
|
import { API_PREFIX, MARKETPLACE_URL_PREFIX } from '@/config'
|
||||||
import { useInvalidateInstalledPluginList } from '@/service/use-plugins'
|
import { useInvalidateInstalledPluginList } from '@/service/use-plugins'
|
||||||
import { useInvalidateAllBuiltInTools, useInvalidateAllToolProviders } from '@/service/use-tools'
|
import { useInvalidateAllBuiltInTools, useInvalidateAllToolProviders } from '@/service/use-tools'
|
||||||
import { useCategories } from '../hooks'
|
import { useSingleCategories } from '../hooks'
|
||||||
import { useProviderContext } from '@/context/provider-context'
|
import { useProviderContext } from '@/context/provider-context'
|
||||||
import { useRenderI18nObject } from '@/hooks/use-i18n'
|
import { useRenderI18nObject } from '@/hooks/use-i18n'
|
||||||
|
|
||||||
@ -36,7 +36,7 @@ const PluginItem: FC<Props> = ({
|
|||||||
plugin,
|
plugin,
|
||||||
}) => {
|
}) => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const { categoriesMap } = useCategories()
|
const { categoriesMap } = useSingleCategories()
|
||||||
const currentPluginID = usePluginPageContext(v => v.currentPluginID)
|
const currentPluginID = usePluginPageContext(v => v.currentPluginID)
|
||||||
const setCurrentPluginID = usePluginPageContext(v => v.setCurrentPluginID)
|
const setCurrentPluginID = usePluginPageContext(v => v.setCurrentPluginID)
|
||||||
const invalidateInstalledPluginList = useInvalidateInstalledPluginList()
|
const invalidateInstalledPluginList = useInvalidateInstalledPluginList()
|
||||||
|
@ -8,14 +8,15 @@ import type { UseMutationResult } from '@tanstack/react-query'
|
|||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
plugin: Plugin
|
plugin: Plugin
|
||||||
onSave: () => void
|
|
||||||
onCancel: () => void
|
onCancel: () => void
|
||||||
mutation: UseMutationResult
|
mutation: Pick<UseMutationResult, 'isSuccess' | 'isPending'>
|
||||||
|
mutate: () => void
|
||||||
confirmButtonText: ReactNode
|
confirmButtonText: ReactNode
|
||||||
cancelButtonText: ReactNode
|
cancelButtonText: ReactNode
|
||||||
modelTitle: ReactNode
|
modelTitle: ReactNode
|
||||||
description: ReactNode
|
description: ReactNode
|
||||||
cardTitleLeft: ReactNode
|
cardTitleLeft: ReactNode
|
||||||
|
modalBottomLeft?: ReactNode
|
||||||
}
|
}
|
||||||
|
|
||||||
const PluginMutationModal: FC<Props> = ({
|
const PluginMutationModal: FC<Props> = ({
|
||||||
@ -27,6 +28,8 @@ const PluginMutationModal: FC<Props> = ({
|
|||||||
modelTitle,
|
modelTitle,
|
||||||
description,
|
description,
|
||||||
cardTitleLeft,
|
cardTitleLeft,
|
||||||
|
mutate,
|
||||||
|
modalBottomLeft,
|
||||||
}: Props) => {
|
}: Props) => {
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
@ -47,20 +50,25 @@ const PluginMutationModal: FC<Props> = ({
|
|||||||
titleLeft={cardTitleLeft}
|
titleLeft={cardTitleLeft}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className='flex pt-5 justify-end items-center gap-2 self-stretch'>
|
<div className='flex pt-5 items-center gap-2 self-stretch'>
|
||||||
{mutation.isPending && (
|
<div>
|
||||||
<Button onClick={onCancel}>
|
{modalBottomLeft}
|
||||||
{cancelButtonText}
|
</div>
|
||||||
|
<div className='ml-auto flex gap-2'>
|
||||||
|
{!mutation.isPending && (
|
||||||
|
<Button onClick={onCancel}>
|
||||||
|
{cancelButtonText}
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
<Button
|
||||||
|
variant='primary'
|
||||||
|
loading={mutation.isPending}
|
||||||
|
onClick={mutate}
|
||||||
|
disabled={mutation.isPending}
|
||||||
|
>
|
||||||
|
{confirmButtonText}
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
</div>
|
||||||
<Button
|
|
||||||
variant='primary'
|
|
||||||
loading={mutation.isPending}
|
|
||||||
onClick={mutation.mutate}
|
|
||||||
disabled={mutation.isPending}
|
|
||||||
>
|
|
||||||
{confirmButtonText}
|
|
||||||
</Button>
|
|
||||||
</div>
|
</div>
|
||||||
</Modal>
|
</Modal>
|
||||||
)
|
)
|
||||||
|
@ -404,6 +404,7 @@ export const SUPPORT_OUTPUT_VARS_NODE = [
|
|||||||
BlockEnum.HttpRequest, BlockEnum.Tool, BlockEnum.VariableAssigner, BlockEnum.VariableAggregator, BlockEnum.QuestionClassifier,
|
BlockEnum.HttpRequest, BlockEnum.Tool, BlockEnum.VariableAssigner, BlockEnum.VariableAggregator, BlockEnum.QuestionClassifier,
|
||||||
BlockEnum.ParameterExtractor, BlockEnum.Iteration,
|
BlockEnum.ParameterExtractor, BlockEnum.Iteration,
|
||||||
BlockEnum.DocExtractor, BlockEnum.ListFilter,
|
BlockEnum.DocExtractor, BlockEnum.ListFilter,
|
||||||
|
BlockEnum.Agent,
|
||||||
]
|
]
|
||||||
|
|
||||||
export const LLM_OUTPUT_STRUCT: Var[] = [
|
export const LLM_OUTPUT_STRUCT: Var[] = [
|
||||||
|
@ -3,13 +3,19 @@
|
|||||||
import Badge from '@/app/components/base/badge'
|
import Badge from '@/app/components/base/badge'
|
||||||
import Tooltip from '@/app/components/base/tooltip'
|
import Tooltip from '@/app/components/base/tooltip'
|
||||||
import PluginVersionPicker from '@/app/components/plugins/update-plugin/plugin-version-picker'
|
import PluginVersionPicker from '@/app/components/plugins/update-plugin/plugin-version-picker'
|
||||||
import { RiArrowLeftRightLine } from '@remixicon/react'
|
import { RiArrowLeftRightLine, RiExternalLinkLine } from '@remixicon/react'
|
||||||
import type { ReactNode } from 'react'
|
import type { ReactNode } from 'react'
|
||||||
import { type FC, useCallback, useState } from 'react'
|
import { type FC, useCallback, useState } from 'react'
|
||||||
import UpdateFromMarketplace from '@/app/components/plugins/update-plugin/from-market-place'
|
|
||||||
import { useBoolean } from 'ahooks'
|
import { useBoolean } from 'ahooks'
|
||||||
import { useCheckInstalled } from '@/service/use-plugins'
|
import { useCheckInstalled, useUpdatePackageFromMarketPlace } from '@/service/use-plugins'
|
||||||
import cn from '@/utils/classnames'
|
import cn from '@/utils/classnames'
|
||||||
|
import PluginMutationModel from '@/app/components/plugins/plugin-mutation-model'
|
||||||
|
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 { marketplaceUrlPrefix } from '@/config'
|
||||||
|
|
||||||
export type SwitchPluginVersionProps = {
|
export type SwitchPluginVersionProps = {
|
||||||
uniqueIdentifier: string
|
uniqueIdentifier: string
|
||||||
@ -23,7 +29,10 @@ export const SwitchPluginVersion: FC<SwitchPluginVersionProps> = (props) => {
|
|||||||
const [pluginId] = uniqueIdentifier.split(':')
|
const [pluginId] = uniqueIdentifier.split(':')
|
||||||
const [isShow, setIsShow] = useState(false)
|
const [isShow, setIsShow] = useState(false)
|
||||||
const [isShowUpdateModal, { setTrue: showUpdateModal, setFalse: hideUpdateModal }] = useBoolean(false)
|
const [isShowUpdateModal, { setTrue: showUpdateModal, setFalse: hideUpdateModal }] = useBoolean(false)
|
||||||
const [targetVersion, setTargetVersion] = useState<string>()
|
const [target, setTarget] = useState<{
|
||||||
|
version: string,
|
||||||
|
pluginUniqueIden: string;
|
||||||
|
}>()
|
||||||
const pluginDetails = useCheckInstalled({
|
const pluginDetails = useCheckInstalled({
|
||||||
pluginIds: [pluginId],
|
pluginIds: [pluginId],
|
||||||
enabled: true,
|
enabled: true,
|
||||||
@ -33,28 +42,55 @@ export const SwitchPluginVersion: FC<SwitchPluginVersionProps> = (props) => {
|
|||||||
const handleUpdatedFromMarketplace = useCallback(() => {
|
const handleUpdatedFromMarketplace = useCallback(() => {
|
||||||
hideUpdateModal()
|
hideUpdateModal()
|
||||||
pluginDetails.refetch()
|
pluginDetails.refetch()
|
||||||
onChange?.(targetVersion!)
|
onChange?.(target!.version)
|
||||||
}, [hideUpdateModal, onChange, pluginDetails, targetVersion])
|
}, [hideUpdateModal, onChange, pluginDetails, target])
|
||||||
|
const { getIconUrl } = useGetIcon()
|
||||||
const targetUniqueIdentifier = (() => {
|
const icon = pluginDetail?.declaration.icon ? getIconUrl(pluginDetail.declaration.icon) : undefined
|
||||||
if (!targetVersion || !pluginDetail) return uniqueIdentifier
|
const mutation = useUpdatePackageFromMarketPlace()
|
||||||
return uniqueIdentifier.replaceAll(pluginDetail.version, targetVersion)
|
const install = () => {
|
||||||
})()
|
mutation.mutate(
|
||||||
|
{
|
||||||
|
new_plugin_unique_identifier: target!.pluginUniqueIden,
|
||||||
|
original_plugin_unique_identifier: uniqueIdentifier,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
onSuccess() {
|
||||||
|
handleUpdatedFromMarketplace()
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const { t } = useTranslation()
|
||||||
return <Tooltip popupContent={!isShow && !isShowUpdateModal && tooltip} triggerMethod='hover'>
|
return <Tooltip popupContent={!isShow && !isShowUpdateModal && tooltip} triggerMethod='hover'>
|
||||||
<div className={cn('w-fit', className)}>
|
<div className={cn('w-fit flex items-center justify-center', className)}>
|
||||||
{isShowUpdateModal && pluginDetail && <UpdateFromMarketplace
|
{isShowUpdateModal && pluginDetail && <PluginMutationModel
|
||||||
payload={{
|
|
||||||
originalPackageInfo: {
|
|
||||||
id: uniqueIdentifier,
|
|
||||||
payload: pluginDetail.declaration,
|
|
||||||
},
|
|
||||||
targetPackageInfo: {
|
|
||||||
id: targetUniqueIdentifier,
|
|
||||||
version: targetVersion!,
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
onCancel={hideUpdateModal}
|
onCancel={hideUpdateModal}
|
||||||
onSave={handleUpdatedFromMarketplace}
|
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 justify-center items-center gap-1'
|
||||||
|
href={`${marketplaceUrlPrefix}/plugins/${pluginDetail.declaration.author}/${pluginDetail.declaration.name}`}
|
||||||
|
target='_blank'
|
||||||
|
>
|
||||||
|
<span className='text-text-accent system-xs-regular text-xs'>
|
||||||
|
{t('workflow.nodes.agent.installPlugin.changelog')}
|
||||||
|
</span>
|
||||||
|
<RiExternalLinkLine className='text-text-accent size-3' />
|
||||||
|
</Link>
|
||||||
|
}
|
||||||
/>}
|
/>}
|
||||||
{pluginDetail && <PluginVersionPicker
|
{pluginDetail && <PluginVersionPicker
|
||||||
isShow={isShow}
|
isShow={isShow}
|
||||||
@ -62,7 +98,10 @@ export const SwitchPluginVersion: FC<SwitchPluginVersionProps> = (props) => {
|
|||||||
pluginID={pluginId}
|
pluginID={pluginId}
|
||||||
currentVersion={pluginDetail.version}
|
currentVersion={pluginDetail.version}
|
||||||
onSelect={(state) => {
|
onSelect={(state) => {
|
||||||
setTargetVersion(state.version)
|
setTarget({
|
||||||
|
pluginUniqueIden: state.unique_identifier,
|
||||||
|
version: state.version,
|
||||||
|
})
|
||||||
showUpdateModal()
|
showUpdateModal()
|
||||||
}}
|
}}
|
||||||
trigger={
|
trigger={
|
||||||
|
@ -319,16 +319,13 @@ const formatItem = (
|
|||||||
case BlockEnum.Agent: {
|
case BlockEnum.Agent: {
|
||||||
const payload = data as AgentNodeType
|
const payload = data as AgentNodeType
|
||||||
const outputs: Var[] = []
|
const outputs: Var[] = []
|
||||||
Object.keys(payload.output_schema.properties).forEach((outputKey) => {
|
Object.keys(payload.output_schema?.properties || {}).forEach((outputKey) => {
|
||||||
const output = payload.output_schema.properties[outputKey]
|
const output = payload.output_schema.properties[outputKey]
|
||||||
outputs.push({
|
outputs.push({
|
||||||
variable: outputKey,
|
variable: outputKey,
|
||||||
type: output.type === 'array'
|
type: output.type === 'array'
|
||||||
? `Array[${output.items?.type.slice(0, 1).toLocaleUpperCase()}${output.items?.type.slice(1)}]` as VarType
|
? `Array[${output.items?.type.slice(0, 1).toLocaleUpperCase()}${output.items?.type.slice(1)}]` as VarType
|
||||||
: `${output.type.slice(0, 1).toLocaleUpperCase()}${output.type.slice(1)}` as VarType,
|
: `${output.type.slice(0, 1).toLocaleUpperCase()}${output.type.slice(1)}` as VarType,
|
||||||
// TODO: is this required?
|
|
||||||
// @ts-expect-error todo added
|
|
||||||
description: output.description,
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
res.vars = [
|
res.vars = [
|
||||||
|
@ -26,7 +26,7 @@ const nodeDefault: NodeDefault<AgentNodeType> = {
|
|||||||
if (!strategy) {
|
if (!strategy) {
|
||||||
return {
|
return {
|
||||||
isValid: false,
|
isValid: false,
|
||||||
errorMessage: t('workflow.checkList.strategyNotSelected'),
|
errorMessage: t('workflow.nodes.agent.checkList.strategyNotSelected'),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (const param of strategy.parameters) {
|
for (const param of strategy.parameters) {
|
||||||
|
@ -28,7 +28,7 @@ import {
|
|||||||
import { useStore as useAppStore } from '@/app/components/app/store'
|
import { useStore as useAppStore } from '@/app/components/app/store'
|
||||||
import { getLastAnswer } from '@/app/components/base/chat/utils'
|
import { getLastAnswer } from '@/app/components/base/chat/utils'
|
||||||
|
|
||||||
interface ChatWrapperProps {
|
type ChatWrapperProps = {
|
||||||
showConversationVariableModal: boolean
|
showConversationVariableModal: boolean
|
||||||
onConversationModalHide: () => void
|
onConversationModalHide: () => void
|
||||||
showInputsFieldsPanel: boolean
|
showInputsFieldsPanel: boolean
|
||||||
|
@ -27,10 +27,9 @@ import {
|
|||||||
getProcessedFilesFromResponse,
|
getProcessedFilesFromResponse,
|
||||||
} from '@/app/components/base/file-uploader/utils'
|
} from '@/app/components/base/file-uploader/utils'
|
||||||
import type { FileEntity } from '@/app/components/base/file-uploader/types'
|
import type { FileEntity } from '@/app/components/base/file-uploader/types'
|
||||||
import type { NodeTracing } from '@/types/workflow'
|
|
||||||
|
|
||||||
type GetAbortController = (abortController: AbortController) => void
|
type GetAbortController = (abortController: AbortController) => void
|
||||||
interface SendCallback {
|
type SendCallback = {
|
||||||
onGetSuggestedQuestions?: (responseItemId: string, getAbortController: GetAbortController) => Promise<any>
|
onGetSuggestedQuestions?: (responseItemId: string, getAbortController: GetAbortController) => Promise<any>
|
||||||
}
|
}
|
||||||
export const useChat = (
|
export const useChat = (
|
||||||
@ -276,6 +275,7 @@ export const useChat = (
|
|||||||
)
|
)
|
||||||
setSuggestQuestions(data)
|
setSuggestQuestions(data)
|
||||||
}
|
}
|
||||||
|
// eslint-disable-next-line unused-imports/no-unused-vars
|
||||||
catch (error) {
|
catch (error) {
|
||||||
setSuggestQuestions([])
|
setSuggestQuestions([])
|
||||||
}
|
}
|
||||||
@ -331,8 +331,7 @@ export const useChat = (
|
|||||||
responseItem.workflowProcess!.tracing!.push({
|
responseItem.workflowProcess!.tracing!.push({
|
||||||
...data,
|
...data,
|
||||||
status: NodeRunningStatus.Running,
|
status: NodeRunningStatus.Running,
|
||||||
details: [],
|
})
|
||||||
} as any)
|
|
||||||
handleUpdateChatList(produce(chatListRef.current, (draft) => {
|
handleUpdateChatList(produce(chatListRef.current, (draft) => {
|
||||||
const currentIndex = draft.findIndex(item => item.id === responseItem.id)
|
const currentIndex = draft.findIndex(item => item.id === responseItem.id)
|
||||||
draft[currentIndex] = {
|
draft[currentIndex] = {
|
||||||
@ -341,30 +340,21 @@ export const useChat = (
|
|||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
},
|
},
|
||||||
onIterationNext: ({ data }) => {
|
|
||||||
const tracing = responseItem.workflowProcess!.tracing!
|
|
||||||
const iterations = tracing.find(item => item.node_id === data.node_id
|
|
||||||
&& (item.execution_metadata?.parallel_id === data.execution_metadata?.parallel_id || item.parallel_id === data.execution_metadata?.parallel_id))!
|
|
||||||
iterations.details!.push([])
|
|
||||||
|
|
||||||
handleUpdateChatList(produce(chatListRef.current, (draft) => {
|
|
||||||
const currentIndex = draft.length - 1
|
|
||||||
draft[currentIndex] = responseItem
|
|
||||||
}))
|
|
||||||
},
|
|
||||||
onIterationFinish: ({ data }) => {
|
onIterationFinish: ({ data }) => {
|
||||||
const tracing = responseItem.workflowProcess!.tracing!
|
const currentTracingIndex = responseItem.workflowProcess!.tracing!.findIndex(item => item.id === data.id)
|
||||||
const iterationsIndex = tracing.findIndex(item => item.node_id === data.node_id
|
if (currentTracingIndex > -1) {
|
||||||
&& (item.execution_metadata?.parallel_id === data.execution_metadata?.parallel_id || item.parallel_id === data.execution_metadata?.parallel_id))!
|
responseItem.workflowProcess!.tracing[currentTracingIndex] = {
|
||||||
tracing[iterationsIndex] = {
|
...responseItem.workflowProcess!.tracing[currentTracingIndex],
|
||||||
...tracing[iterationsIndex],
|
...data,
|
||||||
...data,
|
}
|
||||||
status: NodeRunningStatus.Succeeded,
|
handleUpdateChatList(produce(chatListRef.current, (draft) => {
|
||||||
} as any
|
const currentIndex = draft.findIndex(item => item.id === responseItem.id)
|
||||||
handleUpdateChatList(produce(chatListRef.current, (draft) => {
|
draft[currentIndex] = {
|
||||||
const currentIndex = draft.length - 1
|
...draft[currentIndex],
|
||||||
draft[currentIndex] = responseItem
|
...responseItem,
|
||||||
}))
|
}
|
||||||
|
}))
|
||||||
|
}
|
||||||
},
|
},
|
||||||
onNodeStarted: ({ data }) => {
|
onNodeStarted: ({ data }) => {
|
||||||
if (data.iteration_id)
|
if (data.iteration_id)
|
||||||
@ -386,16 +376,7 @@ export const useChat = (
|
|||||||
if (data.iteration_id)
|
if (data.iteration_id)
|
||||||
return
|
return
|
||||||
|
|
||||||
const currentIndex = responseItem.workflowProcess!.tracing!.findIndex((item) => {
|
responseItem.workflowProcess!.tracing!.push(data)
|
||||||
if (!item.execution_metadata?.parallel_id)
|
|
||||||
return item.node_id === data.node_id
|
|
||||||
return item.node_id === data.node_id && (item.execution_metadata?.parallel_id === data.execution_metadata?.parallel_id || item.parallel_id === data.execution_metadata?.parallel_id)
|
|
||||||
})
|
|
||||||
if (responseItem.workflowProcess!.tracing[currentIndex].retryDetail)
|
|
||||||
responseItem.workflowProcess!.tracing[currentIndex].retryDetail?.push(data as NodeTracing)
|
|
||||||
else
|
|
||||||
responseItem.workflowProcess!.tracing[currentIndex].retryDetail = [data as NodeTracing]
|
|
||||||
|
|
||||||
handleUpdateChatList(produce(chatListRef.current, (draft) => {
|
handleUpdateChatList(produce(chatListRef.current, (draft) => {
|
||||||
const currentIndex = draft.findIndex(item => item.id === responseItem.id)
|
const currentIndex = draft.findIndex(item => item.id === responseItem.id)
|
||||||
draft[currentIndex] = {
|
draft[currentIndex] = {
|
||||||
@ -408,27 +389,20 @@ export const useChat = (
|
|||||||
if (data.iteration_id)
|
if (data.iteration_id)
|
||||||
return
|
return
|
||||||
|
|
||||||
const currentIndex = responseItem.workflowProcess!.tracing!.findIndex((item) => {
|
const currentTracingIndex = responseItem.workflowProcess!.tracing!.findIndex(item => item.id === data.id)
|
||||||
if (!item.execution_metadata?.parallel_id)
|
if (currentTracingIndex > -1) {
|
||||||
return item.node_id === data.node_id
|
responseItem.workflowProcess!.tracing[currentTracingIndex] = {
|
||||||
return item.node_id === data.node_id && (item.execution_metadata?.parallel_id === data.execution_metadata?.parallel_id || item.parallel_id === data.execution_metadata?.parallel_id)
|
...responseItem.workflowProcess!.tracing[currentTracingIndex],
|
||||||
})
|
...data,
|
||||||
responseItem.workflowProcess!.tracing[currentIndex] = {
|
|
||||||
...(responseItem.workflowProcess!.tracing[currentIndex]?.extras
|
|
||||||
? { extras: responseItem.workflowProcess!.tracing[currentIndex].extras }
|
|
||||||
: {}),
|
|
||||||
...(responseItem.workflowProcess!.tracing[currentIndex]?.retryDetail
|
|
||||||
? { retryDetail: responseItem.workflowProcess!.tracing[currentIndex].retryDetail }
|
|
||||||
: {}),
|
|
||||||
...data,
|
|
||||||
} as any
|
|
||||||
handleUpdateChatList(produce(chatListRef.current, (draft) => {
|
|
||||||
const currentIndex = draft.findIndex(item => item.id === responseItem.id)
|
|
||||||
draft[currentIndex] = {
|
|
||||||
...draft[currentIndex],
|
|
||||||
...responseItem,
|
|
||||||
}
|
}
|
||||||
}))
|
handleUpdateChatList(produce(chatListRef.current, (draft) => {
|
||||||
|
const currentIndex = draft.findIndex(item => item.id === responseItem.id)
|
||||||
|
draft[currentIndex] = {
|
||||||
|
...draft[currentIndex],
|
||||||
|
...responseItem,
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
@ -22,7 +22,7 @@ import Tooltip from '@/app/components/base/tooltip'
|
|||||||
import ActionButton, { ActionButtonState } from '@/app/components/base/action-button'
|
import ActionButton, { ActionButtonState } from '@/app/components/base/action-button'
|
||||||
import { useStore } from '@/app/components/workflow/store'
|
import { useStore } from '@/app/components/workflow/store'
|
||||||
|
|
||||||
export interface ChatWrapperRefType {
|
export type ChatWrapperRefType = {
|
||||||
handleRestart: () => void
|
handleRestart: () => void
|
||||||
}
|
}
|
||||||
const DebugAndPreview = () => {
|
const DebugAndPreview = () => {
|
||||||
|
@ -24,7 +24,6 @@ import Toast from '../../base/toast'
|
|||||||
import InputsPanel from './inputs-panel'
|
import InputsPanel from './inputs-panel'
|
||||||
import cn from '@/utils/classnames'
|
import cn from '@/utils/classnames'
|
||||||
import Loading from '@/app/components/base/loading'
|
import Loading from '@/app/components/base/loading'
|
||||||
import formatNodeList from '@/app/components/workflow/run/utils/format-log'
|
|
||||||
|
|
||||||
const WorkflowPreview = () => {
|
const WorkflowPreview = () => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
@ -161,7 +160,7 @@ const WorkflowPreview = () => {
|
|||||||
{currentTab === 'TRACING' && (
|
{currentTab === 'TRACING' && (
|
||||||
<TracingPanel
|
<TracingPanel
|
||||||
className='bg-background-section-burn'
|
className='bg-background-section-burn'
|
||||||
list={formatNodeList(workflowRunningData?.tracing || [], t)}
|
list={workflowRunningData?.tracing || []}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{currentTab === 'TRACING' && !workflowRunningData?.tracing?.length && (
|
{currentTab === 'TRACING' && !workflowRunningData?.tracing?.length && (
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
import { useCallback } from 'react'
|
import { useCallback } from 'react'
|
||||||
import { useStore as usePluginDependenciesStore } from './store'
|
import { useStore as usePluginDependenciesStore } from './store'
|
||||||
import { useMutationCheckDependecies } from '@/service/use-plugins'
|
import { useMutationCheckDependencies } from '@/service/use-plugins'
|
||||||
|
|
||||||
export const usePluginDependencies = () => {
|
export const usePluginDependencies = () => {
|
||||||
const { mutateAsync } = useMutationCheckDependecies()
|
const { mutateAsync } = useMutationCheckDependencies()
|
||||||
|
|
||||||
const handleCheckPluginDependencies = useCallback(async (appId: string) => {
|
const handleCheckPluginDependencies = useCallback(async (appId: string) => {
|
||||||
const { leaked_dependencies } = await mutateAsync(appId)
|
const { leaked_dependencies } = await mutateAsync(appId)
|
||||||
|
@ -30,26 +30,26 @@ const AgentLogItem = ({
|
|||||||
<div className='border-[0.5px] border-components-panel-border rounded-[10px]'>
|
<div className='border-[0.5px] border-components-panel-border rounded-[10px]'>
|
||||||
<div
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
'flex items-center pl-1.5 pt-2 pr-3 pb-2',
|
'flex items-center pl-1.5 pt-2 pr-3 pb-2 cursor-pointer',
|
||||||
expanded && 'pb-1',
|
expanded && 'pb-1',
|
||||||
)}
|
)}
|
||||||
onClick={() => setExpanded(!expanded)}
|
onClick={() => setExpanded(!expanded)}
|
||||||
>
|
>
|
||||||
{
|
{
|
||||||
expanded
|
expanded
|
||||||
? <RiArrowRightSLine className='shrink-0 w-4 h-4 rotate-90' />
|
? <RiArrowRightSLine className='shrink-0 w-4 h-4 rotate-90 text-text-quaternary' />
|
||||||
: <RiArrowRightSLine className='shrink-0 w-4 h-4' />
|
: <RiArrowRightSLine className='shrink-0 w-4 h-4 text-text-quaternary' />
|
||||||
}
|
}
|
||||||
<div className='shrink-0 mr-1.5 w-5 h-5'></div>
|
<div className='shrink-0 mr-1.5 w-5 h-5'></div>
|
||||||
<div className='grow system-sm-semibold-uppercase text-text-secondary truncate'>{label}</div>
|
<div className='grow system-sm-semibold-uppercase text-text-secondary truncate'>{label}</div>
|
||||||
<div className='shrink-0 mr-2 system-xs-regular text-text-tertiary'>0.02s</div>
|
{/* <div className='shrink-0 mr-2 system-xs-regular text-text-tertiary'>0.02s</div> */}
|
||||||
<NodeStatusIcon status={status} />
|
<NodeStatusIcon status={status} />
|
||||||
</div>
|
</div>
|
||||||
{
|
{
|
||||||
expanded && (
|
expanded && (
|
||||||
<div className='p-1 pt-0'>
|
<div className='p-1 pt-0'>
|
||||||
{
|
{
|
||||||
!!children.length && (
|
!!children?.length && (
|
||||||
<Button
|
<Button
|
||||||
className='flex items-center justify-between mb-1 w-full'
|
className='flex items-center justify-between mb-1 w-full'
|
||||||
variant='tertiary'
|
variant='tertiary'
|
||||||
|
@ -19,7 +19,9 @@ const AgentLogNav = ({
|
|||||||
className='shrink-0 px-[5px]'
|
className='shrink-0 px-[5px]'
|
||||||
size='small'
|
size='small'
|
||||||
variant='ghost-accent'
|
variant='ghost-accent'
|
||||||
onClick={() => onShowAgentOrToolLog()}
|
onClick={() => {
|
||||||
|
onShowAgentOrToolLog()
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<RiArrowLeftLine className='mr-1 w-3.5 h-3.5' />
|
<RiArrowLeftLine className='mr-1 w-3.5 h-3.5' />
|
||||||
Agent
|
Agent
|
||||||
@ -31,7 +33,6 @@ const AgentLogNav = ({
|
|||||||
variant='ghost-accent'
|
variant='ghost-accent'
|
||||||
onClick={() => {}}
|
onClick={() => {}}
|
||||||
>
|
>
|
||||||
<RiArrowLeftLine className='mr-1 w-3.5 h-3.5' />
|
|
||||||
Agent strategy
|
Agent strategy
|
||||||
</Button>
|
</Button>
|
||||||
{
|
{
|
||||||
|
@ -24,7 +24,9 @@ const AgentLogTrigger = ({
|
|||||||
<div className='grow mx-0.5 px-1 system-xs-medium text-text-secondary'></div>
|
<div className='grow mx-0.5 px-1 system-xs-medium text-text-secondary'></div>
|
||||||
<div
|
<div
|
||||||
className='shrink-0 flex items-center px-[1px] system-xs-regular-uppercase text-text-tertiary cursor-pointer'
|
className='shrink-0 flex items-center px-[1px] system-xs-regular-uppercase text-text-tertiary cursor-pointer'
|
||||||
onClick={() => onShowAgentOrToolLog({ id: nodeInfo.id, children: agentLog || [] } as AgentLogItemWithChildren)}
|
onClick={() => {
|
||||||
|
onShowAgentOrToolLog({ id: nodeInfo.id, children: agentLog || [] } as AgentLogItemWithChildren)
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
Detail
|
Detail
|
||||||
<RiArrowRightLine className='ml-0.5 w-3.5 h-3.5' />
|
<RiArrowRightLine className='ml-0.5 w-3.5 h-3.5' />
|
||||||
|
@ -13,7 +13,6 @@ import { fetchRunDetail, fetchTracingList } from '@/service/log'
|
|||||||
import type { NodeTracing } from '@/types/workflow'
|
import type { NodeTracing } from '@/types/workflow'
|
||||||
import type { WorkflowRunDetailResponse } from '@/models/log'
|
import type { WorkflowRunDetailResponse } from '@/models/log'
|
||||||
import { useStore as useAppStore } from '@/app/components/app/store'
|
import { useStore as useAppStore } from '@/app/components/app/store'
|
||||||
import formatNodeList from './utils/format-log'
|
|
||||||
export type RunProps = {
|
export type RunProps = {
|
||||||
hideResult?: boolean
|
hideResult?: boolean
|
||||||
activeTab?: 'RESULT' | 'DETAIL' | 'TRACING'
|
activeTab?: 'RESULT' | 'DETAIL' | 'TRACING'
|
||||||
@ -61,7 +60,7 @@ const RunPanel: FC<RunProps> = ({ hideResult, activeTab = 'RESULT', runID, getRe
|
|||||||
const { data: nodeList } = await fetchTracingList({
|
const { data: nodeList } = await fetchTracingList({
|
||||||
url: `/apps/${appID}/workflow-runs/${runID}/node-executions`,
|
url: `/apps/${appID}/workflow-runs/${runID}/node-executions`,
|
||||||
})
|
})
|
||||||
setList(formatNodeList(nodeList, t))
|
setList(nodeList)
|
||||||
}
|
}
|
||||||
catch (err) {
|
catch (err) {
|
||||||
notify({
|
notify({
|
||||||
|
@ -36,7 +36,10 @@ const SpecialResultPanel = ({
|
|||||||
handleShowAgentOrToolLog,
|
handleShowAgentOrToolLog,
|
||||||
}: SpecialResultPanelProps) => {
|
}: SpecialResultPanelProps) => {
|
||||||
return (
|
return (
|
||||||
<>
|
<div onClick={(e) => {
|
||||||
|
e.stopPropagation()
|
||||||
|
e.nativeEvent.stopImmediatePropagation()
|
||||||
|
}}>
|
||||||
{
|
{
|
||||||
!!showRetryDetail && !!retryResultList?.length && setShowRetryDetailFalse && (
|
!!showRetryDetail && !!retryResultList?.length && setShowRetryDetailFalse && (
|
||||||
<RetryResultPanel
|
<RetryResultPanel
|
||||||
@ -63,7 +66,7 @@ const SpecialResultPanel = ({
|
|||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
</>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,10 +11,12 @@ import {
|
|||||||
RiArrowDownSLine,
|
RiArrowDownSLine,
|
||||||
RiMenu4Line,
|
RiMenu4Line,
|
||||||
} from '@remixicon/react'
|
} from '@remixicon/react'
|
||||||
|
import { useTranslation } from 'react-i18next'
|
||||||
import { useLogs } from './hooks'
|
import { useLogs } from './hooks'
|
||||||
import NodePanel from './node'
|
import NodePanel from './node'
|
||||||
import SpecialResultPanel from './special-result-panel'
|
import SpecialResultPanel from './special-result-panel'
|
||||||
import type { NodeTracing } from '@/types/workflow'
|
import type { NodeTracing } from '@/types/workflow'
|
||||||
|
import formatNodeList from '@/app/components/workflow/run/utils/format-log'
|
||||||
|
|
||||||
type TracingPanelProps = {
|
type TracingPanelProps = {
|
||||||
list: NodeTracing[]
|
list: NodeTracing[]
|
||||||
@ -29,7 +31,8 @@ const TracingPanel: FC<TracingPanelProps> = ({
|
|||||||
hideNodeInfo = false,
|
hideNodeInfo = false,
|
||||||
hideNodeProcessDetail = false,
|
hideNodeProcessDetail = false,
|
||||||
}) => {
|
}) => {
|
||||||
const treeNodes = list
|
const { t } = useTranslation()
|
||||||
|
const treeNodes = formatNodeList(list, t)
|
||||||
const [collapsedNodes, setCollapsedNodes] = useState<Set<string>>(new Set())
|
const [collapsedNodes, setCollapsedNodes] = useState<Set<string>>(new Set())
|
||||||
const [hoveredParallel, setHoveredParallel] = useState<string | null>(null)
|
const [hoveredParallel, setHoveredParallel] = useState<string | null>(null)
|
||||||
|
|
||||||
@ -166,7 +169,13 @@ const TracingPanel: FC<TracingPanelProps> = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={cn(className || 'bg-components-panel-bg', 'py-2')}>
|
<div
|
||||||
|
className={cn(className || 'bg-components-panel-bg', 'py-2')}
|
||||||
|
onClick={(e) => {
|
||||||
|
e.stopPropagation()
|
||||||
|
e.nativeEvent.stopImmediatePropagation()
|
||||||
|
}}
|
||||||
|
>
|
||||||
{treeNodes.map(renderNode)}
|
{treeNodes.map(renderNode)}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
@ -3,10 +3,17 @@ const translation = {
|
|||||||
all: 'All',
|
all: 'All',
|
||||||
models: 'Models',
|
models: 'Models',
|
||||||
tools: 'Tools',
|
tools: 'Tools',
|
||||||
agents: 'Agent Strategy',
|
agents: 'Agent Strategies',
|
||||||
extensions: 'Extensions',
|
extensions: 'Extensions',
|
||||||
bundles: 'Bundles',
|
bundles: 'Bundles',
|
||||||
},
|
},
|
||||||
|
categorySingle: {
|
||||||
|
model: 'Model',
|
||||||
|
tool: 'Tool',
|
||||||
|
agent: 'Agent Strategy',
|
||||||
|
extension: 'Extension',
|
||||||
|
bundle: 'Bundle',
|
||||||
|
},
|
||||||
search: 'Search',
|
search: 'Search',
|
||||||
allCategories: 'All Categories',
|
allCategories: 'All Categories',
|
||||||
searchCategories: 'Search Categories',
|
searchCategories: 'Search Categories',
|
||||||
|
@ -725,6 +725,7 @@ const translation = {
|
|||||||
modelNotSupport: {
|
modelNotSupport: {
|
||||||
title: 'Unsupported Model',
|
title: 'Unsupported Model',
|
||||||
desc: 'The installed plugin version does not provide this model.',
|
desc: 'The installed plugin version does not provide this model.',
|
||||||
|
descForVersionSwitch: 'The installed plugin version does not provide this model. Click to switch version.',
|
||||||
},
|
},
|
||||||
configureModel: 'Configure Model',
|
configureModel: 'Configure Model',
|
||||||
notAuthorized: 'Not Authorized',
|
notAuthorized: 'Not Authorized',
|
||||||
@ -755,9 +756,16 @@ const translation = {
|
|||||||
},
|
},
|
||||||
json: 'agent generated json',
|
json: 'agent generated json',
|
||||||
},
|
},
|
||||||
},
|
checkList: {
|
||||||
checkList: {
|
strategyNotSelected: 'Strategy not selected',
|
||||||
strategyNotSelected: 'Strategy not selected',
|
},
|
||||||
|
installPlugin: {
|
||||||
|
title: 'Install Plugin',
|
||||||
|
desc: 'About to install the following plugin',
|
||||||
|
changelog: 'Change log',
|
||||||
|
install: 'Install',
|
||||||
|
cancel: 'Cancel',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
tracing: {
|
tracing: {
|
||||||
|
@ -7,6 +7,13 @@ const translation = {
|
|||||||
extensions: '扩展',
|
extensions: '扩展',
|
||||||
bundles: '插件集',
|
bundles: '插件集',
|
||||||
},
|
},
|
||||||
|
categorySingle: {
|
||||||
|
model: '模型',
|
||||||
|
tool: '工具',
|
||||||
|
agent: 'Agent 策略',
|
||||||
|
extension: '扩展',
|
||||||
|
bundle: '插件集',
|
||||||
|
},
|
||||||
search: '搜索',
|
search: '搜索',
|
||||||
allCategories: '所有类别',
|
allCategories: '所有类别',
|
||||||
searchCategories: '搜索类别',
|
searchCategories: '搜索类别',
|
||||||
|
@ -725,6 +725,7 @@ const translation = {
|
|||||||
modelNotSupport: {
|
modelNotSupport: {
|
||||||
title: '不支持的模型',
|
title: '不支持的模型',
|
||||||
desc: '已安装的插件版本不提供此模型。',
|
desc: '已安装的插件版本不提供此模型。',
|
||||||
|
descForVersionSwitch: '已安装的插件版本不提供此模型。点击切换版本。',
|
||||||
},
|
},
|
||||||
model: '模型',
|
model: '模型',
|
||||||
toolbox: '工具箱',
|
toolbox: '工具箱',
|
||||||
@ -758,6 +759,13 @@ const translation = {
|
|||||||
checkList: {
|
checkList: {
|
||||||
strategyNotSelected: '未选择策略',
|
strategyNotSelected: '未选择策略',
|
||||||
},
|
},
|
||||||
|
installPlugin: {
|
||||||
|
title: '安装插件',
|
||||||
|
desc: '即将安装以下插件',
|
||||||
|
changelog: '更新日志',
|
||||||
|
install: '安装',
|
||||||
|
cancel: '取消',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
tracing: {
|
tracing: {
|
||||||
|
@ -365,7 +365,7 @@ export const usePluginTaskList = () => {
|
|||||||
queryKey: usePluginTaskListKey,
|
queryKey: usePluginTaskListKey,
|
||||||
queryFn: async () => {
|
queryFn: async () => {
|
||||||
const currentData = await get<{ tasks: PluginTask[] }>('/workspaces/current/plugin/tasks?page=1&page_size=100')
|
const currentData = await get<{ tasks: PluginTask[] }>('/workspaces/current/plugin/tasks?page=1&page_size=100')
|
||||||
const taskDone = currentData.tasks.every(task => task.status === TaskStatus.success)
|
const taskDone = currentData.tasks.every(task => task.status === TaskStatus.success || task.status === TaskStatus.failed)
|
||||||
|
|
||||||
if (taskDone)
|
if (taskDone)
|
||||||
setEnabled(false)
|
setEnabled(false)
|
||||||
@ -423,10 +423,10 @@ export const useDownloadPlugin = (info: { organization: string; pluginName: stri
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useMutationCheckDependecies = () => {
|
export const useMutationCheckDependencies = () => {
|
||||||
return useMutation({
|
return useMutation({
|
||||||
mutationFn: (appId: string) => {
|
mutationFn: (appId: string) => {
|
||||||
return get<{ leaked_dependencies: Dependency[] }>(`/apps/import/${appId}/check-dependencies`)
|
return get<{ leaked_dependencies: Dependency[] }>(`/apps/imports/${appId}/check-dependencies`)
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,7 @@ export type NodeTracing = {
|
|||||||
index: number
|
index: number
|
||||||
predecessor_node_id: string
|
predecessor_node_id: string
|
||||||
node_id: string
|
node_id: string
|
||||||
|
iteration_id?: string
|
||||||
node_type: BlockEnum
|
node_type: BlockEnum
|
||||||
title: string
|
title: string
|
||||||
inputs: any
|
inputs: any
|
||||||
|
Loading…
Reference in New Issue
Block a user