This commit is contained in:
2025-12-01 17:21:38 +08:00
parent 32fee2b8ab
commit fab8c13cb3
7511 changed files with 996300 additions and 0 deletions

View File

@@ -0,0 +1,33 @@
import { useCheckInstalled as useDoCheckInstalled } from '@/service/use-plugins'
import { useMemo } from 'react'
import type { VersionInfo } from '../../types'
type Props = {
pluginIds: string[],
enabled: boolean
}
const useCheckInstalled = (props: Props) => {
const { data, isLoading, error } = useDoCheckInstalled(props)
const installedInfo = useMemo(() => {
if (!data)
return undefined
const res: Record<string, VersionInfo> = {}
data?.plugins.forEach((plugin) => {
res[plugin.plugin_id] = {
installedId: plugin.id,
installedVersion: plugin.declaration.version,
uniqueIdentifier: plugin.plugin_unique_identifier,
}
})
return res
}, [data])
return {
installedInfo,
isLoading,
error,
}
}
export default useCheckInstalled

View File

@@ -0,0 +1,57 @@
import { sleep } from '@/utils'
const animTime = 750
const modalClassName = 'install-modal'
const COUNT_DOWN_TIME = 15000 // 15s
function getElemCenter(elem: HTMLElement) {
const rect = elem.getBoundingClientRect()
return {
x: rect.left + rect.width / 2 + window.scrollX,
y: rect.top + rect.height / 2 + window.scrollY,
}
}
const useFoldAnimInto = (onClose: () => void) => {
let countDownRunId: number
const clearCountDown = () => {
clearTimeout(countDownRunId)
}
// modalElem fold into plugin install task btn
const foldIntoAnim = async () => {
clearCountDown()
const modalElem = document.querySelector(`.${modalClassName}`) as HTMLElement
const pluginTaskTriggerElem = document.getElementById('plugin-task-trigger') || document.querySelector('.plugins-nav-button')
if (!modalElem || !pluginTaskTriggerElem) {
onClose()
return
}
const modelCenter = getElemCenter(modalElem)
const modalElemRect = modalElem.getBoundingClientRect()
const pluginTaskTriggerCenter = getElemCenter(pluginTaskTriggerElem)
const xDiff = pluginTaskTriggerCenter.x - modelCenter.x
const yDiff = pluginTaskTriggerCenter.y - modelCenter.y
const scale = 1 / Math.max(modalElemRect.width, modalElemRect.height)
modalElem.style.transition = `all cubic-bezier(0.4, 0, 0.2, 1) ${animTime}ms`
modalElem.style.transform = `translate(${xDiff}px, ${yDiff}px) scale(${scale})`
await sleep(animTime)
onClose()
}
const countDownFoldIntoAnim = async () => {
countDownRunId = window.setTimeout(() => {
foldIntoAnim()
}, COUNT_DOWN_TIME)
}
return {
modalClassName,
foldIntoAnim,
clearCountDown,
countDownFoldIntoAnim,
}
}
export default useFoldAnimInto

View File

@@ -0,0 +1,40 @@
import { useCallback, useState } from 'react'
import useFoldAnimInto from './use-fold-anim-into'
const useHideLogic = (onClose: () => void) => {
const {
modalClassName,
foldIntoAnim: doFoldAnimInto,
clearCountDown,
countDownFoldIntoAnim,
} = useFoldAnimInto(onClose)
const [isInstalling, doSetIsInstalling] = useState(false)
const setIsInstalling = useCallback((isInstalling: boolean) => {
if (!isInstalling)
clearCountDown()
doSetIsInstalling(isInstalling)
}, [clearCountDown])
const foldAnimInto = useCallback(() => {
if (isInstalling) {
doFoldAnimInto()
return
}
onClose()
}, [doFoldAnimInto, isInstalling, onClose])
const handleStartToInstall = useCallback(() => {
setIsInstalling(true)
countDownFoldIntoAnim()
}, [countDownFoldIntoAnim, setIsInstalling])
return {
modalClassName,
foldAnimInto,
setIsInstalling,
handleStartToInstall,
}
}
export default useHideLogic

View File

@@ -0,0 +1,46 @@
import { useGlobalPublicStore } from '@/context/global-public-context'
import type { SystemFeatures } from '@/types/feature'
import { InstallationScope } from '@/types/feature'
import type { Plugin, PluginManifestInMarket } from '../../types'
type PluginProps = (Plugin | PluginManifestInMarket) & { from: 'github' | 'marketplace' | 'package' }
export function pluginInstallLimit(plugin: PluginProps, systemFeatures: SystemFeatures) {
if (systemFeatures.plugin_installation_permission.restrict_to_marketplace_only) {
if (plugin.from === 'github' || plugin.from === 'package')
return { canInstall: false }
}
if (systemFeatures.plugin_installation_permission.plugin_installation_scope === InstallationScope.ALL) {
return {
canInstall: true,
}
}
if (systemFeatures.plugin_installation_permission.plugin_installation_scope === InstallationScope.NONE) {
return {
canInstall: false,
}
}
const verification = plugin.verification || {}
if (!plugin.verification || !plugin.verification.authorized_category)
verification.authorized_category = 'langgenius'
if (systemFeatures.plugin_installation_permission.plugin_installation_scope === InstallationScope.OFFICIAL_ONLY) {
return {
canInstall: verification.authorized_category === 'langgenius',
}
}
if (systemFeatures.plugin_installation_permission.plugin_installation_scope === InstallationScope.OFFICIAL_AND_PARTNER) {
return {
canInstall: verification.authorized_category === 'langgenius' || verification.authorized_category === 'partner',
}
}
return {
canInstall: true,
}
}
export default function usePluginInstallLimit(plugin: PluginProps) {
const systemFeatures = useGlobalPublicStore(s => s.systemFeatures)
return pluginInstallLimit(plugin, systemFeatures)
}

View File

@@ -0,0 +1,67 @@
import { useModelList } from '@/app/components/header/account-setting/model-provider-page/hooks'
import { ModelTypeEnum } from '@/app/components/header/account-setting/model-provider-page/declarations'
import { useProviderContext } from '@/context/provider-context'
import { useInvalidateInstalledPluginList } from '@/service/use-plugins'
import { useInvalidateAllBuiltInTools, useInvalidateAllToolProviders, useInvalidateRAGRecommendedPlugins } from '@/service/use-tools'
import { useInvalidateStrategyProviders } from '@/service/use-strategy'
import type { Plugin, PluginDeclaration, PluginManifestInMarket } from '../../types'
import { PluginCategoryEnum } from '../../types'
import { useInvalidDataSourceList } from '@/service/use-pipeline'
import { useInvalidDataSourceListAuth } from '@/service/use-datasource'
import { useInvalidateAllTriggerPlugins } from '@/service/use-triggers'
const useRefreshPluginList = () => {
const invalidateInstalledPluginList = useInvalidateInstalledPluginList()
const { mutate: refetchLLMModelList } = useModelList(ModelTypeEnum.textGeneration)
const { mutate: refetchEmbeddingModelList } = useModelList(ModelTypeEnum.textEmbedding)
const { mutate: refetchRerankModelList } = useModelList(ModelTypeEnum.rerank)
const { refreshModelProviders } = useProviderContext()
const invalidateAllToolProviders = useInvalidateAllToolProviders()
const invalidateAllBuiltInTools = useInvalidateAllBuiltInTools()
const invalidateAllDataSources = useInvalidDataSourceList()
const invalidateDataSourceListAuth = useInvalidDataSourceListAuth()
const invalidateStrategyProviders = useInvalidateStrategyProviders()
const invalidateAllTriggerPlugins = useInvalidateAllTriggerPlugins()
const invalidateRAGRecommendedPlugins = useInvalidateRAGRecommendedPlugins()
return {
refreshPluginList: (manifest?: PluginManifestInMarket | Plugin | PluginDeclaration | null, refreshAllType?: boolean) => {
// installed list
invalidateInstalledPluginList()
// tool page, tool select
if ((manifest && PluginCategoryEnum.tool.includes(manifest.category)) || refreshAllType) {
invalidateAllToolProviders()
invalidateAllBuiltInTools()
invalidateRAGRecommendedPlugins()
// TODO: update suggested tools. It's a function in hook useMarketplacePlugins,handleUpdatePlugins
}
if ((manifest && PluginCategoryEnum.trigger.includes(manifest.category)) || refreshAllType)
invalidateAllTriggerPlugins()
if ((manifest && PluginCategoryEnum.datasource.includes(manifest.category)) || refreshAllType) {
invalidateAllDataSources()
invalidateDataSourceListAuth()
}
// model select
if ((manifest && PluginCategoryEnum.model.includes(manifest.category)) || refreshAllType) {
refreshModelProviders()
refetchLLMModelList()
refetchEmbeddingModelList()
refetchRerankModelList()
}
// agent select
if ((manifest && PluginCategoryEnum.agent.includes(manifest.category)) || refreshAllType)
invalidateStrategyProviders()
},
}
}
export default useRefreshPluginList