diff --git a/web/app/components/base/badge.tsx b/web/app/components/base/badge.tsx index 78b9a76326..fe034ad2f4 100644 --- a/web/app/components/base/badge.tsx +++ b/web/app/components/base/badge.tsx @@ -20,7 +20,7 @@ const Badge = ({ return (
{ {loading ? t('workflow.nodes.agent.pluginInstaller.installing') : t('workflow.nodes.agent.pluginInstaller.install')}
{loading - ? + ? : } diff --git a/web/app/components/base/qrcode/style.module.css b/web/app/components/base/qrcode/style.module.css index b0c4441e99..d84e5fa45c 100644 --- a/web/app/components/base/qrcode/style.module.css +++ b/web/app/components/base/qrcode/style.module.css @@ -41,6 +41,7 @@ gap: 4px; } .qrcodeform { + z-index: 50; border: 0.5px solid #eaecf0; display: flex; flex-direction: column; diff --git a/web/app/components/header/account-setting/model-provider-page/hooks.ts b/web/app/components/header/account-setting/model-provider-page/hooks.ts index 612747e42b..231df0e9db 100644 --- a/web/app/components/header/account-setting/model-provider-page/hooks.ts +++ b/web/app/components/header/account-setting/model-provider-page/hooks.ts @@ -16,6 +16,7 @@ import type { } from './declarations' import { ConfigurationMethodEnum, + CustomConfigurationStatusEnum, ModelStatusEnum, } from './declarations' import I18n from '@/context/i18n' @@ -33,6 +34,9 @@ import { import type { Plugin } from '@/app/components/plugins/types' import { PluginType } from '@/app/components/plugins/types' import { getMarketplacePluginsByCollectionId } from '@/app/components/plugins/marketplace/utils' +import { useModalContextSelector } from '@/context/modal-context' +import { useEventEmitterContextContext } from '@/context/event-emitter' +import { UPDATE_MODEL_PROVIDER_CUSTOM_MODEL_LIST } from './provider-added-card' type UseDefaultModelAndModelList = ( defaultModel: DefaultModelResponse | undefined, @@ -304,3 +308,42 @@ export const useMarketplaceAllPlugins = (providers: ModelProvider[], searchText: isLoading, } } + +export const useModelModalHandler = () => { + const setShowModelModal = useModalContextSelector(state => state.setShowModelModal) + const updateModelProviders = useUpdateModelProviders() + const updateModelList = useUpdateModelList() + const { eventEmitter } = useEventEmitterContextContext() + + return ( + provider: ModelProvider, + configurationMethod: ConfigurationMethodEnum, + CustomConfigurationModelFixedFields?: CustomConfigurationModelFixedFields, + ) => { + setShowModelModal({ + payload: { + currentProvider: provider, + currentConfigurationMethod: configurationMethod, + currentCustomConfigurationModelFixedFields: CustomConfigurationModelFixedFields, + }, + onSaveCallback: () => { + updateModelProviders() + + provider.supported_model_types.forEach((type) => { + updateModelList(type) + }) + + if (configurationMethod === ConfigurationMethodEnum.customizableModel + && provider.custom_configuration.status === CustomConfigurationStatusEnum.active) { + eventEmitter?.emit({ + type: UPDATE_MODEL_PROVIDER_CUSTOM_MODEL_LIST, + payload: provider.provider, + } as any) + + if (CustomConfigurationModelFixedFields?.__model_type) + updateModelList(CustomConfigurationModelFixedFields.__model_type) + } + }, + }) + } +} diff --git a/web/app/components/header/account-setting/model-provider-page/index.tsx b/web/app/components/header/account-setting/model-provider-page/index.tsx index 428686efce..2e09fe93b1 100644 --- a/web/app/components/header/account-setting/model-provider-page/index.tsx +++ b/web/app/components/header/account-setting/model-provider-page/index.tsx @@ -9,19 +9,21 @@ import { RiBrainLine, } from '@remixicon/react' import SystemModelSelector from './system-model-selector' -import ProviderAddedCard, { UPDATE_MODEL_PROVIDER_CUSTOM_MODEL_LIST } from './provider-added-card' +import ProviderAddedCard from './provider-added-card' import type { + ConfigurationMethodEnum, CustomConfigurationModelFixedFields, + ModelProvider, } from './declarations' import { - ConfigurationMethodEnum, CustomConfigurationStatusEnum, ModelTypeEnum, } from './declarations' import { useDefaultModel, useMarketplaceAllPlugins, + useModelModalHandler, useUpdateModelList, useUpdateModelProviders, } from './hooks' @@ -87,37 +89,7 @@ const ModelProviderPage = ({ searchText }: Props) => { return [filteredConfiguredProviders, filteredNotConfiguredProviders] }, [configuredProviders, debouncedSearchText, notConfiguredProviders]) - const handleOpenModal = ( - provider: ModelProvider, - configurationMethod: ConfigurationMethodEnum, - CustomConfigurationModelFixedFields?: CustomConfigurationModelFixedFields, - ) => { - setShowModelModal({ - payload: { - currentProvider: provider, - currentConfigurationMethod: configurationMethod, - currentCustomConfigurationModelFixedFields: CustomConfigurationModelFixedFields, - }, - onSaveCallback: () => { - updateModelProviders() - - provider.supported_model_types.forEach((type) => { - updateModelList(type) - }) - - if (configurationMethod === ConfigurationMethodEnum.customizableModel && provider.custom_configuration.status === CustomConfigurationStatusEnum.active) { - eventEmitter?.emit({ - type: UPDATE_MODEL_PROVIDER_CUSTOM_MODEL_LIST, - payload: provider.provider, - } as any) - - if (CustomConfigurationModelFixedFields?.__model_type) - updateModelList(CustomConfigurationModelFixedFields?.__model_type) - } - }, - }) - } - + const handleOpenModal = useModelModalHandler() const [collapse, setCollapse] = useState(false) const locale = getLocaleOnClient() const { diff --git a/web/app/components/header/account-setting/model-provider-page/model-parameter-modal/agent-model-trigger.tsx b/web/app/components/header/account-setting/model-provider-page/model-parameter-modal/agent-model-trigger.tsx index adffecb82a..1d07e76541 100644 --- a/web/app/components/header/account-setting/model-provider-page/model-parameter-modal/agent-model-trigger.tsx +++ b/web/app/components/header/account-setting/model-provider-page/model-parameter-modal/agent-model-trigger.tsx @@ -2,27 +2,25 @@ import type { FC } from 'react' import { useEffect, useMemo, useState } from 'react' import { useTranslation } from 'react-i18next' import type { - CustomConfigurationModelFixedFields, ModelItem, ModelProvider, } from '../declarations' import { - ConfigurationMethodEnum, CustomConfigurationStatusEnum, ModelTypeEnum, } from '../declarations' -import { UPDATE_MODEL_PROVIDER_CUSTOM_MODEL_LIST } from '../provider-added-card' import type { PluginInfoFromMarketPlace } from '@/app/components/plugins/types' -import { useInstallPackageFromMarketPlace } from '@/service/use-plugins' +import { useInvalidateInstalledPluginList } from '@/service/use-plugins' import ConfigurationButton from './configuration-button' import { PluginType } from '@/app/components/plugins/types' import { + useModelModalHandler, useUpdateModelList, useUpdateModelProviders, } from '../hooks' import ModelIcon from '../model-icon' import ModelDisplay from './model-display' -import InstallButton from '@/app/components/base/install-button' +import { InstallPluginButton } from '@/app/components/workflow/nodes/_base/components/install-plugin-button' import StatusIndicators from './status-indicators' import cn from '@/utils/classnames' import { useProviderContext } from '@/context/provider-context' @@ -72,10 +70,9 @@ const AgentModelTrigger: FC = ({ }, [modelProviders, providerName]) const [pluginInfo, setPluginInfo] = useState(null) const [isPluginChecked, setIsPluginChecked] = useState(false) - const [loading, setLoading] = useState(false) const [installed, setInstalled] = useState(false) - const { mutateAsync: installPackageFromMarketPlace } = useInstallPackageFromMarketPlace() - + const invalidateInstalledPluginList = useInvalidateInstalledPluginList() + const handleOpenModal = useModelModalHandler() useEffect(() => { (async () => { if (providerName && !modelProvider) { @@ -101,66 +98,6 @@ const AgentModelTrigger: FC = ({ if (modelId && !isPluginChecked) return null - const handleOpenModal = ( - provider: ModelProvider, - configurationMethod: ConfigurationMethodEnum, - CustomConfigurationModelFixedFields?: CustomConfigurationModelFixedFields, - ) => { - setShowModelModal({ - payload: { - currentProvider: provider, - currentConfigurationMethod: configurationMethod, - currentCustomConfigurationModelFixedFields: CustomConfigurationModelFixedFields, - }, - onSaveCallback: () => { - updateModelProviders() - - provider.supported_model_types.forEach((type) => { - updateModelList(type) - }) - - if (configurationMethod === ConfigurationMethodEnum.customizableModel - && provider.custom_configuration.status === CustomConfigurationStatusEnum.active) { - eventEmitter?.emit({ - type: UPDATE_MODEL_PROVIDER_CUSTOM_MODEL_LIST, - payload: provider.provider, - } as any) - - if (CustomConfigurationModelFixedFields?.__model_type) - updateModelList(CustomConfigurationModelFixedFields.__model_type) - } - }, - }) - } - - const handleInstall = async (pluginInfo: PluginInfoFromMarketPlace) => { - setLoading(true) - try { - const { all_installed } = await installPackageFromMarketPlace(pluginInfo.latest_package_identifier) - if (all_installed) { - [ - ModelTypeEnum.textGeneration, - ModelTypeEnum.textEmbedding, - ModelTypeEnum.rerank, - ModelTypeEnum.moderation, - ModelTypeEnum.speech2text, - ModelTypeEnum.tts, - ].forEach((type: ModelTypeEnum) => { - if (scope?.includes(type)) - updateModelList(type) - }) - updateModelProviders() - setInstalled(true) - } - } - catch (error) { - console.error('Installation failed:', error) - } - finally { - setLoading(false) - } - } - return (
= ({ t={t} /> {!installed && !modelProvider && pluginInfo && ( - { - e.stopPropagation() - handleInstall(pluginInfo) + e.stopPropagation()} + size={'small'} + uniqueIdentifier={pluginInfo.latest_package_identifier} + onSuccess={() => { + [ + ModelTypeEnum.textGeneration, + ModelTypeEnum.textEmbedding, + ModelTypeEnum.rerank, + ModelTypeEnum.moderation, + ModelTypeEnum.speech2text, + ModelTypeEnum.tts, + ].forEach((type: ModelTypeEnum) => { + if (scope?.includes(type)) + updateModelList(type) + }, + ) + updateModelProviders() + invalidateInstalledPluginList() + setInstalled(true) }} - t={t} /> )} {modelProvider && !disabled && !needsConfiguration && ( diff --git a/web/app/components/header/plugins-nav/downloading-icon.module.css b/web/app/components/header/plugins-nav/downloading-icon.module.css new file mode 100644 index 0000000000..c11a9f2f2c --- /dev/null +++ b/web/app/components/header/plugins-nav/downloading-icon.module.css @@ -0,0 +1,44 @@ +@keyframes realistic-blink { + 0% { fill: #37ff37; opacity: 0.4; } + 15% { fill: #37ff37; opacity: 0.9; } + 25% { fill: #37ff37; opacity: 0.3; } + 38% { fill: #ff4444; opacity: 0.8; } + 42% { fill: #ff4444; opacity: 0.3; } + 58% { fill: #37ff37; opacity: 0.9; } + 65% { fill: #37ff37; opacity: 0.4; } + 79% { fill: #ff4444; opacity: 0.8; } + 84% { fill: #ff4444; opacity: 0.3; } + 92% { fill: #37ff37; opacity: 0.8; } + 100% { fill: #37ff37; opacity: 0.4; } +} + +@keyframes drop { + 0% { + transform: translateY(-4px); + opacity: 0; + } + 5% { + transform: translateY(-4px); + opacity: 1; + } + 65% { + transform: translateY(2px); + opacity: 1; + } + 80% { + transform: translateY(2px); + opacity: 0; + } + 100% { + transform: translateY(2px); + opacity: 0; + } +} + +#downloadingIconLight { + animation: realistic-blink 3s infinite ease-in-out; +} + +#downloadingIconArrow { + animation: drop 1.2s cubic-bezier(0.4, 0, 1, 1) infinite; +} \ No newline at end of file diff --git a/web/app/components/header/plugins-nav/downloading-icon.tsx b/web/app/components/header/plugins-nav/downloading-icon.tsx new file mode 100644 index 0000000000..d3fc486445 --- /dev/null +++ b/web/app/components/header/plugins-nav/downloading-icon.tsx @@ -0,0 +1,17 @@ +import s from './downloading-icon.module.css' + +const DownloadingIcon = () => { + return ( +
+ + + + + + + +
+ ) +} + +export default DownloadingIcon diff --git a/web/app/components/header/plugins-nav/index.tsx b/web/app/components/header/plugins-nav/index.tsx index aa57e652b2..b2c6eba1a6 100644 --- a/web/app/components/header/plugins-nav/index.tsx +++ b/web/app/components/header/plugins-nav/index.tsx @@ -5,6 +5,9 @@ import Link from 'next/link' import classNames from '@/utils/classnames' import { Group } from '@/app/components/base/icons/src/vender/other' import { useSelectedLayoutSegment } from 'next/navigation' +import DownloadingIcon from './downloading-icon' +import { usePluginTaskStatus } from '@/app/components/plugins/plugin-page/plugin-tasks/hooks' +import Indicator from '@/app/components/header/indicator' type PluginsNavProps = { className?: string @@ -16,17 +19,43 @@ const PluginsNav = ({ const { t } = useTranslation() const selectedSegment = useSelectedLayoutSegment() const activated = selectedSegment === 'plugins' + const { + isInstalling, + isInstallingWithError, + isFailed, + } = usePluginTaskStatus() return ( -
+
+ { + (isFailed || isInstallingWithError) && !activated && ( + + ) + }
- + { + (!(isInstalling || isInstallingWithError) || activated) && ( + + ) + } + { + (isInstalling || isInstallingWithError) && !activated && ( + + ) + }
{t('common.menus.plugins')}
diff --git a/web/app/components/plugins/plugin-detail-panel/index.tsx b/web/app/components/plugins/plugin-detail-panel/index.tsx index 4d20c0877d..692b2ecd26 100644 --- a/web/app/components/plugins/plugin-detail-panel/index.tsx +++ b/web/app/components/plugins/plugin-detail-panel/index.tsx @@ -9,6 +9,7 @@ import AgentStrategyList from './agent-strategy-list' import Drawer from '@/app/components/base/drawer' import type { PluginDetail } from '@/app/components/plugins/types' import cn from '@/utils/classnames' +import ToolSelector from '@/app/components/plugins/plugin-detail-panel/tool-selector' type Props = { detail?: PluginDetail @@ -27,6 +28,16 @@ const PluginDetailPanel: FC = ({ onUpdate() } + const [value, setValue] = React.useState({ + provider_name: 'langgenius/google/google', + tool_name: 'google_search', + }) + + const testHandle = (item: any) => { + console.log(item) + setValue(item) + } + if (!detail) return null @@ -52,6 +63,17 @@ const PluginDetailPanel: FC = ({ {!!detail.declaration.agent_strategy && } {!!detail.declaration.endpoint && } {!!detail.declaration.model && } + {false && ( +
+ testHandle(item)} + onDelete={() => testHandle(null)} + supportEnableSwitch + /> +
+ )}
)} diff --git a/web/app/components/plugins/plugin-detail-panel/tool-selector/index.tsx b/web/app/components/plugins/plugin-detail-panel/tool-selector/index.tsx index c59a1799f3..220edc22ca 100644 --- a/web/app/components/plugins/plugin-detail-panel/tool-selector/index.tsx +++ b/web/app/components/plugins/plugin-detail-panel/tool-selector/index.tsx @@ -32,7 +32,7 @@ import { useInvalidateAllBuiltInTools, useUpdateProviderCredentials, } from '@/service/use-tools' -import { useInstallPackageFromMarketPlace } from '@/service/use-plugins' +import { useInvalidateInstalledPluginList } from '@/service/use-plugins' import { usePluginInstalledCheck } from '@/app/components/plugins/plugin-detail-panel/tool-selector/hooks' import { CollectionType } from '@/app/components/tools/types' import type { ToolDefaultValue } from '@/app/components/workflow/block-selector/types' @@ -94,6 +94,7 @@ const ToolSelector: FC = ({ const { data: customTools } = useAllCustomTools() const { data: workflowTools } = useAllWorkflowTools() const invalidateAllBuiltinTools = useInvalidateAllBuiltInTools() + const invalidateInstalledPluginList = useInvalidateInstalledPluginList() // plugin info check const { inMarketPlace, manifest } = usePluginInstalledCheck(value?.provider_name) @@ -171,22 +172,15 @@ const ToolSelector: FC = ({ }) // install from marketplace - const { mutateAsync: installPackageFromMarketPlace, isPending } = useInstallPackageFromMarketPlace() + const manifestIcon = useMemo(() => { if (!manifest) return '' return `${MARKETPLACE_API_PREFIX}/plugins/${(manifest as any).plugin_id}/icon` }, [manifest]) const handleInstall = async () => { - if (!manifest) - return - try { - await installPackageFromMarketPlace(manifest.latest_package_identifier) - invalidateAllBuiltinTools() - } - catch (e: any) { - Toast.notify({ type: 'error', message: `${e.message || e}` }) - } + invalidateAllBuiltinTools() + invalidateInstalledPluginList() } return ( @@ -223,7 +217,7 @@ const ToolSelector: FC = ({ noAuth={currentProvider && !currentProvider.is_team_authorization} onAuth={() => setShowSettingAuth(true)} uninstalled={!currentProvider && inMarketPlace} - isInstalling={isPending} + installInfo={manifest?.latest_package_identifier} onInstall={() => handleInstall()} isError={!currentProvider && !inMarketPlace} errorTip={
diff --git a/web/app/components/plugins/plugin-detail-panel/tool-selector/tool-item.tsx b/web/app/components/plugins/plugin-detail-panel/tool-selector/tool-item.tsx index 5927318619..45a9abd592 100644 --- a/web/app/components/plugins/plugin-detail-panel/tool-selector/tool-item.tsx +++ b/web/app/components/plugins/plugin-detail-panel/tool-selector/tool-item.tsx @@ -5,8 +5,6 @@ import { RiDeleteBinLine, RiEqualizer2Line, RiErrorWarningFill, - RiInstallLine, - RiLoader2Line, } from '@remixicon/react' import { Group } from '@/app/components/base/icons/src/vender/other' import AppIcon from '@/app/components/base/app-icon' @@ -15,6 +13,7 @@ import Button from '@/app/components/base/button' import Indicator from '@/app/components/header/indicator' import ActionButton from '@/app/components/base/action-button' import Tooltip from '@/app/components/base/tooltip' +import { InstallPluginButton } from '@/app/components/workflow/nodes/_base/components/install-plugin-button' import cn from '@/utils/classnames' type Props = { @@ -30,7 +29,7 @@ type Props = { isError?: boolean errorTip?: any uninstalled?: boolean - isInstalling?: boolean + installInfo?: string onInstall?: () => void open: boolean } @@ -47,7 +46,7 @@ const ToolItem = ({ noAuth, onAuth, uninstalled, - isInstalling, + installInfo, onInstall, isError, errorTip, @@ -115,20 +114,15 @@ const ToolItem = ({ )} - {!isError && uninstalled && ( - + /> )} {isError && ( = ({ const setCurrentPluginID = usePluginPageContext(v => v.setCurrentPluginID) const invalidateInstalledPluginList = useInvalidateInstalledPluginList() const invalidateAllToolProviders = useInvalidateAllToolProviders() + const invalidateAllBuiltinTools = useInvalidateAllBuiltInTools() const { refreshModelProviders } = useProviderContext() const { @@ -62,8 +63,10 @@ const PluginItem: FC = ({ invalidateInstalledPluginList() if (PluginType.model.includes(category)) refreshModelProviders() - if (PluginType.tool.includes(category)) + if (PluginType.tool.includes(category)) { invalidateAllToolProviders() + invalidateAllBuiltinTools() + } } const getValueFromI18nObject = useRenderI18nObject() const title = getValueFromI18nObject(label) diff --git a/web/app/components/plugins/plugin-page/plugin-tasks/hooks.ts b/web/app/components/plugins/plugin-page/plugin-tasks/hooks.ts index e15f9b963a..f32a812c13 100644 --- a/web/app/components/plugins/plugin-page/plugin-tasks/hooks.ts +++ b/web/app/components/plugins/plugin-page/plugin-tasks/hooks.ts @@ -64,14 +64,16 @@ export const usePluginTaskStatus = () => { const timerRef = useRef(null) useEffect(() => { - if (isSuccess && opacity > 0) { + if (isSuccess) { if (timerRef.current) { clearTimeout(timerRef.current) timerRef.current = null } - timerRef.current = setTimeout(() => { - setOpacity(v => v - 0.1) - }, 200) + if (opacity > 0) { + timerRef.current = setTimeout(() => { + setOpacity(v => v - 0.1) + }, 200) + } } if (!isSuccess) diff --git a/web/app/components/workflow/block-selector/market-place-plugin/list.tsx b/web/app/components/workflow/block-selector/market-place-plugin/list.tsx index 596b6f21c5..8509faf253 100644 --- a/web/app/components/workflow/block-selector/market-place-plugin/list.tsx +++ b/web/app/components/workflow/block-selector/market-place-plugin/list.tsx @@ -15,14 +15,16 @@ type Props = { list: Plugin[] searchText: string tags: string[] + disableMaxWidth?: boolean } -const List = ({ +const List = forwardRef<{ handleScroll: () => void }, Props>(({ wrapElemRef, searchText, tags, list, -}: Props, ref: any) => { + disableMaxWidth = false, +}, ref) => { const { t } = useTranslation() const hasFilter = !searchText const hasRes = list.length > 0 @@ -95,7 +97,7 @@ const List = ({
)} -
+
{list.map((item, index) => ( { }} /> ))} -
+
) -} -export default forwardRef(List) +}) + +List.displayName = 'List' + +export default List diff --git a/web/app/components/workflow/nodes/_base/components/agent-strategy-selector.tsx b/web/app/components/workflow/nodes/_base/components/agent-strategy-selector.tsx index a7fa48ec07..c5862dab02 100644 --- a/web/app/components/workflow/nodes/_base/components/agent-strategy-selector.tsx +++ b/web/app/components/workflow/nodes/_base/components/agent-strategy-selector.tsx @@ -1,24 +1,25 @@ import { PortalToFollowElem, PortalToFollowElemContent, PortalToFollowElemTrigger } from '@/app/components/base/portal-to-follow-elem' import type { ReactNode } from 'react' -import { memo, useMemo, useState } from 'react' +import { memo, useEffect, useMemo, useRef, useState } from 'react' import type { Strategy } from './agent-strategy' import classNames from '@/utils/classnames' -import { RiArrowDownSLine, RiArrowRightUpLine, RiErrorWarningFill } from '@remixicon/react' +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 { MARKETPLACE_URL_PREFIX } from '@/config' import Tools from '../../../block-selector/tools' import { useTranslation } from 'react-i18next' import { useStrategyProviders } from '@/service/use-strategy' -import type { StrategyPluginDetail } from '@/app/components/plugins/types' +import { PluginType, 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 PluginList from '@/app/components/workflow/block-selector/market-place-plugin/list' +import { useMarketplacePlugins } from '@/app/components/plugins/marketplace/hooks' const NotFoundWarn = (props: { title: ReactNode, @@ -119,6 +120,25 @@ export const AgentStrategySelector = memo((props: AgentStrategySelectorProps) => )?.icon as string | undefined const { t } = useTranslation() + const wrapElemRef = useRef(null) + + const { + queryPluginsWithDebounced: fetchPlugins, + plugins: notInstalledPlugins = [], + } = useMarketplacePlugins() + + useEffect(() => { + if (query) { + fetchPlugins({ + query, + category: PluginType.agent, + }) + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [query]) + + const pluginRef = useRef(null) + return
-
- {/* TODO: fix when in list view show workflow as group label */} +
plugin_unique_identifier: tool!.provider_id, }) setOpen(false) - }} - hasSearchText={false} - showWorkflowEmpty={false} - className='max-w-none' - indexBarClassName='top-0 xl:top-36' + } } + className='max-w-none max-h-full h-full overflow-y-auto' + indexBarClassName='top-0 xl:top-36' showWorkflowEmpty={false} hasSearchText={false} /> + -
- Find more in - - Marketplace - -
diff --git a/web/app/components/workflow/nodes/_base/components/install-plugin-button.tsx b/web/app/components/workflow/nodes/_base/components/install-plugin-button.tsx index bdbcdfde5a..bf4073358f 100644 --- a/web/app/components/workflow/nodes/_base/components/install-plugin-button.tsx +++ b/web/app/components/workflow/nodes/_base/components/install-plugin-button.tsx @@ -38,6 +38,6 @@ export const InstallPluginButton = (props: InstallPluginButtonProps) => { className={classNames('flex items-center', className)} > {!isLoading ? t('workflow.nodes.agent.pluginInstaller.install') : t('workflow.nodes.agent.pluginInstaller.installing')} - {!isLoading ? : } + {!isLoading ? : } }