diff --git a/web/app/(commonLayout)/plugins/test/card/page.tsx b/web/app/(commonLayout)/plugins/test/card/page.tsx index 1d7817a982..534789c00c 100644 --- a/web/app/(commonLayout)/plugins/test/card/page.tsx +++ b/web/app/(commonLayout)/plugins/test/card/page.tsx @@ -6,35 +6,53 @@ import CardMoreInfo from '@/app/components/plugins/card/card-more-info' // import ProviderCard from '@/app/components/plugins/provider-card' import Badge from '@/app/components/base/badge' import InstallBundle from '@/app/components/plugins/install-plugin/install-bundle' +import { useBoolean } from 'ahooks' const PluginList = () => { const pluginList = [toolNotion, extensionDallE, modelGPT4, customTool] + const [isShow, { + setFalse: hide, + }] = useBoolean(true) return (
- { }} fromDSLPayload={[ - { - type: 'marketplace', - value: { - plugin_unique_identifier: 'langgenius/google:0.0.2@dcb354c9d0fee60e6e9c9eb996e1e485bbef343ba8cd545c0cfb3ec80970f6f1', - }, - }, - { - type: 'github', - value: { - repo: 'YIXIAO0/test', - version: '1.11.5', - package: 'test.difypkg', - github_plugin_unique_identifier: 'yixiao0/test:0.0.1@3592166c87afcf944b4f13f27467a5c8f9e00bd349cb42033a072734a37431b4', - }, - }, - { - type: 'marketplace', - value: { - plugin_unique_identifier: 'langgenius/openai:0.0.1@f88fdb98d104466db16a425bfe3af8c1bcad45047a40fb802d98a989ac57a5a3', - }, - }, - ]} /> + {isShow && ( + + ) + }
{/*

Dify Plugin list

*/} {/*
diff --git a/web/app/components/app/configuration/dataset-config/params-config/config-content.tsx b/web/app/components/app/configuration/dataset-config/params-config/config-content.tsx index fe91f4a79a..dcb2b1a3fd 100644 --- a/web/app/components/app/configuration/dataset-config/params-config/config-content.tsx +++ b/web/app/components/app/configuration/dataset-config/params-config/config-content.tsx @@ -25,7 +25,7 @@ import { useSelectedDatasetsMode } from '@/app/components/workflow/nodes/knowled import Switch from '@/app/components/base/switch' import Toast from '@/app/components/base/toast' -interface Props { +type Props = { datasetConfigs: DatasetConfigs onChange: (configs: DatasetConfigs, isRetrievalModeChange?: boolean) => void isInWorkflow?: boolean diff --git a/web/app/components/app/configuration/dataset-config/params-config/index.tsx b/web/app/components/app/configuration/dataset-config/params-config/index.tsx index 7f7a4799d1..701b7053f5 100644 --- a/web/app/components/app/configuration/dataset-config/params-config/index.tsx +++ b/web/app/components/app/configuration/dataset-config/params-config/index.tsx @@ -139,11 +139,11 @@ const ParamsConfig = ({ />
- - +
) diff --git a/web/app/components/app/configuration/index.tsx b/web/app/components/app/configuration/index.tsx index 5cae3c1bfb..6bbab4a6e0 100644 --- a/web/app/components/app/configuration/index.tsx +++ b/web/app/components/app/configuration/index.tsx @@ -72,6 +72,7 @@ import { SupportUploadFileTypes } from '@/app/components/workflow/types' import NewFeaturePanel from '@/app/components/base/features/new-feature-panel' import { fetchFileUploadConfig } from '@/service/common' import { correctProvider } from '@/utils' +import PluginDependency from '@/app/components/workflow/plugin-dependency' type PublishConfig = { modelConfig: ModelConfig @@ -1038,6 +1039,7 @@ const Configuration: FC = () => { onAutoAddPromptVariable={handleAddPromptVariable} /> )} + diff --git a/web/app/components/app/create-from-dsl-modal/index.tsx b/web/app/components/app/create-from-dsl-modal/index.tsx index 45ef8dbde6..2064b92132 100644 --- a/web/app/components/app/create-from-dsl-modal/index.tsx +++ b/web/app/components/app/create-from-dsl-modal/index.tsx @@ -80,24 +80,16 @@ const CreateFromDSLModal = ({ show, onSuccess, onClose, activeTab = CreateFromDS let app if (currentTab === CreateFromDSLModalTab.FROM_FILE) { - const leakedData = await mutateAsync({ dslString: fileContent }) - if (leakedData?.leaked.length) { - isCreatingRef.current = false - return - } app = await importApp({ data: fileContent || '', }) + await mutateAsync({ dslString: fileContent }) } if (currentTab === CreateFromDSLModalTab.FROM_URL) { - const leakedData = await mutateAsync({ url: dslUrlValue }) - if (leakedData?.leaked.length) { - isCreatingRef.current = false - return - } app = await importAppFromUrl({ url: dslUrlValue || '', }) + await mutateAsync({ url: dslUrlValue }) } if (onSuccess) onSuccess() diff --git a/web/app/components/app/overview/settings/index.tsx b/web/app/components/app/overview/settings/index.tsx index e7cc4148ef..f23100a796 100644 --- a/web/app/components/app/overview/settings/index.tsx +++ b/web/app/components/app/overview/settings/index.tsx @@ -243,7 +243,7 @@ const SettingsModal: FC = ({

{t(`${prefixSettings}.workflow.title`)}

-
{t(`${prefixSettings}.workflow.subTitle`)}
+
{t(`${prefixSettings}.workflow.subTitle`)}
= ({ {systemFeatures.enable_web_sso_switch_component &&

{t(`${prefixSettings}.sso.label`)}

-
{t(`${prefixSettings}.sso.title`)}
+
{t(`${prefixSettings}.sso.title`)}
= ({
} {!isShowMore &&
setIsShowMore(true)}>
-
{t(`${prefixSettings}.more.entry`)}
-
+
{t(`${prefixSettings}.more.entry`)}
+
diff --git a/web/app/components/base/file-uploader/file-from-link-or-local/index.tsx b/web/app/components/base/file-uploader/file-from-link-or-local/index.tsx index 1ff2bdd174..8ae8bb0538 100644 --- a/web/app/components/base/file-uploader/file-from-link-or-local/index.tsx +++ b/web/app/components/base/file-uploader/file-from-link-or-local/index.tsx @@ -59,7 +59,7 @@ const FileFromLinkOrLocal = ({ setOpen(v => !v)} asChild> {trigger(open)} - +
{ showFromLink && ( diff --git a/web/app/components/header/account-setting/members-page/index.tsx b/web/app/components/header/account-setting/members-page/index.tsx index e09e4bbc0d..2eaee6f901 100644 --- a/web/app/components/header/account-setting/members-page/index.tsx +++ b/web/app/components/header/account-setting/members-page/index.tsx @@ -48,7 +48,7 @@ const MembersPage = () => { return ( <>
-
+
{currentWorkspace?.name}
diff --git a/web/app/components/header/account-setting/model-provider-page/model-modal/Form.tsx b/web/app/components/header/account-setting/model-provider-page/model-modal/Form.tsx index cef2146daa..f4e23b566b 100644 --- a/web/app/components/header/account-setting/model-provider-page/model-modal/Form.tsx +++ b/web/app/components/header/account-setting/model-provider-page/model-modal/Form.tsx @@ -18,7 +18,8 @@ import { SimpleSelect } from '@/app/components/base/select' import Tooltip from '@/app/components/base/tooltip' import Radio from '@/app/components/base/radio' import ModelParameterModal from '@/app/components/header/account-setting/model-provider-page/model-parameter-modal' -import ToolSelector from '@/app/components/tools/tool-selector' +import ToolSelector from '@/app/components/plugins/plugin-detail-panel/tool-selector' +import AppSelector from '@/app/components/plugins/plugin-detail-panel/app-selector' type FormProps = { className?: string @@ -347,7 +348,32 @@ const Form: FC = ({ } if (formSchema.type === FormTypeEnum.appSelector) { - // TODO + const { + variable, + label, + required, + } = formSchema as (CredentialFormSchemaTextInput | CredentialFormSchemaSecretInput) + + return ( +
+
+ {label[language] || label.en_US} + { + required && ( + * + ) + } + {tooltipContent} +
+ handleFormChange(variable, item as any)} + /> + {fieldMoreInfo?.(formSchema)} + {validating && changeKey === variable && } +
+ ) } } diff --git a/web/app/components/header/index.tsx b/web/app/components/header/index.tsx index cf1549b8c3..8f44bf6eae 100644 --- a/web/app/components/header/index.tsx +++ b/web/app/components/header/index.tsx @@ -76,7 +76,7 @@ const Header = () => {
- {t('billing.upgradeBtn.encourage')} + {t('billing.upgradeBtn.encourageShort')}
@@ -98,7 +98,7 @@ const Header = () => {
- {t('billing.upgradeBtn.encourage')} + {t('billing.upgradeBtn.encourageShort')}
diff --git a/web/app/components/plugins/install-plugin/install-bundle/index.tsx b/web/app/components/plugins/install-plugin/install-bundle/index.tsx index 54f00d68a4..4e57af59e0 100644 --- a/web/app/components/plugins/install-plugin/install-bundle/index.tsx +++ b/web/app/components/plugins/install-plugin/install-bundle/index.tsx @@ -3,8 +3,9 @@ import type { FC } from 'react' import Modal from '@/app/components/base/modal' import React, { useCallback, useState } from 'react' import { InstallStep } from '../../types' -import type { Dependency } from '../../types' +import type { Dependency, Plugin } from '../../types' import Install from './steps/install' +import Installed from './steps/installed' import { useTranslation } from 'react-i18next' const i18nPrefix = 'plugin.installModal' @@ -29,7 +30,8 @@ const InstallBundle: FC = ({ }) => { const { t } = useTranslation() const [step, setStep] = useState(installType === InstallType.fromMarketplace ? InstallStep.readyToInstall : InstallStep.uploading) - + const [installedPlugins, setInstalledPlugins] = useState([]) + const [installStatus, setInstallStatus] = useState<{ success: boolean }[]>([]) const getTitle = useCallback(() => { if (step === InstallStep.uploadFailed) return t(`${i18nPrefix}.uploadFailed`) @@ -41,6 +43,12 @@ const InstallBundle: FC = ({ return t(`${i18nPrefix}.installPlugin`) }, [step, t]) + const handleInstalled = useCallback((plugins: Plugin[], installStatus: { success: boolean }[]) => { + setInstallStatus(installStatus) + setInstalledPlugins(plugins) + setStep(InstallStep.installed) + }, []) + return ( = ({ + )} + {step === InstallStep.installed && ( + )} diff --git a/web/app/components/plugins/install-plugin/install-bundle/item/github-item.tsx b/web/app/components/plugins/install-plugin/install-bundle/item/github-item.tsx index 1a773ca6a8..49f7e448aa 100644 --- a/web/app/components/plugins/install-plugin/install-bundle/item/github-item.tsx +++ b/web/app/components/plugins/install-plugin/install-bundle/item/github-item.tsx @@ -29,7 +29,10 @@ const Item: FC = ({ const [payload, setPayload] = React.useState(null) useEffect(() => { if (data) { - const payload = pluginManifestToCardPluginProps(data.manifest) + const payload = { + ...pluginManifestToCardPluginProps(data.manifest), + plugin_id: data.unique_identifier, + } onFetchedPayload(payload) setPayload(payload) } diff --git a/web/app/components/plugins/install-plugin/install-bundle/item/loaded-item.tsx b/web/app/components/plugins/install-plugin/install-bundle/item/loaded-item.tsx index ef083b6924..1fff28b5fc 100644 --- a/web/app/components/plugins/install-plugin/install-bundle/item/loaded-item.tsx +++ b/web/app/components/plugins/install-plugin/install-bundle/item/loaded-item.tsx @@ -5,6 +5,7 @@ import type { Plugin } from '../../../types' import Card from '../../../card' import Checkbox from '@/app/components/base/checkbox' import Badge, { BadgeState } from '@/app/components/base/badge/index' +import useGetIcon from '../../base/use-get-icon' type Props = { checked: boolean @@ -17,6 +18,7 @@ const LoadedItem: FC = ({ onCheckedChange, payload, }) => { + const { getIconUrl } = useGetIcon() return (
= ({ /> {payload.version} : null} />
diff --git a/web/app/components/plugins/install-plugin/install-bundle/steps/install-by-dsl-list.tsx b/web/app/components/plugins/install-plugin/install-bundle/steps/install-by-dsl-list.tsx index 8442c0a13d..aeafa8f18f 100644 --- a/web/app/components/plugins/install-plugin/install-bundle/steps/install-by-dsl-list.tsx +++ b/web/app/components/plugins/install-plugin/install-bundle/steps/install-by-dsl-list.tsx @@ -26,9 +26,12 @@ const InstallByDSLList: FC = ({ const [plugins, setPlugins, getPlugins] = useGetState([]) const handlePlugInFetched = useCallback((index: number) => { return (p: Plugin) => { - setPlugins(plugins.map((item, i) => i === index ? p : item)) + const nextPlugins = produce(getPlugins(), (draft) => { + draft[index] = p + }) + setPlugins(nextPlugins) } - }, [plugins]) + }, [getPlugins, setPlugins]) const marketPlaceInDSLIndex = useMemo(() => { const res: number[] = [] diff --git a/web/app/components/plugins/install-plugin/install-bundle/steps/install.tsx b/web/app/components/plugins/install-plugin/install-bundle/steps/install.tsx index 1ac7f95746..5600481a69 100644 --- a/web/app/components/plugins/install-plugin/install-bundle/steps/install.tsx +++ b/web/app/components/plugins/install-plugin/install-bundle/steps/install.tsx @@ -7,23 +7,25 @@ import { RiLoader2Line } from '@remixicon/react' import { useTranslation } from 'react-i18next' import InstallByDSLList from './install-by-dsl-list' import { useInstallFromMarketplaceAndGitHub } from '@/service/use-plugins' - +import { useInvalidateInstalledPluginList } from '@/service/use-plugins' const i18nPrefix = 'plugin.installModal' type Props = { fromDSLPayload: Dependency[] + onInstalled: (plugins: Plugin[], installStatus: { success: boolean }[]) => void onCancel: () => void } const Install: FC = ({ fromDSLPayload, + onInstalled, onCancel, }) => { const { t } = useTranslation() const [selectedPlugins, setSelectedPlugins] = React.useState([]) const [selectedIndexes, setSelectedIndexes] = React.useState([]) const selectedPluginsNum = selectedPlugins.length - + const invalidateInstalledPluginList = useInvalidateInstalledPluginList() const handleSelect = (plugin: Plugin, selectedIndex: number) => { const isSelected = !!selectedPlugins.find(p => p.plugin_id === plugin.plugin_id) let nextSelectedPlugins @@ -35,18 +37,21 @@ const Install: FC = ({ const nextSelectedIndexes = isSelected ? selectedIndexes.filter(i => i !== selectedIndex) : [...selectedIndexes, selectedIndex] setSelectedIndexes(nextSelectedIndexes) } + const [canInstall, setCanInstall] = React.useState(false) const handleLoadedAllPlugin = useCallback(() => { setCanInstall(true) - }, [selectedPlugins, selectedIndexes]) + }, []) // Install from marketplace and github const { mutate: installFromMarketplaceAndGitHub, isPending: isInstalling } = useInstallFromMarketplaceAndGitHub({ - onSuccess: () => { - console.log('success!') + onSuccess: (res: { success: boolean }[]) => { + onInstalled(selectedPlugins, res) + const hasInstallSuccess = res.some(r => r.success) + if (hasInstallSuccess) + invalidateInstalledPluginList() }, }) - console.log(canInstall, !isInstalling, selectedPlugins.length === 0) const handleInstall = () => { installFromMarketplaceAndGitHub(fromDSLPayload.filter((_d, index) => selectedIndexes.includes(index))) } diff --git a/web/app/components/plugins/install-plugin/install-bundle/steps/installed.tsx b/web/app/components/plugins/install-plugin/install-bundle/steps/installed.tsx new file mode 100644 index 0000000000..f8f058f2fa --- /dev/null +++ b/web/app/components/plugins/install-plugin/install-bundle/steps/installed.tsx @@ -0,0 +1,60 @@ +'use client' +import type { FC } from 'react' +import React from 'react' +import type { Plugin } from '../../../types' +import Card from '@/app/components/plugins/card' +import Button from '@/app/components/base/button' +import { useTranslation } from 'react-i18next' +import Badge, { BadgeState } from '@/app/components/base/badge/index' +import useGetIcon from '../../base/use-get-icon' + +type Props = { + list: Plugin[] + installStatus: { success: boolean }[] + onCancel: () => void +} + +const Installed: FC = ({ + list, + installStatus, + onCancel, +}) => { + const { t } = useTranslation() + const { getIconUrl } = useGetIcon() + return ( + <> +
+ {/*

{(isFailed && errMsg) ? errMsg : t(`plugin.installModal.${isFailed ? 'installFailedDesc' : 'installedSuccessfullyDesc'}`)}

*/} +
+ {list.map((plugin, index) => { + return ( + {plugin.version} : null} + /> + ) + })} +
+
+ {/* Action Buttons */} +
+ +
+ + ) +} + +export default React.memo(Installed) diff --git a/web/app/components/plugins/install-plugin/install-from-github/steps/loaded.tsx b/web/app/components/plugins/install-plugin/install-from-github/steps/loaded.tsx index 6b63c24aea..d4f15c0de4 100644 --- a/web/app/components/plugins/install-plugin/install-from-github/steps/loaded.tsx +++ b/web/app/components/plugins/install-plugin/install-from-github/steps/loaded.tsx @@ -2,7 +2,7 @@ import React from 'react' import Button from '@/app/components/base/button' -import type { PluginDeclaration, UpdateFromGitHubPayload } from '../../../types' +import type { PluginDeclaration, PluginType, UpdateFromGitHubPayload } from '../../../types' import Card from '../../../card' import Badge, { BadgeState } from '@/app/components/base/badge/index' import { pluginManifestToCardPluginProps } from '../../utils' @@ -13,6 +13,7 @@ import { RiLoader2Line } from '@remixicon/react' import { usePluginTaskList } from '@/service/use-plugins' import checkTaskStatus from '../../base/check-task-status' import { parseGitHubUrl } from '../../utils' +import { useCategories } from '../../../hooks' type LoadedProps = { updatePayload: UpdateFromGitHubPayload @@ -40,6 +41,7 @@ const Loaded: React.FC = ({ onFailed, }) => { const { t } = useTranslation() + const { categoriesMap } = useCategories() const [isInstalling, setIsInstalling] = React.useState(false) const { mutateAsync: installPackageFromGitHub } = useInstallPackageFromGitHub() const { handleRefetch } = usePluginTaskList() @@ -115,7 +117,7 @@ const Loaded: React.FC = ({
{payload.version}} />
diff --git a/web/app/components/plugins/marketplace/search-box/tags-filter.tsx b/web/app/components/plugins/marketplace/search-box/tags-filter.tsx index 416cc99b91..dec07d0319 100644 --- a/web/app/components/plugins/marketplace/search-box/tags-filter.tsx +++ b/web/app/components/plugins/marketplace/search-box/tags-filter.tsx @@ -52,7 +52,10 @@ const TagsFilter = ({ open={open} onOpenChange={setOpen} > - setOpen(v => !v)}> + setOpen(v => !v)} + >
+ inputsRef: any + onFormChange: (value: Record) => void +} +const AppInputsForm = ({ + inputsForms, + inputs, + inputsRef, + onFormChange, +}: Props) => { + const { t } = useTranslation() + + const handleFormChange = useCallback((variable: string, value: any) => { + onFormChange({ + ...inputsRef.current, + [variable]: value, + }) + }, [onFormChange, inputsRef]) + + const renderField = (form: any) => { + const { + label, + variable, + options, + } = form + if (form.type === InputVarType.textInput) { + return ( + handleFormChange(variable, e.target.value)} + placeholder={label} + /> + ) + } + if (form.type === InputVarType.number) { + return ( + handleFormChange(variable, e.target.value)} + placeholder={label} + /> + ) + } + if (form.type === InputVarType.paragraph) { + return ( +