Skip to content

Commit

Permalink
Merge branch 'feat/plugins' into dev/plugin-deploy
Browse files Browse the repository at this point in the history
  • Loading branch information
JzoNgKVO committed Dec 30, 2024
2 parents db1ad3c + 2007828 commit f6c1ae5
Show file tree
Hide file tree
Showing 23 changed files with 362 additions and 139 deletions.
27 changes: 27 additions & 0 deletions web/app/components/base/install-button/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import Button from '../button'
import { RiInstallLine, RiLoader2Line } from '@remixicon/react'

type InstallButtonProps = {
loading: boolean
onInstall: () => void
t: any
}

const InstallButton = ({ loading, onInstall, t }: InstallButtonProps) => {
return (
<Button size='small' className='z-[100]' onClick={onInstall}>
<div className={`flex px-[3px] justify-center items-center gap-1
${loading ? 'text-components-button-secondary-text-disabled' : 'text-components-button-secondary-text'}
system-xs-medium`}
>
{loading ? t('workflow.nodes.agent.pluginInstaller.installing') : t('workflow.nodes.agent.pluginInstaller.install')}
</div>
{loading
? <RiLoader2Line className='w-3.5 h-3.5 text-text-quaternary' />
: <RiInstallLine className='w-3.5 h-3.5 text-text-secondary' />
}
</Button>
)
}

export default InstallButton
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import type {
ModelProvider,
} from '../declarations'
import { useLanguage } from '../hooks'
import { CubeOutline } from '@/app/components/base/icons/src/vender/line/shapes'
import { Group } from '@/app/components/base/icons/src/vender/other'
import { OpenaiBlue, OpenaiViolet } from '@/app/components/base/icons/src/public/llm'
import cn from '@/utils/classnames'

Expand Down Expand Up @@ -41,10 +41,12 @@ const ModelIcon: FC<ModelIconProps> = ({

return (
<div className={cn(
'flex items-center justify-center w-6 h-6 rounded border-[0.5px] border-black/5 bg-gray-50',
'flex items-center justify-center w-5 h-5 rounded-md border-[0.5px] border-components-panel-border-subtle bg-background-default-subtle',
className,
)}>
<CubeOutline className='w-4 h-4 text-text-quaternary' />
<div className='flex w-3 h-3 items-center justify-center opacity-35'>
<Group className='text-text-tertiary' />
</div>
</div>
)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { FC } from 'react'
import { useEffect, useState } from 'react'
import { useTranslation } from 'react-i18next'
import type {
CustomConfigurationModelFixedFields,
Expand All @@ -10,20 +11,24 @@ import {
CustomConfigurationStatusEnum,
} from '../declarations'
import { UPDATE_MODEL_PROVIDER_CUSTOM_MODEL_LIST } from '../provider-added-card'
import { ModelStatusEnum } from '../declarations'
import type { PluginInfoFromMarketPlace } from '@/app/components/plugins/types'
import { useInstallPackageFromMarketPlace } from '@/service/use-plugins'
import ConfigurationButton from './configuration-button'
import { PluginType } from '@/app/components/plugins/types'
import {
useUpdateModelList,
useUpdateModelProviders,
} from '../hooks'
import ModelIcon from '../model-icon'
import ModelName from '../model-name'
import Button from '@/app/components/base/button'
import ModelDisplay from './model-display'
import InstallButton from '@/app/components/base/install-button'
import StatusIndicators from './status-indicators'
import cn from '@/utils/classnames'
import { useProviderContext } from '@/context/provider-context'
import { useModalContextSelector } from '@/context/modal-context'
import { useEventEmitterContextContext } from '@/context/event-emitter'
import Tooltip from '@/app/components/base/tooltip'
import { RiEqualizer2Line, RiErrorWarningFill } from '@remixicon/react'
import { RiEqualizer2Line } from '@remixicon/react'
import { fetchPluginInfoFromMarketPlace } from '@/service/plugins'

export type AgentModelTriggerProps = {
open?: boolean
Expand Down Expand Up @@ -56,6 +61,36 @@ const AgentModelTrigger: FC<AgentModelTriggerProps> = ({
item => item.quota_type === modelProvider.system_configuration.current_quota_type,
)
)
const [pluginInfo, setPluginInfo] = useState<PluginInfoFromMarketPlace | null>(null)
const [isPluginChecked, setIsPluginChecked] = useState(false)
const [loading, setLoading] = useState(false)
const [installed, setInstalled] = useState(false)
const { mutateAsync: installPackageFromMarketPlace } = useInstallPackageFromMarketPlace()

useEffect(() => {
(async () => {
if (providerName && !modelProvider) {
const parts = providerName.split('/')
const org = parts[0]
const name = parts[1]
try {
const pluginInfo = await fetchPluginInfoFromMarketPlace({ org, name })
if (pluginInfo.data.plugin.category === PluginType.model)
setPluginInfo(pluginInfo.data.plugin)
}
catch (error) {
// pass
}
setIsPluginChecked(true)
}
else {
setIsPluginChecked(true)
}
})()
}, [providerName, modelProvider])

if (modelId && !isPluginChecked)
return null

const handleOpenModal = (
provider: ModelProvider,
Expand Down Expand Up @@ -97,64 +132,41 @@ const AgentModelTrigger: FC<AgentModelTriggerProps> = ({
>
{modelId ? (
<>
{currentProvider && (
<ModelIcon
className="m-0.5"
provider={currentProvider}
modelName={currentModel?.model}
isDeprecated={hasDeprecated}
/>
)}
{!currentProvider && (
<ModelIcon
className="m-0.5"
provider={modelProvider}
modelName={modelId}
isDeprecated={hasDeprecated}
/>
)}
{currentModel && (
<ModelName
className="flex px-1 py-[3px] items-center gap-1 grow"
modelItem={currentModel}
showMode
showFeatures
<ModelIcon
className="m-0.5"
provider={currentProvider || modelProvider}
modelName={currentModel?.model || modelId}
isDeprecated={hasDeprecated}
/>
<ModelDisplay
currentModel={currentModel}
modelId={modelId}
/>
{needsConfiguration && (
<ConfigurationButton
modelProvider={modelProvider}
handleOpenModal={handleOpenModal}
/>
)}
{!currentModel && (
<div className="flex py-[3px] px-1 items-center gap-1 grow opacity-50 truncate">
<div className="text-components-input-text-filled text-ellipsis overflow-hidden system-sm-regular">
{modelId}
</div>
</div>
)}
{needsConfiguration && (
<Button
size="small"
className="z-[100]"
onClick={(e) => {
e.stopPropagation()
handleOpenModal(modelProvider, ConfigurationMethodEnum.predefinedModel, undefined)
<StatusIndicators
needsConfiguration={needsConfiguration}
modelProvider={!!modelProvider}
disabled={!!disabled}
pluginInfo={pluginInfo}
t={t}
/>
{!installed && !modelProvider && pluginInfo && (
<InstallButton
loading={loading}
onInstall={async () => {
setLoading(true)
const { all_installed } = await installPackageFromMarketPlace(pluginInfo.latest_package_identifier)
if (all_installed)
setInstalled(true)
}}
>
<div className="flex px-[3px] justify-center items-center gap-1">
{t('workflow.nodes.agent.notAuthorized')}
</div>
<div className="flex w-[14px] h-[14px] justify-center items-center">
<div className="w-2 h-2 shrink-0 rounded-[3px] border border-components-badge-status-light-warning-border-inner
bg-components-badge-status-light-warning-bg shadow-components-badge-status-light-warning-halo" />
</div>
</Button>
t={t}
/>
)}
{!needsConfiguration && disabled && (
<Tooltip
popupContent={t('workflow.nodes.agent.modelSelectorTooltips.deprecated')}
asChild={false}
>
<RiErrorWarningFill className='w-4 h-4 text-text-destructive' />
</Tooltip>
)
}
</>
) : (
<>
Expand All @@ -168,11 +180,6 @@ const AgentModelTrigger: FC<AgentModelTriggerProps> = ({
</div>
</>
)}
{currentProvider && currentModel && currentModel.status === ModelStatusEnum.active && (
<div className="flex pr-1 items-center">
<RiEqualizer2Line className="w-4 h-4 text-text-tertiary group-hover:text-text-secondary" />
</div>
)}
</div>
)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import Button from '@/app/components/base/button'
import { ConfigurationMethodEnum } from '../declarations'
import { useTranslation } from 'react-i18next'

type ConfigurationButtonProps = {
modelProvider: any
handleOpenModal: any
}

const ConfigurationButton = ({ modelProvider, handleOpenModal }: ConfigurationButtonProps) => {
const { t } = useTranslation()
return (
<Button
size="small"
className="z-[100]"
onClick={(e) => {
e.stopPropagation()
handleOpenModal(modelProvider, ConfigurationMethodEnum.predefinedModel, undefined)
}}
>
<div className="flex px-[3px] justify-center items-center gap-1">
{t('workflow.nodes.agent.notAuthorized')}
</div>
<div className="flex w-[14px] h-[14px] justify-center items-center">
<div className="w-2 h-2 shrink-0 rounded-[3px] border border-components-badge-status-light-warning-border-inner
bg-components-badge-status-light-warning-bg shadow-components-badge-status-light-warning-halo" />
</div>
</Button>
)
}

export default ConfigurationButton
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import ModelName from '../model-name'

type ModelDisplayProps = {
currentModel: any
modelId: string
}

const ModelDisplay = ({ currentModel, modelId }: ModelDisplayProps) => {
return currentModel ? (
<ModelName
className="flex px-1 py-[3px] items-center gap-1 grow"
modelItem={currentModel}
showMode
showFeatures
/>
) : (
<div className="flex py-[3px] px-1 items-center gap-1 grow opacity-50 truncate">
<div className="text-components-input-text-filled text-ellipsis overflow-hidden system-sm-regular">
{modelId}
</div>
</div>
)
}

export default ModelDisplay
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import Tooltip from '@/app/components/base/tooltip'
import { RiErrorWarningFill } from '@remixicon/react'

type StatusIndicatorsProps = {
needsConfiguration: boolean
modelProvider: boolean
disabled: boolean
pluginInfo: any
t: any
}

const StatusIndicators = ({ needsConfiguration, modelProvider, disabled, pluginInfo, t }: StatusIndicatorsProps) => {
return (
<>
{!needsConfiguration && modelProvider && disabled && (
<Tooltip
popupContent={t('workflow.nodes.agent.modelSelectorTooltips.deprecated')}
asChild={false}
>
<RiErrorWarningFill className='w-4 h-4 text-text-destructive' />
</Tooltip>
)}
{!modelProvider && !pluginInfo && (
<Tooltip
popupContent={
<div className='flex w-[240px] max-w-[240px] gap-1 flex-col px-1 py-1.5'>
<div className='text-text-primary title-xs-semi-bold'>{t('workflow.nodes.agent.modelNotInMarketplace.title')}</div>
<div className='min-w-[200px] text-text-secondary body-xs-regular'>
{t('workflow.nodes.agent.modelNotInMarketplace.desc')}
</div>
<div className='text-text-accent body-xs-regular'>{t('workflow.nodes.agent.modelNotInMarketplace.manageInPlugins')}</div>
</div>
}
asChild={false}
needsDelay
>
<RiErrorWarningFill className='w-4 h-4 text-text-destructive' />
</Tooltip>
)}
</>
)
}

export default StatusIndicators
16 changes: 0 additions & 16 deletions web/app/components/plugins/plugin-detail-panel/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import ActionList from './action-list'
import ModelList from './model-list'
import AgentStrategyList from './agent-strategy-list'
import Drawer from '@/app/components/base/drawer'
import MultipleToolSelector from '@/app/components/plugins/plugin-detail-panel/multiple-tool-selector'
import type { PluginDetail } from '@/app/components/plugins/types'
import cn from '@/utils/classnames'

Expand All @@ -28,12 +27,6 @@ const PluginDetailPanel: FC<Props> = ({
onUpdate()
}

const [value, setValue] = React.useState<any>(undefined)
const testChange = (val: any) => {
console.log('tool change', val)
setValue(val)
}

if (!detail)
return null

Expand All @@ -59,15 +52,6 @@ const PluginDetailPanel: FC<Props> = ({
{!!detail.declaration.agent_strategy && <AgentStrategyList detail={detail} />}
{!!detail.declaration.endpoint && <EndpointList detail={detail} />}
{!!detail.declaration.model && <ModelList detail={detail} />}
{false && (
<div className='px-4 py-2'>
<MultipleToolSelector
value={value || []}
label='TOOLS'
onChange={testChange}
/>
</div>
)}
</div>
</>
)}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import {
usePluginManifestInfo,
} from '@/service/use-plugins'

export const usePluginInstalledCheck = (providerName = '') => {
const pluginID = providerName?.split('/').splice(0, 2).join('/')

const { data: manifest } = usePluginManifestInfo(pluginID)

return {
inMarketPlace: !!manifest,
manifest: manifest?.data.plugin,
}
}
Loading

0 comments on commit f6c1ae5

Please sign in to comment.