+
{
plugins && (
-
{plugins.length} results
+
{t('plugin.marketplace.pluginsResult', { num: plugins.length })}
)
}
-
+ {
+ isLoading && (
+
+
+
+ )
+ }
+ {
+ !isLoading && (
+
+ )
+ }
)
}
diff --git a/web/app/components/plugins/marketplace/sort-dropdown/index.tsx b/web/app/components/plugins/marketplace/sort-dropdown/index.tsx
index ed1d788b29..df520f26c1 100644
--- a/web/app/components/plugins/marketplace/sort-dropdown/index.tsx
+++ b/web/app/components/plugins/marketplace/sort-dropdown/index.tsx
@@ -4,6 +4,7 @@ import {
RiArrowDownSLine,
RiCheckLine,
} from '@remixicon/react'
+import { useTranslation } from 'react-i18next'
import { useMarketplaceContext } from '../context'
import {
PortalToFollowElem,
@@ -11,30 +12,30 @@ import {
PortalToFollowElemTrigger,
} from '@/app/components/base/portal-to-follow-elem'
-const options = [
- {
- value: 'install_count',
- order: 'DESC',
- text: 'Most Popular',
- },
- {
- value: 'version_updated_at',
- order: 'DESC',
- text: 'Recently Updated',
- },
- {
- value: 'created_at',
- order: 'DESC',
- text: 'Newly Released',
- },
- {
- value: 'created_at',
- order: 'ASC',
- text: 'First Released',
- },
-]
-
const SortDropdown = () => {
+ const { t } = useTranslation()
+ const options = [
+ {
+ value: 'install_count',
+ order: 'DESC',
+ text: t('plugin.marketplace.sortOption.mostPopular'),
+ },
+ {
+ value: 'version_updated_at',
+ order: 'DESC',
+ text: t('plugin.marketplace.sortOption.recentlyUpdated'),
+ },
+ {
+ value: 'created_at',
+ order: 'DESC',
+ text: t('plugin.marketplace.sortOption.newlyReleased'),
+ },
+ {
+ value: 'created_at',
+ order: 'ASC',
+ text: t('plugin.marketplace.sortOption.firstReleased'),
+ },
+ ]
const sort = useMarketplaceContext(v => v.sort)
const handleSortChange = useMarketplaceContext(v => v.handleSortChange)
const [open, setOpen] = useState(false)
@@ -53,7 +54,7 @@ const SortDropdown = () => {
setOpen(v => !v)}>
- Sort by
+ {t('plugin.marketplace.sortBy')}
{selectedOption.text}
diff --git a/web/app/components/plugins/plugin-detail-panel/action-list.tsx b/web/app/components/plugins/plugin-detail-panel/action-list.tsx
index c90f1ffb0d..609e7d1306 100644
--- a/web/app/components/plugins/plugin-detail-panel/action-list.tsx
+++ b/web/app/components/plugins/plugin-detail-panel/action-list.tsx
@@ -1,5 +1,4 @@
import React, { useState } from 'react'
-import useSWR from 'swr'
import { useTranslation } from 'react-i18next'
import { usePluginPageContext } from '@/app/components/plugins/plugin-page/context'
import { useAppContext } from '@/context/app-context'
@@ -9,28 +8,39 @@ import Indicator from '@/app/components/header/indicator'
import ToolItem from '@/app/components/tools/provider/tool-item'
import ConfigCredential from '@/app/components/tools/setting/build-in/config-credentials'
import {
- fetchBuiltInToolList,
- fetchCollectionDetail,
- removeBuiltInToolCredential,
- updateBuiltInToolCredential,
-} from '@/service/tools'
+ useBuiltinProviderInfo,
+ useBuiltinTools,
+ useInvalidateBuiltinProviderInfo,
+ useRemoveProviderCredentials,
+ useUpdateProviderCredentials,
+} from '@/service/use-tools'
const ActionList = () => {
const { t } = useTranslation()
const { isCurrentWorkspaceManager } = useAppContext()
const currentPluginDetail = usePluginPageContext(v => v.currentPluginDetail)
- const { data: provider } = useSWR(
- `builtin/${currentPluginDetail.plugin_id}/${currentPluginDetail.name}`,
- fetchCollectionDetail,
- )
- const { data } = useSWR(
- `${currentPluginDetail.plugin_id}/${currentPluginDetail.name}`,
- fetchBuiltInToolList,
- )
+ const { data: provider } = useBuiltinProviderInfo(`${currentPluginDetail.plugin_id}/${currentPluginDetail.name}`)
+ const invalidateProviderInfo = useInvalidateBuiltinProviderInfo()
+ const { data } = useBuiltinTools(`${currentPluginDetail.plugin_id}/${currentPluginDetail.name}`)
const [showSettingAuth, setShowSettingAuth] = useState(false)
- const handleCredentialSettingUpdate = () => {}
+ const handleCredentialSettingUpdate = () => {
+ invalidateProviderInfo(`${currentPluginDetail.plugin_id}/${currentPluginDetail.name}`)
+ Toast.notify({
+ type: 'success',
+ message: t('common.api.actionSuccess'),
+ })
+ setShowSettingAuth(false)
+ }
+
+ const { mutate: updatePermission } = useUpdateProviderCredentials({
+ onSuccess: handleCredentialSettingUpdate,
+ })
+
+ const { mutate: removePermission } = useRemoveProviderCredentials({
+ onSuccess: handleCredentialSettingUpdate,
+ })
if (!data || !provider)
return null
@@ -77,24 +87,11 @@ const ActionList = () => {
setShowSettingAuth(false)}
- onSaved={async (value) => {
- await updateBuiltInToolCredential(provider.name, value)
- Toast.notify({
- type: 'success',
- message: t('common.api.actionSuccess'),
- })
- handleCredentialSettingUpdate()
- setShowSettingAuth(false)
- }}
- onRemove={async () => {
- await removeBuiltInToolCredential(provider.name)
- Toast.notify({
- type: 'success',
- message: t('common.api.actionSuccess'),
- })
- handleCredentialSettingUpdate()
- setShowSettingAuth(false)
- }}
+ onSaved={async value => updatePermission({
+ providerName: provider.name,
+ credentials: value,
+ })}
+ onRemove={async () => removePermission(provider.name)}
/>
)}
diff --git a/web/app/components/plugins/plugin-detail-panel/detail-header.tsx b/web/app/components/plugins/plugin-detail-panel/detail-header.tsx
index b40f264967..97e61b66d8 100644
--- a/web/app/components/plugins/plugin-detail-panel/detail-header.tsx
+++ b/web/app/components/plugins/plugin-detail-panel/detail-header.tsx
@@ -28,7 +28,7 @@ import { Github } from '@/app/components/base/icons/src/public/common'
import { uninstallPlugin } from '@/service/plugins'
import { useGetLanguage } from '@/context/i18n'
import { useModalContext } from '@/context/modal-context'
-
+import UpdateFromMarketplace from '@/app/components/plugins/update-plugin/from-market-place'
import { API_PREFIX, MARKETPLACE_URL_PREFIX } from '@/config'
import cn from '@/utils/classnames'
@@ -55,17 +55,35 @@ const DetailHeader = ({
source,
tenant_id,
version,
+ latest_unique_identifier,
latest_version,
meta,
} = detail
const { author, name, label, description, icon, verified } = detail.declaration
const isFromGitHub = source === PluginSource.github
+ const isFromMarketplace = source === PluginSource.marketplace
const hasNewVersion = useMemo(() => {
- return source === PluginSource.github && latest_version !== version
- }, [source, latest_version, version])
+ if (isFromGitHub)
+ return latest_version !== version
+
+ if (isFromMarketplace)
+ return !!latest_version && latest_version !== version
+
+ return false
+ }, [isFromGitHub, isFromMarketplace, latest_version, version])
+
+ const [isShowUpdateModal, {
+ setTrue: showUpdateModal,
+ setFalse: hideUpdateModal,
+ }] = useBoolean(false)
const handleUpdate = async () => {
+ if (isFromMarketplace) {
+ showUpdateModal()
+ return
+ }
+
try {
const fetchedReleases = await fetchReleases(author, name)
if (fetchedReleases.length === 0)
@@ -106,6 +124,11 @@ const DetailHeader = ({
}
}
+ const handleUpdatedFromMarketplace = () => {
+ onUpdate()
+ hideUpdateModal()
+ }
+
const [isShowPluginInfo, {
setTrue: showPluginInfo,
setFalse: hidePluginInfo,
@@ -222,6 +245,24 @@ const DetailHeader = ({
isDisabled={deleting}
/>
)}
+ {
+ isShowUpdateModal && (
+
+ )
+ }
)
}
diff --git a/web/app/components/plugins/plugin-detail-panel/endpoint-card.tsx b/web/app/components/plugins/plugin-detail-panel/endpoint-card.tsx
index 1a984b4eda..14e9abef9b 100644
--- a/web/app/components/plugins/plugin-detail-panel/endpoint-card.tsx
+++ b/web/app/components/plugins/plugin-detail-panel/endpoint-card.tsx
@@ -13,11 +13,11 @@ import Indicator from '@/app/components/header/indicator'
import Switch from '@/app/components/base/switch'
import Toast from '@/app/components/base/toast'
import {
- deleteEndpoint,
- disableEndpoint,
- enableEndpoint,
- updateEndpoint,
-} from '@/service/plugins'
+ useDeleteEndpoint,
+ useDisableEndpoint,
+ useEnableEndpoint,
+ useUpdateEndpoint,
+} from '@/service/use-endpoints'
type Props = {
data: EndpointListItem
@@ -32,43 +32,34 @@ const EndpointCard = ({
const [active, setActive] = useState(data.enabled)
const endpointID = data.id
+ // switch
const [isShowDisableConfirm, {
setTrue: showDisableConfirm,
setFalse: hideDisableConfirm,
}] = useBoolean(false)
- const activeEndpoint = async () => {
- try {
- await enableEndpoint({
- url: '/workspaces/current/endpoints/enable',
- endpointID,
- })
+ const { mutate: enableEndpoint } = useEnableEndpoint({
+ onSuccess: async () => {
await handleChange()
- }
- catch (error: any) {
- console.error(error)
+ },
+ onError: () => {
Toast.notify({ type: 'error', message: t('common.actionMsg.modifiedUnsuccessfully') })
setActive(false)
- }
- }
- const inactiveEndpoint = async () => {
- try {
- await disableEndpoint({
- url: '/workspaces/current/endpoints/disable',
- endpointID,
- })
+ },
+ })
+ const { mutate: disableEndpoint } = useDisableEndpoint({
+ onSuccess: async () => {
await handleChange()
hideDisableConfirm()
- }
- catch (error) {
- console.error(error)
+ },
+ onError: () => {
Toast.notify({ type: 'error', message: t('common.actionMsg.modifiedUnsuccessfully') })
- setActive(true)
- }
- }
+ setActive(false)
+ },
+ })
const handleSwitch = (state: boolean) => {
if (state) {
setActive(true)
- activeEndpoint()
+ enableEndpoint(endpointID)
}
else {
setActive(false)
@@ -76,30 +67,26 @@ const EndpointCard = ({
}
}
+ // delete
const [isShowDeleteConfirm, {
setTrue: showDeleteConfirm,
setFalse: hideDeleteConfirm,
}] = useBoolean(false)
- const handleDelete = async () => {
- try {
- await deleteEndpoint({
- url: '/workspaces/current/endpoints/delete',
- endpointID,
- })
+ const { mutate: deleteEndpoint } = useDeleteEndpoint({
+ onSuccess: async () => {
await handleChange()
hideDeleteConfirm()
- }
- catch (error) {
- console.error(error)
+ },
+ onError: () => {
Toast.notify({ type: 'error', message: t('common.actionMsg.modifiedUnsuccessfully') })
- }
- }
+ },
+ })
+ // update
const [isShowEndpointModal, {
setTrue: showEndpointModalConfirm,
setFalse: hideEndpointModalConfirm,
}] = useBoolean(false)
-
const formSchemas = useMemo(() => {
return toolCredentialToFormSchemas([NAME_FIELD, ...data.declaration.settings])
}, [data.declaration.settings])
@@ -110,27 +97,19 @@ const EndpointCard = ({
}
return addDefaultValue(formValue, formSchemas)
}, [data.name, data.settings, formSchemas])
-
- const handleUpdate = async (state: any) => {
- const newName = state.name
- delete state.name
- try {
- await updateEndpoint({
- url: '/workspaces/current/endpoints/update',
- body: {
- endpoint_id: data.id,
- settings: state,
- name: newName,
- },
- })
+ const { mutate: updateEndpoint } = useUpdateEndpoint({
+ onSuccess: async () => {
await handleChange()
hideEndpointModalConfirm()
- }
- catch (error) {
- console.error(error)
+ },
+ onError: () => {
Toast.notify({ type: 'error', message: t('common.actionMsg.modifiedUnsuccessfully') })
- }
- }
+ },
+ })
+ const handleUpdate = (state: any) => updateEndpoint({
+ endpointID,
+ state,
+ })
return (
@@ -192,7 +171,7 @@ const EndpointCard = ({
hideDisableConfirm()
setActive(true)
}}
- onConfirm={inactiveEndpoint}
+ onConfirm={() => disableEndpoint(endpointID)}
/>
)}
{isShowDeleteConfirm && (
@@ -201,7 +180,7 @@ const EndpointCard = ({
title={t('plugin.detailPanel.endpointDeleteTip')}
content={
{t('plugin.detailPanel.endpointDeleteContent', { name: data.name })}
}
onCancel={hideDeleteConfirm}
- onConfirm={handleDelete}
+ onConfirm={() => deleteEndpoint(endpointID)}
/>
)}
{isShowEndpointModal && (
diff --git a/web/app/components/plugins/plugin-detail-panel/endpoint-list.tsx b/web/app/components/plugins/plugin-detail-panel/endpoint-list.tsx
index 6323e42365..b5f5d2768e 100644
--- a/web/app/components/plugins/plugin-detail-panel/endpoint-list.tsx
+++ b/web/app/components/plugins/plugin-detail-panel/endpoint-list.tsx
@@ -1,6 +1,5 @@
import React, { useMemo } from 'react'
import { useTranslation } from 'react-i18next'
-import useSWR from 'swr'
import { useBoolean } from 'ahooks'
import { RiAddLine } from '@remixicon/react'
import EndpointModal from './endpoint-modal'
@@ -12,9 +11,10 @@ import Tooltip from '@/app/components/base/tooltip'
import Toast from '@/app/components/base/toast'
import { usePluginPageContext } from '@/app/components/plugins/plugin-page/context'
import {
- createEndpoint,
- fetchEndpointList,
-} from '@/service/plugins'
+ useCreateEndpoint,
+ useEndpointList,
+ useInvalidateEndpointList,
+} from '@/service/use-endpoints'
import cn from '@/utils/classnames'
type Props = {
@@ -25,17 +25,9 @@ const EndpointList = ({ showTopBorder }: Props) => {
const pluginDetail = usePluginPageContext(v => v.currentPluginDetail)
const pluginUniqueID = pluginDetail.plugin_unique_identifier
const declaration = pluginDetail.declaration.endpoint
- const { data, mutate } = useSWR(
- {
- url: '/workspaces/current/endpoints/list/plugin',
- params: {
- plugin_id: pluginDetail.plugin_id,
- page: 1,
- page_size: 100,
- },
- },
- fetchEndpointList,
- )
+ const { data } = useEndpointList(pluginDetail.plugin_id)
+ const invalidateEndpointList = useInvalidateEndpointList()
+
const [isShowEndpointModal, {
setTrue: showEndpointModal,
setFalse: hideEndpointModal,
@@ -45,26 +37,20 @@ const EndpointList = ({ showTopBorder }: Props) => {
return toolCredentialToFormSchemas([NAME_FIELD, ...declaration.settings])
}, [declaration.settings])
- const handleCreate = async (state: any) => {
- const newName = state.name
- delete state.name
- try {
- await createEndpoint({
- url: '/workspaces/current/endpoints/create',
- body: {
- plugin_unique_identifier: pluginUniqueID,
- settings: state,
- name: newName,
- },
- })
- await mutate()
+ const { mutate: createEndpoint } = useCreateEndpoint({
+ onSuccess: async () => {
+ await invalidateEndpointList(pluginDetail.plugin_id)
hideEndpointModal()
- }
- catch (error) {
- console.error(error)
+ },
+ onError: () => {
Toast.notify({ type: 'error', message: t('common.actionMsg.modifiedUnsuccessfully') })
- }
- }
+ },
+ })
+
+ const handleCreate = (state: any) => createEndpoint({
+ pluginUniqueID,
+ state,
+ })
if (!data)
return null
@@ -92,7 +78,7 @@ const EndpointList = ({ showTopBorder }: Props) => {
invalidateEndpointList(pluginDetail.plugin_id)}
/>
))}
diff --git a/web/app/components/plugins/plugin-detail-panel/endpoint-modal.tsx b/web/app/components/plugins/plugin-detail-panel/endpoint-modal.tsx
index c09de2bdb2..ca4813d3c6 100644
--- a/web/app/components/plugins/plugin-detail-panel/endpoint-modal.tsx
+++ b/web/app/components/plugins/plugin-detail-panel/endpoint-modal.tsx
@@ -69,7 +69,7 @@ const EndpointModal: FC