- Please make sure that you only install plugins from a trusted source.
+ {step !== 'installed' && 'Please make sure that you only install plugins from a trusted source.'}
-
+
{step === 'url' && (
<>
= ({ onClose }) => {
/>
>
)}
+ {step === 'installed' && (
+ <>
+ The plugin has been installed successfully.
+
+ {[
+ { label: 'Repository', value: repoUrl },
+ { label: 'Version', value: selectedVersion },
+ { label: 'Package', value: selectedPackage },
+ ].map(({ label, value }) => (
+
+ ))}
+
+ >
+ )}
-
- Cancel
-
-
- {step === 'package' ? 'Install' : 'Next'}
-
+ {step === 'installed'
+ ? (
+
+ Close
+
+ )
+ : (
+ <>
+
+ Cancel
+
+
+ {step === 'package' ? 'Install' : 'Next'}
+
+ >
+ )}
)
diff --git a/web/app/components/plugins/install-plugin/install-from-local-package/index.tsx b/web/app/components/plugins/install-plugin/install-from-local-package/index.tsx
index c8863faf79..87e470584e 100644
--- a/web/app/components/plugins/install-plugin/install-from-local-package/index.tsx
+++ b/web/app/components/plugins/install-plugin/install-from-local-package/index.tsx
@@ -1,9 +1,13 @@
'use client'
-import React from 'react'
+import React, { useCallback, useEffect, useState } from 'react'
+import { useContext } from 'use-context-selector'
import { RiLoader2Line } from '@remixicon/react'
+import Card from '../../card'
+import { toolNotion } from '../../card/card-mock'
import Modal from '@/app/components/base/modal'
import Button from '@/app/components/base/button'
+import I18n from '@/context/i18n'
type InstallFromLocalPackageProps = {
file: File
@@ -11,12 +15,48 @@ type InstallFromLocalPackageProps = {
}
const InstallFromLocalPackage: React.FC
= ({ onClose }) => {
+ const [status, setStatus] = useState<'uploading' | 'ready' | 'installing' | 'installed'>('uploading')
+ const { locale } = useContext(I18n)
+
+ useEffect(() => {
+ const timer = setTimeout(() => setStatus('ready'), 1500)
+ return () => clearTimeout(timer)
+ }, [])
+
+ const handleInstall = useCallback(async () => {
+ setStatus('installing')
+ await new Promise(resolve => setTimeout(resolve, 1000))
+ setStatus('installed')
+ }, [])
+
+ const renderStatusMessage = () => {
+ switch (status) {
+ case 'uploading':
+ return (
+
+
+
+ Uploading notion-sync.difypkg ...
+
+
+ )
+ case 'installed':
+ return The plugin has been installed successfully.
+ default:
+ return (
+
+
About to install the following plugin.
+
Please make sure that you only install plugins from a trusted source .
+
+ )
+ }
+ }
+
return (
@@ -25,28 +65,38 @@ const InstallFromLocalPackage: React.FC = ({ onClo
-
-
-
- Uploading notion-sync.difypkg ...
-
+ {renderStatusMessage()}
+
+
-
- Cancel
-
-
- Install
-
+ {status === 'installed'
+ ? (
+ Close
+ )
+ : (
+ <>
+
+ Cancel
+
+
+ {status === 'installing' ? 'Installing...' : 'Install'}
+
+ >
+ )}
)
diff --git a/web/app/components/plugins/install-plugin/install-from-marketplace/index.tsx b/web/app/components/plugins/install-plugin/install-from-marketplace/index.tsx
index 524588132f..96deec4da9 100644
--- a/web/app/components/plugins/install-plugin/install-from-marketplace/index.tsx
+++ b/web/app/components/plugins/install-plugin/install-from-marketplace/index.tsx
@@ -1,6 +1,6 @@
'use client'
-import React, { useState } from 'react'
+import React, { useMemo, useState } from 'react'
import { useContext } from 'use-context-selector'
import { RiInformation2Line } from '@remixicon/react'
import Card from '../../card'
@@ -17,88 +17,119 @@ type InstallFromMarketplaceProps = {
const InstallFromMarketplace: React.FC
= ({ onClose }) => {
const { locale } = useContext(I18n)
-
- // Mock a plugin list
- const plugins = [toolNotion, extensionDallE, modelGPT4]
+ const plugins = useMemo(() => [toolNotion, extensionDallE, modelGPT4], [])
const [selectedPlugins, setSelectedPlugins] = useState>(new Set())
+ const [isInstalling, setIsInstalling] = useState(false)
+ const [nextStep, setNextStep] = useState(false)
+
+ const mockInstall = async () => {
+ setIsInstalling(true)
+ await new Promise(resolve => setTimeout(resolve, 1500))
+ setIsInstalling(false)
+ }
+
+ const pluginsToShow = useMemo(() => {
+ if (plugins.length === 1 || (nextStep && selectedPlugins.size === 1))
+ return plugins.length === 1 ? plugins : plugins.filter((_, index) => selectedPlugins.has(index))
+
+ return nextStep ? plugins.filter((_, index) => selectedPlugins.has(index)) : plugins
+ }, [plugins, nextStep, selectedPlugins])
+
+ const renderPluginCard = (plugin: any, index: number) => (
+ {plugin.version}
+ )
+ : (
+ <>
+
+ {`${plugin.version} -> ${plugin.latest_version}`}
+
+
+ >
+ )
+ }
+ />
+ )
return (
-
Install plugin
+
+ {nextStep ? (isInstalling ? 'Install plugin' : 'Installation successful') : 'Install plugin'}
+
-
About to install the following plugin
+
+ {(nextStep && !isInstalling)
+ ? `The following ${pluginsToShow.length === 1 ? 'plugin has' : `${pluginsToShow.length} plugins have`} been installed successfully`
+ : `About to install the following ${pluginsToShow.length === 1 ? 'plugin' : `${pluginsToShow.length} plugins`}`}
+
-
- {plugins.length === 1
- &&
-
- }
- {plugins.length > 1 && plugins.map((plugin, index) => (
-
-
{
- const newSelectedPlugins = new Set(selectedPlugins)
- if (newSelectedPlugins.has(index))
- newSelectedPlugins.delete(index)
- else
- newSelectedPlugins.add(index)
-
- setSelectedPlugins(newSelectedPlugins)
- }}
- />
- {plugin.version}
- : <>
- {`${plugin.version} -> ${plugin.latest_version}`}
-
-
- >
- }
- />
+
+ {pluginsToShow.map((plugin, index) => (
+
1 && !nextStep) ? 'pl-1 items-center gap-2' : ''} flex-grow`}>
+ {(plugins.length > 1 && !nextStep) && (
+ {
+ const newSelectedPlugins = new Set(selectedPlugins)
+ newSelectedPlugins.has(index) ? newSelectedPlugins.delete(index) : newSelectedPlugins.add(index)
+ setSelectedPlugins(newSelectedPlugins)
+ }}
+ />
+ )}
+ {renderPluginCard(plugin, index)}
))}
-
- Cancel
-
-
- Install
-
+ {nextStep
+ ? (
+
+ {isInstalling ? 'Installing...' : 'Close'}
+
+ )
+ : (
+ <>
+
+ Cancel
+
+ 1 && selectedPlugins.size < 1}
+ onClick={() => {
+ setNextStep(true)
+ mockInstall()
+ }}
+ >
+ Install
+
+ >
+ )}
)