mirror of https://github.com/langgenius/dify.git
merge feat/plugins
This commit is contained in:
commit
9302a5fac8
|
|
@ -8,7 +8,7 @@ const PluginList = async () => {
|
|||
return (
|
||||
<PluginPage
|
||||
plugins={<PluginsPanel />}
|
||||
marketplace={<Marketplace locale={locale} />}
|
||||
marketplace={<Marketplace locale={locale} shouldExclude />}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -72,7 +72,6 @@ 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
|
||||
|
|
@ -1042,7 +1041,6 @@ const Configuration: FC = () => {
|
|||
onAutoAddPromptVariable={handleAddPromptVariable}
|
||||
/>
|
||||
)}
|
||||
<PluginDependency />
|
||||
</>
|
||||
</FeaturesProvider>
|
||||
</ConfigContext.Provider>
|
||||
|
|
|
|||
|
|
@ -25,7 +25,8 @@ import AppsFull from '@/app/components/billing/apps-full-in-dialog'
|
|||
import { NEED_REFRESH_APP_LIST_KEY } from '@/config'
|
||||
import { getRedirection } from '@/utils/app-redirection'
|
||||
import cn from '@/utils/classnames'
|
||||
import { useMutationCheckDependenciesBeforeImportDSL } from '@/service/use-plugins'
|
||||
import { useStore as usePluginDependencyStore } from '@/app/components/workflow/plugin-dependency/store'
|
||||
import PluginDependency from '@/app/components/workflow/plugin-dependency'
|
||||
|
||||
type CreateFromDSLModalProps = {
|
||||
show: boolean
|
||||
|
|
@ -48,7 +49,6 @@ const CreateFromDSLModal = ({ show, onSuccess, onClose, activeTab = CreateFromDS
|
|||
const [fileContent, setFileContent] = useState<string>()
|
||||
const [currentTab, setCurrentTab] = useState(activeTab)
|
||||
const [dslUrlValue, setDslUrlValue] = useState(dslUrl)
|
||||
const { mutateAsync } = useMutationCheckDependenciesBeforeImportDSL()
|
||||
const [showErrorModal, setShowErrorModal] = useState(false)
|
||||
const [versions, setVersions] = useState<{ importedVersion: string; systemVersion: string }>()
|
||||
const [importId, setImportId] = useState<string>()
|
||||
|
|
@ -92,20 +92,22 @@ const CreateFromDSLModal = ({ show, onSuccess, onClose, activeTab = CreateFromDS
|
|||
mode: DSLImportMode.YAML_CONTENT,
|
||||
yaml_content: fileContent || '',
|
||||
})
|
||||
await mutateAsync({ dslString: fileContent })
|
||||
}
|
||||
if (currentTab === CreateFromDSLModalTab.FROM_URL) {
|
||||
response = await importDSL({
|
||||
mode: DSLImportMode.YAML_URL,
|
||||
yaml_url: dslUrlValue || '',
|
||||
})
|
||||
await mutateAsync({ url: dslUrlValue })
|
||||
}
|
||||
|
||||
if (!response)
|
||||
return
|
||||
|
||||
const { id, status, app_id, imported_dsl_version, current_dsl_version } = response
|
||||
const { id, status, app_id, imported_dsl_version, current_dsl_version, leaked_dependencies } = response
|
||||
if (leaked_dependencies?.length) {
|
||||
const { setDependencies } = usePluginDependencyStore.getState()
|
||||
setDependencies(leaked_dependencies)
|
||||
}
|
||||
if (status === DSLImportStatus.COMPLETED || status === DSLImportStatus.COMPLETED_WITH_WARNINGS) {
|
||||
if (onSuccess)
|
||||
onSuccess()
|
||||
|
|
@ -272,7 +274,7 @@ const CreateFromDSLModal = ({ show, onSuccess, onClose, activeTab = CreateFromDS
|
|||
>
|
||||
<div className='flex pb-4 flex-col items-start gap-2 self-stretch'>
|
||||
<div className='text-text-primary title-2xl-semi-bold'>{t('app.newApp.appCreateDSLErrorTitle')}</div>
|
||||
<div className='flex flex-grow flex-col text-text-secondary system-md-regular'>
|
||||
<div className='flex grow flex-col text-text-secondary system-md-regular'>
|
||||
<div>{t('app.newApp.appCreateDSLErrorPart1')}</div>
|
||||
<div>{t('app.newApp.appCreateDSLErrorPart2')}</div>
|
||||
<br />
|
||||
|
|
@ -280,6 +282,7 @@ const CreateFromDSLModal = ({ show, onSuccess, onClose, activeTab = CreateFromDS
|
|||
<div>{t('app.newApp.appCreateDSLErrorPart4')}<span className='system-md-medium'>{versions?.systemVersion}</span></div>
|
||||
</div>
|
||||
</div>
|
||||
<PluginDependency />
|
||||
<div className='flex pt-6 justify-end items-start gap-2 self-stretch'>
|
||||
<Button variant='secondary' onClick={() => setShowErrorModal(false)}>{t('app.newApp.Cancel')}</Button>
|
||||
<Button variant='primary' destructive onClick={onDSLConfirm}>{t('app.newApp.Confirm')}</Button>
|
||||
|
|
|
|||
|
|
@ -263,7 +263,7 @@ describe('build chat item tree and get thread messages', () => {
|
|||
expect(tree7).toMatchSnapshot()
|
||||
})
|
||||
|
||||
const partialMessages2 = (partialMessages as ChatItemInTree[])
|
||||
const partialMessages2 = partialMessages as ChatItemInTree[]
|
||||
const tree8 = buildChatItemTree(partialMessages2)
|
||||
it('should work with partial messages 2', () => {
|
||||
expect(tree8).toMatchSnapshot()
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ const Toast = ({
|
|||
{type === 'warning' && <RiAlertFill className={`${size === 'md' ? 'w-5 h-5' : 'w-4 h-4'} text-text-warning-secondary`} aria-hidden="true" />}
|
||||
{type === 'info' && <RiInformation2Fill className={`${size === 'md' ? 'w-5 h-5' : 'w-4 h-4'} text-text-accent`} aria-hidden="true" />}
|
||||
</div>
|
||||
<div className={`flex py-1 ${size === 'md' ? 'px-1' : 'px-0.5'} flex-col items-start gap-1 flex-grow`}>
|
||||
<div className={`flex py-1 ${size === 'md' ? 'px-1' : 'px-0.5'} flex-col items-start gap-1 grow`}>
|
||||
<div className='text-text-primary system-sm-semibold'>{message}</div>
|
||||
{children && <div className='text-text-secondary system-xs-regular'>
|
||||
{children}
|
||||
|
|
@ -71,7 +71,7 @@ const Toast = ({
|
|||
}
|
||||
</div>
|
||||
<ActionButton className='z-[1000]' onClick={close}>
|
||||
<RiCloseLine className='w-4 h-4 flex-shrink-0 text-text-tertiary' />
|
||||
<RiCloseLine className='w-4 h-4 shrink-0 text-text-tertiary' />
|
||||
</ActionButton>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -135,7 +135,7 @@ const NewSegmentModal: FC<NewSegmentModalProps> = ({
|
|||
<div className='mb-8'>
|
||||
<TagInput items={keywords} onChange={newKeywords => setKeywords(newKeywords)} />
|
||||
</div>
|
||||
<div className='flex justify-end'>
|
||||
<div className='flex justify-end space-x-2'>
|
||||
<Button
|
||||
onClick={handleCancel}>
|
||||
{t('common.operation.cancel')}
|
||||
|
|
|
|||
|
|
@ -11,12 +11,14 @@ type Props = {
|
|||
checked: boolean
|
||||
onCheckedChange: (plugin: Plugin) => void
|
||||
payload: PackageDependency
|
||||
isFromMarketPlace?: boolean
|
||||
}
|
||||
|
||||
const PackageItem: FC<Props> = ({
|
||||
payload,
|
||||
checked,
|
||||
onCheckedChange,
|
||||
isFromMarketPlace,
|
||||
}) => {
|
||||
if (!payload.value?.manifest)
|
||||
return <LoadingError />
|
||||
|
|
@ -27,6 +29,7 @@ const PackageItem: FC<Props> = ({
|
|||
payload={plugin}
|
||||
checked={checked}
|
||||
onCheckedChange={onCheckedChange}
|
||||
isFromMarketPlace={isFromMarketPlace}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ type Props = {
|
|||
onStepChange: (step: InstallStep) => void,
|
||||
allPlugins: Dependency[]
|
||||
onClose: () => void
|
||||
isFromMarketPlace?: boolean
|
||||
}
|
||||
|
||||
const ReadyToInstall: FC<Props> = ({
|
||||
|
|
@ -18,6 +19,7 @@ const ReadyToInstall: FC<Props> = ({
|
|||
onStepChange,
|
||||
allPlugins,
|
||||
onClose,
|
||||
isFromMarketPlace,
|
||||
}) => {
|
||||
const [installedPlugins, setInstalledPlugins] = useState<Plugin[]>([])
|
||||
const [installStatus, setInstallStatus] = useState<InstallStatusResponse[]>([])
|
||||
|
|
@ -33,6 +35,7 @@ const ReadyToInstall: FC<Props> = ({
|
|||
allPlugins={allPlugins}
|
||||
onCancel={onClose}
|
||||
onInstalled={handleInstalled}
|
||||
isFromMarketPlace={isFromMarketPlace}
|
||||
/>
|
||||
)}
|
||||
{step === InstallStep.installed && (
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ type Props = {
|
|||
selectedPlugins: Plugin[]
|
||||
onSelect: (plugin: Plugin, selectedIndex: number) => void
|
||||
onLoadedAllPlugin: () => void
|
||||
isFromMarketPlace?: boolean
|
||||
}
|
||||
|
||||
const InstallByDSLList: FC<Props> = ({
|
||||
|
|
@ -21,9 +22,12 @@ const InstallByDSLList: FC<Props> = ({
|
|||
selectedPlugins,
|
||||
onSelect,
|
||||
onLoadedAllPlugin,
|
||||
isFromMarketPlace,
|
||||
}) => {
|
||||
const { isLoading: isFetchingMarketplaceDataFromDSL, data: marketplaceFromDSLRes } = useFetchPluginsInMarketPlaceByIds(allPlugins.filter(d => d.type === 'marketplace').map(d => (d as GitHubItemAndMarketPlaceDependency).value.plugin_unique_identifier!))
|
||||
const { isLoading: isFetchingMarketplaceDataFromLocal, data: marketplaceResFromLocalRes } = useFetchPluginsInMarketPlaceByInfo(allPlugins.filter(d => d.type === 'marketplace').map(d => (d as GitHubItemAndMarketPlaceDependency).value!))
|
||||
// DSL has id, to get plugin info to show more info
|
||||
const { isLoading: isFetchingMarketplaceDataById, data: infoGetById, error: infoByIdError } = useFetchPluginsInMarketPlaceByIds(allPlugins.filter(d => d.type === 'marketplace').map(d => (d as GitHubItemAndMarketPlaceDependency).value.plugin_unique_identifier!))
|
||||
// has meta(org,name,version), to get id
|
||||
const { isLoading: isFetchingDataByMeta, data: infoByMeta, error: infoByMetaError } = useFetchPluginsInMarketPlaceByInfo(allPlugins.filter(d => d.type === 'marketplace').map(d => (d as GitHubItemAndMarketPlaceDependency).value!))
|
||||
const [plugins, doSetPlugins] = useState<(Plugin | undefined)[]>((() => {
|
||||
const hasLocalPackage = allPlugins.some(d => d.type === 'package')
|
||||
if (!hasLocalPackage)
|
||||
|
|
@ -75,8 +79,8 @@ const InstallByDSLList: FC<Props> = ({
|
|||
}, [allPlugins])
|
||||
|
||||
useEffect(() => {
|
||||
if (!isFetchingMarketplaceDataFromDSL && marketplaceFromDSLRes?.data.plugins) {
|
||||
const payloads = marketplaceFromDSLRes?.data.plugins
|
||||
if (!isFetchingMarketplaceDataById && infoGetById?.data.plugins) {
|
||||
const payloads = infoGetById?.data.plugins
|
||||
const failedIndex: number[] = []
|
||||
const nextPlugins = produce(pluginsRef.current, (draft) => {
|
||||
marketPlaceInDSLIndex.forEach((index, i) => {
|
||||
|
|
@ -92,11 +96,11 @@ const InstallByDSLList: FC<Props> = ({
|
|||
setErrorIndexes([...errorIndexes, ...failedIndex])
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [isFetchingMarketplaceDataFromDSL])
|
||||
}, [isFetchingMarketplaceDataById])
|
||||
|
||||
useEffect(() => {
|
||||
if (!isFetchingMarketplaceDataFromLocal && marketplaceResFromLocalRes?.data.list) {
|
||||
const payloads = marketplaceResFromLocalRes?.data.list
|
||||
if (!isFetchingDataByMeta && infoByMeta?.data.list) {
|
||||
const payloads = infoByMeta?.data.list
|
||||
const failedIndex: number[] = []
|
||||
const nextPlugins = produce(pluginsRef.current, (draft) => {
|
||||
marketPlaceInDSLIndex.forEach((index, i) => {
|
||||
|
|
@ -117,7 +121,15 @@ const InstallByDSLList: FC<Props> = ({
|
|||
setErrorIndexes([...errorIndexes, ...failedIndex])
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [isFetchingMarketplaceDataFromLocal])
|
||||
}, [isFetchingDataByMeta])
|
||||
|
||||
useEffect(() => {
|
||||
// get info all failed
|
||||
if (infoByMetaError || infoByIdError)
|
||||
setErrorIndexes([...errorIndexes, ...marketPlaceInDSLIndex])
|
||||
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [infoByMetaError, infoByIdError])
|
||||
|
||||
const isLoadedAllData = (plugins.filter(p => !!p).length + errorIndexes.length) === allPlugins.length
|
||||
useEffect(() => {
|
||||
|
|
@ -161,12 +173,14 @@ const InstallByDSLList: FC<Props> = ({
|
|||
)
|
||||
}
|
||||
|
||||
// Local package
|
||||
return (
|
||||
<PackageItem
|
||||
key={index}
|
||||
checked={!!selectedPlugins.find(p => p.plugin_id === plugins[index]?.plugin_id)}
|
||||
onCheckedChange={handleSelect(index)}
|
||||
payload={d as PackageDependency}
|
||||
isFromMarketPlace={isFromMarketPlace}
|
||||
/>
|
||||
)
|
||||
})
|
||||
|
|
|
|||
|
|
@ -14,12 +14,14 @@ type Props = {
|
|||
allPlugins: Dependency[]
|
||||
onInstalled: (plugins: Plugin[], installStatus: InstallStatusResponse[]) => void
|
||||
onCancel: () => void
|
||||
isFromMarketPlace?: boolean
|
||||
}
|
||||
|
||||
const Install: FC<Props> = ({
|
||||
allPlugins,
|
||||
onInstalled,
|
||||
onCancel,
|
||||
isFromMarketPlace,
|
||||
}) => {
|
||||
const { t } = useTranslation()
|
||||
const [selectedPlugins, setSelectedPlugins] = React.useState<Plugin[]>([])
|
||||
|
|
@ -75,6 +77,7 @@ const Install: FC<Props> = ({
|
|||
selectedPlugins={selectedPlugins}
|
||||
onSelect={handleSelect}
|
||||
onLoadedAllPlugin={handleLoadedAllPlugin}
|
||||
isFromMarketPlace={isFromMarketPlace}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -41,12 +41,14 @@ const InstallFromMarketplace: React.FC<InstallFromMarketplaceProps> = ({
|
|||
// TODO: check installed in beta version.
|
||||
|
||||
const getTitle = useCallback(() => {
|
||||
if (isBundle && step === InstallStep.installed)
|
||||
return t(`${i18nPrefix}.installComplete`)
|
||||
if (step === InstallStep.installed)
|
||||
return t(`${i18nPrefix}.installedSuccessfully`)
|
||||
if (step === InstallStep.installFailed)
|
||||
return t(`${i18nPrefix}.installFailed`)
|
||||
return t(`${i18nPrefix}.installPlugin`)
|
||||
}, [step, t])
|
||||
}, [isBundle, step, t])
|
||||
|
||||
const handleInstalled = useCallback(() => {
|
||||
setStep(InstallStep.installed)
|
||||
|
|
@ -55,7 +57,7 @@ const InstallFromMarketplace: React.FC<InstallFromMarketplaceProps> = ({
|
|||
updateModelProviders()
|
||||
if (PluginType.tool.includes(manifest.category))
|
||||
invalidateAllToolProviders()
|
||||
}, [invalidateAllToolProviders, invalidateInstalledPluginList, manifest.category, updateModelProviders])
|
||||
}, [invalidateAllToolProviders, invalidateInstalledPluginList, manifest, updateModelProviders])
|
||||
|
||||
const handleFailed = useCallback((errorMsg?: string) => {
|
||||
setStep(InstallStep.installFailed)
|
||||
|
|
@ -76,17 +78,6 @@ const InstallFromMarketplace: React.FC<InstallFromMarketplaceProps> = ({
|
|||
{getTitle()}
|
||||
</div>
|
||||
</div>
|
||||
{
|
||||
step === InstallStep.readyToInstall && (
|
||||
<Install
|
||||
uniqueIdentifier={uniqueIdentifier}
|
||||
payload={manifest!}
|
||||
onCancel={onClose}
|
||||
onInstalled={handleInstalled}
|
||||
onFailed={handleFailed}
|
||||
/>
|
||||
)
|
||||
}
|
||||
{
|
||||
isBundle ? (
|
||||
<ReadyToInstallBundle
|
||||
|
|
@ -94,18 +85,34 @@ const InstallFromMarketplace: React.FC<InstallFromMarketplaceProps> = ({
|
|||
onStepChange={setStep}
|
||||
onClose={onClose}
|
||||
allPlugins={dependencies!}
|
||||
isFromMarketPlace
|
||||
/>
|
||||
) : ([InstallStep.installed, InstallStep.installFailed].includes(step)) && (
|
||||
<Installed
|
||||
payload={manifest!}
|
||||
isMarketPayload
|
||||
isFailed={step === InstallStep.installFailed}
|
||||
errMsg={errorMsg}
|
||||
onCancel={onSuccess}
|
||||
/>
|
||||
) : (<>
|
||||
{
|
||||
step === InstallStep.readyToInstall && (
|
||||
<Install
|
||||
uniqueIdentifier={uniqueIdentifier}
|
||||
payload={manifest!}
|
||||
onCancel={onClose}
|
||||
onInstalled={handleInstalled}
|
||||
onFailed={handleFailed}
|
||||
/>
|
||||
)}
|
||||
{
|
||||
[InstallStep.installed, InstallStep.installFailed].includes(step) && (
|
||||
<Installed
|
||||
payload={manifest!}
|
||||
isMarketPayload
|
||||
isFailed={step === InstallStep.installFailed}
|
||||
errMsg={errorMsg}
|
||||
onCancel={onSuccess}
|
||||
/>
|
||||
)
|
||||
}
|
||||
</>
|
||||
)
|
||||
}
|
||||
</Modal>
|
||||
</Modal >
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -94,7 +94,7 @@ const Installed: FC<Props> = ({
|
|||
</>
|
||||
)
|
||||
}</>)
|
||||
}, [payload.latest_version, supportCheckInstalled])
|
||||
}, [payload.latest_version, payload.version, supportCheckInstalled])
|
||||
|
||||
return (
|
||||
<>
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import type {
|
|||
import {
|
||||
useCallback,
|
||||
useEffect,
|
||||
useMemo,
|
||||
useRef,
|
||||
useState,
|
||||
} from 'react'
|
||||
|
|
@ -30,6 +31,7 @@ import {
|
|||
useMarketplacePlugins,
|
||||
} from './hooks'
|
||||
import { getMarketplaceListCondition } from './utils'
|
||||
import { useInstalledPluginList } from '@/service/use-plugins'
|
||||
|
||||
export type MarketplaceContextValue = {
|
||||
intersected: boolean
|
||||
|
|
@ -74,6 +76,7 @@ export const MarketplaceContext = createContext<MarketplaceContextValue>({
|
|||
type MarketplaceContextProviderProps = {
|
||||
children: ReactNode
|
||||
searchParams?: SearchParams
|
||||
shouldExclude?: boolean
|
||||
}
|
||||
|
||||
export function useMarketplaceContext(selector: (value: MarketplaceContextValue) => any) {
|
||||
|
|
@ -83,7 +86,13 @@ export function useMarketplaceContext(selector: (value: MarketplaceContextValue)
|
|||
export const MarketplaceContextProvider = ({
|
||||
children,
|
||||
searchParams,
|
||||
shouldExclude,
|
||||
}: MarketplaceContextProviderProps) => {
|
||||
const { data, isSuccess } = useInstalledPluginList(!shouldExclude)
|
||||
const exclude = useMemo(() => {
|
||||
if (shouldExclude)
|
||||
return data?.plugins.map(plugin => plugin.plugin_id)
|
||||
}, [data?.plugins, shouldExclude])
|
||||
const queryFromSearchParams = searchParams?.q || ''
|
||||
const tagsFromSearchParams = searchParams?.tags ? getValidTagKeys(searchParams.tags.split(',')) : []
|
||||
const hasValidTags = !!tagsFromSearchParams.length
|
||||
|
|
@ -125,8 +134,15 @@ export const MarketplaceContextProvider = ({
|
|||
})
|
||||
history.pushState({}, '', `/${searchParams?.language ? `?language=${searchParams?.language}` : ''}`)
|
||||
}
|
||||
else {
|
||||
if (shouldExclude && isSuccess) {
|
||||
queryMarketplaceCollectionsAndPlugins({
|
||||
exclude,
|
||||
})
|
||||
}
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [queryPlugins])
|
||||
}, [queryPlugins, queryMarketplaceCollectionsAndPlugins, isSuccess, exclude])
|
||||
|
||||
const handleSearchPluginTextChange = useCallback((text: string) => {
|
||||
setSearchPluginText(text)
|
||||
|
|
@ -136,6 +152,7 @@ export const MarketplaceContextProvider = ({
|
|||
queryMarketplaceCollectionsAndPlugins({
|
||||
category: activePluginTypeRef.current === PLUGIN_TYPE_SEARCH_MAP.all ? undefined : activePluginTypeRef.current,
|
||||
condition: getMarketplaceListCondition(activePluginTypeRef.current),
|
||||
exclude,
|
||||
})
|
||||
resetPlugins()
|
||||
|
||||
|
|
@ -148,8 +165,9 @@ export const MarketplaceContextProvider = ({
|
|||
tags: filterPluginTagsRef.current,
|
||||
sortBy: sortRef.current.sortBy,
|
||||
sortOrder: sortRef.current.sortOrder,
|
||||
exclude,
|
||||
})
|
||||
}, [queryPluginsWithDebounced, queryMarketplaceCollectionsAndPlugins, resetPlugins])
|
||||
}, [queryPluginsWithDebounced, queryMarketplaceCollectionsAndPlugins, resetPlugins, exclude])
|
||||
|
||||
const handleFilterPluginTagsChange = useCallback((tags: string[]) => {
|
||||
setFilterPluginTags(tags)
|
||||
|
|
@ -159,6 +177,7 @@ export const MarketplaceContextProvider = ({
|
|||
queryMarketplaceCollectionsAndPlugins({
|
||||
category: activePluginTypeRef.current === PLUGIN_TYPE_SEARCH_MAP.all ? undefined : activePluginTypeRef.current,
|
||||
condition: getMarketplaceListCondition(activePluginTypeRef.current),
|
||||
exclude,
|
||||
})
|
||||
resetPlugins()
|
||||
|
||||
|
|
@ -171,8 +190,9 @@ export const MarketplaceContextProvider = ({
|
|||
tags,
|
||||
sortBy: sortRef.current.sortBy,
|
||||
sortOrder: sortRef.current.sortOrder,
|
||||
exclude,
|
||||
})
|
||||
}, [queryPlugins, resetPlugins, queryMarketplaceCollectionsAndPlugins])
|
||||
}, [queryPlugins, resetPlugins, queryMarketplaceCollectionsAndPlugins, exclude])
|
||||
|
||||
const handleActivePluginTypeChange = useCallback((type: string) => {
|
||||
setActivePluginType(type)
|
||||
|
|
@ -182,6 +202,7 @@ export const MarketplaceContextProvider = ({
|
|||
queryMarketplaceCollectionsAndPlugins({
|
||||
category: type === PLUGIN_TYPE_SEARCH_MAP.all ? undefined : type,
|
||||
condition: getMarketplaceListCondition(type),
|
||||
exclude,
|
||||
})
|
||||
resetPlugins()
|
||||
|
||||
|
|
@ -194,8 +215,9 @@ export const MarketplaceContextProvider = ({
|
|||
tags: filterPluginTagsRef.current,
|
||||
sortBy: sortRef.current.sortBy,
|
||||
sortOrder: sortRef.current.sortOrder,
|
||||
exclude,
|
||||
})
|
||||
}, [queryPlugins, resetPlugins, queryMarketplaceCollectionsAndPlugins])
|
||||
}, [queryPlugins, resetPlugins, queryMarketplaceCollectionsAndPlugins, exclude])
|
||||
|
||||
const handleSortChange = useCallback((sort: PluginsSort) => {
|
||||
setSort(sort)
|
||||
|
|
@ -207,8 +229,9 @@ export const MarketplaceContextProvider = ({
|
|||
tags: filterPluginTagsRef.current,
|
||||
sortBy: sortRef.current.sortBy,
|
||||
sortOrder: sortRef.current.sortOrder,
|
||||
exclude,
|
||||
})
|
||||
}, [queryPlugins])
|
||||
}, [queryPlugins, exclude])
|
||||
|
||||
return (
|
||||
<MarketplaceContext.Provider
|
||||
|
|
|
|||
|
|
@ -17,7 +17,9 @@ import {
|
|||
getPluginIconInMarketplace,
|
||||
} from './utils'
|
||||
import i18n from '@/i18n/i18next-config'
|
||||
import { useMutationPluginsFromMarketplace } from '@/service/use-plugins'
|
||||
import {
|
||||
useMutationPluginsFromMarketplace,
|
||||
} from '@/service/use-plugins'
|
||||
|
||||
export const useMarketplaceCollectionsAndPlugins = () => {
|
||||
const [isLoading, setIsLoading] = useState(false)
|
||||
|
|
@ -55,7 +57,7 @@ export const useMarketplacePlugins = () => {
|
|||
mutate(pluginsSearchParams)
|
||||
}, [mutate])
|
||||
|
||||
const { run: queryPluginsWithDebounced } = useDebounceFn((pluginsSearchParams) => {
|
||||
const { run: queryPluginsWithDebounced } = useDebounceFn((pluginsSearchParams: PluginsSearchParams) => {
|
||||
mutate(pluginsSearchParams)
|
||||
}, {
|
||||
wait: 500,
|
||||
|
|
|
|||
|
|
@ -11,18 +11,26 @@ import { TanstackQueryIniter } from '@/context/query-client'
|
|||
type MarketplaceProps = {
|
||||
locale: string
|
||||
showInstallButton?: boolean
|
||||
shouldExclude?: boolean
|
||||
searchParams?: SearchParams
|
||||
}
|
||||
const Marketplace = async ({
|
||||
locale,
|
||||
showInstallButton = true,
|
||||
shouldExclude,
|
||||
searchParams,
|
||||
}: MarketplaceProps) => {
|
||||
const { marketplaceCollections, marketplaceCollectionPluginsMap } = await getMarketplaceCollectionsAndPlugins()
|
||||
let marketplaceCollections: any = []
|
||||
let marketplaceCollectionPluginsMap = {}
|
||||
if (!shouldExclude) {
|
||||
const marketplaceCollectionsAndPluginsData = await getMarketplaceCollectionsAndPlugins()
|
||||
marketplaceCollections = marketplaceCollectionsAndPluginsData.marketplaceCollections
|
||||
marketplaceCollectionPluginsMap = marketplaceCollectionsAndPluginsData.marketplaceCollectionPluginsMap
|
||||
}
|
||||
|
||||
return (
|
||||
<TanstackQueryIniter>
|
||||
<MarketplaceContextProvider searchParams={searchParams}>
|
||||
<MarketplaceContextProvider searchParams={searchParams} shouldExclude={shouldExclude}>
|
||||
<Description locale={locale} />
|
||||
<IntersectionLine />
|
||||
<SearchBoxWrapper locale={locale} />
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ export type PluginsSearchParams = {
|
|||
sortOrder?: string
|
||||
category?: string
|
||||
tags?: string[]
|
||||
exclude?: string[]
|
||||
}
|
||||
|
||||
export type PluginsSort = {
|
||||
|
|
@ -37,6 +38,7 @@ export type PluginsSort = {
|
|||
export type CollectionsAndPluginsSearchParams = {
|
||||
category?: string
|
||||
condition?: string
|
||||
exclude?: string[]
|
||||
}
|
||||
|
||||
export type SearchParams = {
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ import { PluginType } from '@/app/components/plugins/types'
|
|||
import type {
|
||||
CollectionsAndPluginsSearchParams,
|
||||
MarketplaceCollection,
|
||||
PluginsSearchParams,
|
||||
} from '@/app/components/plugins/marketplace/types'
|
||||
import { MARKETPLACE_API_PREFIX } from '@/config'
|
||||
|
||||
|
|
@ -22,10 +21,18 @@ export const getMarketplaceCollectionsAndPlugins = async (query?: CollectionsAnd
|
|||
const marketplaceCollectionsDataJson = await marketplaceCollectionsData.json()
|
||||
marketplaceCollections = marketplaceCollectionsDataJson.data.collections
|
||||
await Promise.all(marketplaceCollections.map(async (collection: MarketplaceCollection) => {
|
||||
let url = `${MARKETPLACE_API_PREFIX}/collections/${collection.name}/plugins?page=1&page_size=100`
|
||||
if (query?.category)
|
||||
url += `&category=${query.category}`
|
||||
const marketplaceCollectionPluginsData = await globalThis.fetch(url, { cache: 'no-store' })
|
||||
const url = `${MARKETPLACE_API_PREFIX}/collections/${collection.name}/plugins`
|
||||
const marketplaceCollectionPluginsData = await globalThis.fetch(
|
||||
url,
|
||||
{
|
||||
cache: 'no-store',
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
category: query?.category,
|
||||
exclude: query?.exclude,
|
||||
}),
|
||||
},
|
||||
)
|
||||
const marketplaceCollectionPluginsDataJson = await marketplaceCollectionPluginsData.json()
|
||||
const plugins = marketplaceCollectionPluginsDataJson.data.plugins.map((plugin: Plugin) => {
|
||||
return {
|
||||
|
|
@ -49,45 +56,6 @@ export const getMarketplaceCollectionsAndPlugins = async (query?: CollectionsAnd
|
|||
}
|
||||
}
|
||||
|
||||
export const getMarketplacePlugins = async (query: PluginsSearchParams) => {
|
||||
let marketplacePlugins = [] as Plugin[]
|
||||
try {
|
||||
const marketplacePluginsData = await globalThis.fetch(
|
||||
`${MARKETPLACE_API_PREFIX}/plugins/search/basic`,
|
||||
{
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
page: 1,
|
||||
page_size: 10,
|
||||
query: query.query,
|
||||
sort_by: query.sortBy,
|
||||
sort_order: query.sortOrder,
|
||||
category: query.category,
|
||||
tags: query.tags,
|
||||
}),
|
||||
},
|
||||
)
|
||||
const marketplacePluginsDataJson = await marketplacePluginsData.json()
|
||||
marketplacePlugins = marketplacePluginsDataJson.data.plugins.map((plugin: Plugin) => {
|
||||
return {
|
||||
...plugin,
|
||||
icon: getPluginIconInMarketplace(plugin),
|
||||
}
|
||||
})
|
||||
}
|
||||
// eslint-disable-next-line unused-imports/no-unused-vars
|
||||
catch (e) {
|
||||
marketplacePlugins = []
|
||||
}
|
||||
|
||||
return {
|
||||
marketplacePlugins,
|
||||
}
|
||||
}
|
||||
|
||||
export const getMarketplaceListCondition = (pluginType: string) => {
|
||||
if (pluginType === PluginType.tool)
|
||||
return 'category=tool'
|
||||
|
|
|
|||
|
|
@ -201,7 +201,15 @@ const DetailHeader = ({
|
|||
}
|
||||
/>
|
||||
{(hasNewVersion || isFromGitHub) && (
|
||||
<Button variant='secondary-accent' size='small' className='!h-5' onClick={handleUpdate}>{t('plugin.detailPanel.operation.update')}</Button>
|
||||
<Button variant='secondary-accent' size='small' className='!h-5' onClick={() => {
|
||||
if (isFromMarketplace) {
|
||||
setTargetVersion({
|
||||
version: latest_version,
|
||||
unique_identifier: latest_unique_identifier,
|
||||
})
|
||||
}
|
||||
handleUpdate()
|
||||
}}>{t('plugin.detailPanel.operation.update')}</Button>
|
||||
)}
|
||||
</div>
|
||||
<div className='mb-1 flex justify-between items-center h-4'>
|
||||
|
|
|
|||
|
|
@ -28,13 +28,15 @@ import {
|
|||
useRouter,
|
||||
useSearchParams,
|
||||
} from 'next/navigation'
|
||||
import type { Dependency } from '../types'
|
||||
import type { PluginDeclaration, PluginManifestInMarket } from '../types'
|
||||
import { sleep } from '@/utils'
|
||||
import { fetchManifestFromMarketPlace } from '@/service/plugins'
|
||||
import { fetchBundleInfoFromMarketPlace, fetchManifestFromMarketPlace } from '@/service/plugins'
|
||||
import { marketplaceApiPrefix } from '@/config'
|
||||
import { SUPPORT_INSTALL_LOCAL_FILE_EXTENSIONS } from '@/config'
|
||||
|
||||
const PACKAGE_IDS_KEY = 'package-ids'
|
||||
const BUNDLE_INFO_KEY = 'bundle-info'
|
||||
|
||||
export type PluginPageProps = {
|
||||
plugins: React.ReactNode
|
||||
|
|
@ -58,6 +60,18 @@ const PluginPage = ({
|
|||
return ''
|
||||
}
|
||||
}, [searchParams])
|
||||
|
||||
const [dependencies, setDependencies] = useState<Dependency[]>([])
|
||||
const bundleInfo = useMemo(() => {
|
||||
const info = searchParams.get(BUNDLE_INFO_KEY)
|
||||
try {
|
||||
return info ? JSON.parse(info) : undefined
|
||||
}
|
||||
catch (e) {
|
||||
return undefined
|
||||
}
|
||||
}, [searchParams])
|
||||
|
||||
const [isShowInstallFromMarketplace, {
|
||||
setTrue: showInstallFromMarketplace,
|
||||
setFalse: doHideInstallFromMarketplace,
|
||||
|
|
@ -67,6 +81,7 @@ const PluginPage = ({
|
|||
doHideInstallFromMarketplace()
|
||||
const url = new URL(window.location.href)
|
||||
url.searchParams.delete(PACKAGE_IDS_KEY)
|
||||
url.searchParams.delete(BUNDLE_INFO_KEY)
|
||||
replace(url.toString())
|
||||
}
|
||||
const [manifest, setManifest] = useState<PluginDeclaration | PluginManifestInMarket | null>(null)
|
||||
|
|
@ -76,16 +91,23 @@ const PluginPage = ({
|
|||
await sleep(100)
|
||||
if (packageId) {
|
||||
const { data } = await fetchManifestFromMarketPlace(encodeURIComponent(packageId))
|
||||
const { plugin } = data
|
||||
const { plugin, version } = data
|
||||
setManifest({
|
||||
...plugin,
|
||||
version: version.version,
|
||||
icon: `${marketplaceApiPrefix}/plugins/${plugin.org}/${plugin.name}/icon`,
|
||||
})
|
||||
showInstallFromMarketplace()
|
||||
return
|
||||
}
|
||||
if (bundleInfo) {
|
||||
const { data } = await fetchBundleInfoFromMarketPlace(bundleInfo)
|
||||
setDependencies(data.version.dependencies)
|
||||
showInstallFromMarketplace()
|
||||
}
|
||||
})()
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [packageId])
|
||||
}, [packageId, bundleInfo])
|
||||
|
||||
const {
|
||||
canManagement,
|
||||
|
|
@ -210,6 +232,8 @@ const PluginPage = ({
|
|||
<InstallFromMarketplace
|
||||
manifest={manifest! as PluginManifestInMarket}
|
||||
uniqueIdentifier={packageId}
|
||||
isBundle={!!bundleInfo}
|
||||
dependencies={dependencies}
|
||||
onClose={hideInstallFromMarketplace}
|
||||
onSuccess={hideInstallFromMarketplace}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@ export type PluginManifestInMarket = {
|
|||
icon: string
|
||||
label: Record<Locale, string>
|
||||
category: PluginType
|
||||
version: string // TODO: wait api return current plugin version
|
||||
version: string // conbine the other place to it
|
||||
latest_version: string
|
||||
brief: Record<Locale, string>
|
||||
introduction: string
|
||||
|
|
|
|||
|
|
@ -89,6 +89,7 @@ const UpdatePluginModal: FC<Props> = ({
|
|||
})
|
||||
onSave()
|
||||
}
|
||||
// eslint-disable-next-line unused-imports/no-unused-vars
|
||||
catch (e) {
|
||||
setUploadStep(UploadStep.notStarted)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import {
|
||||
useEffect,
|
||||
useMemo,
|
||||
} from 'react'
|
||||
import {
|
||||
useMarketplaceCollectionsAndPlugins,
|
||||
|
|
@ -7,8 +8,14 @@ import {
|
|||
} from '@/app/components/plugins/marketplace/hooks'
|
||||
import { PluginType } from '@/app/components/plugins/types'
|
||||
import { getMarketplaceListCondition } from '@/app/components/plugins/marketplace/utils'
|
||||
import { useAllToolProviders } from '@/service/use-tools'
|
||||
|
||||
export const useMarketplace = (searchPluginText: string, filterPluginTags: string[]) => {
|
||||
const { data: toolProvidersData, isSuccess } = useAllToolProviders()
|
||||
const exclude = useMemo(() => {
|
||||
if (isSuccess)
|
||||
return toolProvidersData?.filter(toolProvider => !!toolProvider.plugin_id).map(toolProvider => toolProvider.plugin_id!)
|
||||
}, [isSuccess, toolProvidersData])
|
||||
const {
|
||||
isLoading,
|
||||
marketplaceCollections,
|
||||
|
|
@ -24,12 +31,13 @@ export const useMarketplace = (searchPluginText: string, filterPluginTags: strin
|
|||
} = useMarketplacePlugins()
|
||||
|
||||
useEffect(() => {
|
||||
if (searchPluginText || filterPluginTags.length) {
|
||||
if ((searchPluginText || filterPluginTags.length) && isSuccess) {
|
||||
if (searchPluginText) {
|
||||
queryPluginsWithDebounced({
|
||||
category: PluginType.tool,
|
||||
query: searchPluginText,
|
||||
tags: filterPluginTags,
|
||||
exclude,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
|
@ -37,16 +45,20 @@ export const useMarketplace = (searchPluginText: string, filterPluginTags: strin
|
|||
category: PluginType.tool,
|
||||
query: searchPluginText,
|
||||
tags: filterPluginTags,
|
||||
exclude,
|
||||
})
|
||||
}
|
||||
else {
|
||||
queryMarketplaceCollectionsAndPlugins({
|
||||
category: PluginType.tool,
|
||||
condition: getMarketplaceListCondition(PluginType.tool),
|
||||
})
|
||||
resetPlugins()
|
||||
if (isSuccess) {
|
||||
queryMarketplaceCollectionsAndPlugins({
|
||||
category: PluginType.tool,
|
||||
condition: getMarketplaceListCondition(PluginType.tool),
|
||||
exclude,
|
||||
})
|
||||
resetPlugins()
|
||||
}
|
||||
}
|
||||
}, [searchPluginText, filterPluginTags, queryPlugins, queryMarketplaceCollectionsAndPlugins, queryPluginsWithDebounced, resetPlugins])
|
||||
}, [searchPluginText, filterPluginTags, queryPlugins, queryMarketplaceCollectionsAndPlugins, queryPluginsWithDebounced, resetPlugins, exclude, isSuccess])
|
||||
|
||||
return {
|
||||
isLoading: isLoading || isPluginsLoading,
|
||||
|
|
|
|||
|
|
@ -72,7 +72,6 @@ import SyncingDataModal from './syncing-data-modal'
|
|||
import UpdateDSLModal from './update-dsl-modal'
|
||||
import DSLExportConfirmModal from './dsl-export-confirm-modal'
|
||||
import LimitTips from './limit-tips'
|
||||
import PluginDependency from './plugin-dependency'
|
||||
import {
|
||||
useStore,
|
||||
useWorkflowStore,
|
||||
|
|
@ -327,7 +326,6 @@ const Workflow: FC<WorkflowProps> = memo(({
|
|||
/>
|
||||
)
|
||||
}
|
||||
<PluginDependency />
|
||||
<LimitTips />
|
||||
<ReactFlow
|
||||
nodeTypes={nodeTypes}
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ type BeforeRunFormProps = {
|
|||
|
||||
function formatValue(value: string | any, type: InputVarType) {
|
||||
if (type === InputVarType.number)
|
||||
return parseFloat(value)
|
||||
return Number.parseFloat(value)
|
||||
if (type === InputVarType.json)
|
||||
return JSON.parse(value)
|
||||
if (type === InputVarType.contexts) {
|
||||
|
|
|
|||
|
|
@ -88,7 +88,7 @@ const CodeEditor: FC<Props> = ({
|
|||
|
||||
const index = (() => {
|
||||
if (match)
|
||||
return parseInt(match[1]!) + 1
|
||||
return Number.parseInt(match[1]!) + 1
|
||||
|
||||
return 1
|
||||
})()
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ import Field from '@/app/components/workflow/nodes/_base/components/field'
|
|||
import Split from '@/app/components/workflow/nodes/_base/components/split'
|
||||
import CodeEditor from '@/app/components/workflow/nodes/_base/components/editor/code-editor'
|
||||
import TypeSelector from '@/app/components/workflow/nodes/_base/components/selector'
|
||||
import { type NodePanelProps } from '@/app/components/workflow/types'
|
||||
import type { NodePanelProps } from '@/app/components/workflow/types'
|
||||
import BeforeRunForm from '@/app/components/workflow/nodes/_base/components/before-run-form'
|
||||
import ResultPanel from '@/app/components/workflow/run/result-panel'
|
||||
const i18nPrefix = 'workflow.nodes.code'
|
||||
|
|
|
|||
|
|
@ -1,23 +1,43 @@
|
|||
import { useCallback } from 'react'
|
||||
import {
|
||||
useCallback,
|
||||
useState,
|
||||
} from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useStore } from './store'
|
||||
import InstallBundle from '@/app/components/plugins/install-plugin/install-bundle'
|
||||
import ReadyToInstall from '@/app/components/plugins/install-plugin/install-bundle/ready-to-install'
|
||||
import { InstallStep } from '@/app/components/plugins/types'
|
||||
|
||||
const i18nPrefix = 'plugin.installModal'
|
||||
const PluginDependency = () => {
|
||||
const dependencies = useStore(s => s.dependencies)
|
||||
|
||||
const handleCancelInstallBundle = useCallback(() => {
|
||||
const { setDependencies } = useStore.getState()
|
||||
setDependencies([])
|
||||
}, [])
|
||||
const [step, setStep] = useState<InstallStep>(InstallStep.readyToInstall)
|
||||
|
||||
const { t } = useTranslation()
|
||||
const getTitle = useCallback(() => {
|
||||
if (step === InstallStep.uploadFailed)
|
||||
return t(`${i18nPrefix}.uploadFailed`)
|
||||
if (step === InstallStep.installed)
|
||||
return t(`${i18nPrefix}.installComplete`)
|
||||
|
||||
return t(`${i18nPrefix}.installPlugin`)
|
||||
}, [step, t])
|
||||
|
||||
if (!dependencies.length)
|
||||
return null
|
||||
|
||||
return (
|
||||
<div>
|
||||
<InstallBundle
|
||||
fromDSLPayload={dependencies}
|
||||
onClose={handleCancelInstallBundle}
|
||||
<div className='flex pt-6 pl-6 pb-3 pr-14 items-start gap-2 self-stretch'>
|
||||
<div className='self-stretch text-text-primary title-2xl-semi-bold'>
|
||||
{getTitle()}
|
||||
</div>
|
||||
</div>
|
||||
<ReadyToInstall
|
||||
step={step}
|
||||
onStepChange={setStep}
|
||||
allPlugins={dependencies}
|
||||
onClose={() => {}}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
|
|
|
|||
|
|
@ -38,7 +38,8 @@ import { ToastContext } from '@/app/components/base/toast'
|
|||
import { useEventEmitterContextContext } from '@/context/event-emitter'
|
||||
import { useStore as useAppStore } from '@/app/components/app/store'
|
||||
import { FILE_EXTS } from '@/app/components/base/prompt-editor/constants'
|
||||
import { useMutationCheckDependenciesBeforeImportDSL } from '@/service/use-plugins'
|
||||
import { useStore as usePluginDependencyStore } from '@/app/components/workflow/plugin-dependency/store'
|
||||
import PluginDependency from '@/app/components/workflow/plugin-dependency'
|
||||
|
||||
type UpdateDSLModalProps = {
|
||||
onCancel: () => void
|
||||
|
|
@ -58,7 +59,6 @@ const UpdateDSLModal = ({
|
|||
const [fileContent, setFileContent] = useState<string>()
|
||||
const [loading, setLoading] = useState(false)
|
||||
const { eventEmitter } = useEventEmitterContextContext()
|
||||
const { mutateAsync, mutate } = useMutationCheckDependenciesBeforeImportDSL()
|
||||
const [show, setShow] = useState(true)
|
||||
const [showErrorModal, setShowErrorModal] = useState(false)
|
||||
const [versions, setVersions] = useState<{ importedVersion: string; systemVersion: string }>()
|
||||
|
|
@ -81,7 +81,7 @@ const UpdateDSLModal = ({
|
|||
setFileContent('')
|
||||
}
|
||||
|
||||
const handleWorkflowUpdate = async (app_id: string) => {
|
||||
const handleWorkflowUpdate = useCallback(async (app_id: string) => {
|
||||
const {
|
||||
graph,
|
||||
features,
|
||||
|
|
@ -124,7 +124,7 @@ const UpdateDSLModal = ({
|
|||
hash,
|
||||
},
|
||||
} as any)
|
||||
}
|
||||
}, [eventEmitter])
|
||||
|
||||
const isCreatingRef = useRef(false)
|
||||
const handleImport: MouseEventHandler = useCallback(async () => {
|
||||
|
|
@ -136,36 +136,42 @@ const UpdateDSLModal = ({
|
|||
try {
|
||||
if (appDetail && fileContent) {
|
||||
setLoading(true)
|
||||
const {
|
||||
graph,
|
||||
features,
|
||||
hash,
|
||||
} = await updateWorkflowDraftFromDSL(appDetail.id, fileContent)
|
||||
await mutateAsync({ dslString: fileContent })
|
||||
const { nodes, edges, viewport } = graph
|
||||
const newFeatures = {
|
||||
file: {
|
||||
image: {
|
||||
enabled: !!features.file_upload?.image?.enabled,
|
||||
number_limits: features.file_upload?.image?.number_limits || 3,
|
||||
transfer_methods: features.file_upload?.image?.transfer_methods || ['local_file', 'remote_url'],
|
||||
},
|
||||
enabled: !!(features.file_upload?.enabled || features.file_upload?.image?.enabled),
|
||||
allowed_file_types: features.file_upload?.allowed_file_types || [SupportUploadFileTypes.image],
|
||||
allowed_file_extensions: features.file_upload?.allowed_file_extensions || FILE_EXTS[SupportUploadFileTypes.image].map(ext => `.${ext}`),
|
||||
allowed_file_upload_methods: features.file_upload?.allowed_file_upload_methods || features.file_upload?.image?.transfer_methods || ['local_file', 'remote_url'],
|
||||
number_limits: features.file_upload?.number_limits || features.file_upload?.image?.number_limits || 3,
|
||||
},
|
||||
opening: {
|
||||
enabled: !!features.opening_statement,
|
||||
opening_statement: features.opening_statement,
|
||||
suggested_questions: features.suggested_questions,
|
||||
},
|
||||
suggested: features.suggested_questions_after_answer || { enabled: false },
|
||||
speech2text: features.speech_to_text || { enabled: false },
|
||||
text2speech: features.text_to_speech || { enabled: false },
|
||||
citation: features.retriever_resource || { enabled: false },
|
||||
moderation: features.sensitive_word_avoidance || { enabled: false },
|
||||
const response = await importDSL({ mode: DSLImportMode.YAML_CONTENT, yaml_content: fileContent, app_id: appDetail.id })
|
||||
const { id, status, app_id, imported_dsl_version, current_dsl_version, leaked_dependencies } = response
|
||||
if (leaked_dependencies?.length) {
|
||||
const { setDependencies } = usePluginDependencyStore.getState()
|
||||
setDependencies(leaked_dependencies)
|
||||
}
|
||||
if (status === DSLImportStatus.COMPLETED || status === DSLImportStatus.COMPLETED_WITH_WARNINGS) {
|
||||
if (!app_id) {
|
||||
notify({ type: 'error', message: t('workflow.common.importFailure') })
|
||||
return
|
||||
}
|
||||
handleWorkflowUpdate(app_id)
|
||||
if (onImport)
|
||||
onImport()
|
||||
notify({
|
||||
type: status === DSLImportStatus.COMPLETED ? 'success' : 'warning',
|
||||
message: t(status === DSLImportStatus.COMPLETED ? 'workflow.common.importSuccess' : 'workflow.common.importWarning'),
|
||||
children: status === DSLImportStatus.COMPLETED_WITH_WARNINGS && t('workflow.common.importWarningDetails'),
|
||||
})
|
||||
setLoading(false)
|
||||
onCancel()
|
||||
}
|
||||
else if (status === DSLImportStatus.PENDING) {
|
||||
setShow(false)
|
||||
setTimeout(() => {
|
||||
setShowErrorModal(true)
|
||||
}, 300)
|
||||
setVersions({
|
||||
importedVersion: imported_dsl_version ?? '',
|
||||
systemVersion: current_dsl_version ?? '',
|
||||
})
|
||||
setImportId(id)
|
||||
}
|
||||
else {
|
||||
setLoading(false)
|
||||
notify({ type: 'error', message: t('workflow.common.importFailure') })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -174,7 +180,7 @@ const UpdateDSLModal = ({
|
|||
notify({ type: 'error', message: t('workflow.common.importFailure') })
|
||||
}
|
||||
isCreatingRef.current = false
|
||||
}, [currentFile, fileContent, onCancel, notify, t, eventEmitter, appDetail, onImport, mutateAsync])
|
||||
}, [currentFile, fileContent, onCancel, notify, t, appDetail, onImport, handleWorkflowUpdate])
|
||||
|
||||
const onUpdateDSLConfirm: MouseEventHandler = async () => {
|
||||
try {
|
||||
|
|
@ -222,12 +228,12 @@ const UpdateDSLModal = ({
|
|||
<RiCloseLine className='w-[18px] h-[18px] text-text-tertiary' />
|
||||
</div>
|
||||
</div>
|
||||
<div className='flex relative p-2 mb-2 gap-0.5 flex-grow rounded-xl border-[0.5px] border-components-panel-border bg-components-panel-bg-blur shadow-xs overflow-hidden'>
|
||||
<div className='flex relative p-2 mb-2 gap-0.5 grow rounded-xl border-[0.5px] border-components-panel-border bg-components-panel-bg-blur shadow-xs overflow-hidden'>
|
||||
<div className='absolute top-0 left-0 w-full h-full opacity-40 bg-[linear-gradient(92deg,rgba(247,144,9,0.25)_0%,rgba(255,255,255,0.00)_100%)]' />
|
||||
<div className='flex p-1 justify-center items-start'>
|
||||
<RiAlertFill className='w-4 h-4 flex-shrink-0 text-text-warning-secondary' />
|
||||
<RiAlertFill className='w-4 h-4 shrink-0 text-text-warning-secondary' />
|
||||
</div>
|
||||
<div className='flex py-1 flex-col items-start gap-0.5 flex-grow'>
|
||||
<div className='flex py-1 flex-col items-start gap-0.5 grow'>
|
||||
<div className='text-text-primary system-xs-medium whitespace-pre-line'>{t('workflow.common.importDSLTip')}</div>
|
||||
<div className='flex pt-1 pb-0.5 items-start gap-1 self-stretch'>
|
||||
<Button
|
||||
|
|
@ -275,7 +281,7 @@ const UpdateDSLModal = ({
|
|||
>
|
||||
<div className='flex pb-4 flex-col items-start gap-2 self-stretch'>
|
||||
<div className='text-text-primary title-2xl-semi-bold'>{t('app.newApp.appCreateDSLErrorTitle')}</div>
|
||||
<div className='flex flex-grow flex-col text-text-secondary system-md-regular'>
|
||||
<div className='flex grow flex-col text-text-secondary system-md-regular'>
|
||||
<div>{t('app.newApp.appCreateDSLErrorPart1')}</div>
|
||||
<div>{t('app.newApp.appCreateDSLErrorPart2')}</div>
|
||||
<br />
|
||||
|
|
@ -283,6 +289,7 @@ const UpdateDSLModal = ({
|
|||
<div>{t('app.newApp.appCreateDSLErrorPart4')}<span className='system-md-medium'>{versions?.systemVersion}</span></div>
|
||||
</div>
|
||||
</div>
|
||||
<PluginDependency />
|
||||
<div className='flex pt-6 justify-end items-start gap-2 self-stretch'>
|
||||
<Button variant='secondary' onClick={() => setShowErrorModal(false)}>{t('app.newApp.Cancel')}</Button>
|
||||
<Button variant='primary' destructive onClick={onUpdateDSLConfirm}>{t('app.newApp.Confirm')}</Button>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import type { LangFuseConfig, LangSmithConfig, TracingProvider } from '@/app/(commonLayout)/app/(appDetailLayout)/[appId]/overview/tracing/type'
|
||||
import type { App, AppSSO, AppTemplate, SiteConfig } from '@/types/app'
|
||||
import type { Dependency } from '@/app/components/plugins/types'
|
||||
|
||||
/* export type App = {
|
||||
id: string
|
||||
|
|
@ -87,6 +88,7 @@ export type DSLImportResponse = {
|
|||
current_dsl_version?: string
|
||||
imported_dsl_version?: string
|
||||
error: string
|
||||
leaked_dependencies: Dependency[]
|
||||
}
|
||||
|
||||
export type AppSSOResponse = { enabled: AppSSO['enable_sso'] }
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import type { Fetcher } from 'swr'
|
||||
import { get, getMarketplace, post, upload } from './base'
|
||||
import type {
|
||||
Dependency,
|
||||
InstallPackageResponse,
|
||||
Permissions,
|
||||
PluginDeclaration,
|
||||
|
|
@ -63,7 +64,15 @@ export const fetchManifest = async (uniqueIdentifier: string) => {
|
|||
}
|
||||
|
||||
export const fetchManifestFromMarketPlace = async (uniqueIdentifier: string) => {
|
||||
return getMarketplace<{ data: { plugin: PluginManifestInMarket } }>(`/plugins/identifier?unique_identifier=${uniqueIdentifier}`)
|
||||
return getMarketplace<{ data: { plugin: PluginManifestInMarket, version: { version: string } } }>(`/plugins/identifier?unique_identifier=${uniqueIdentifier}`)
|
||||
}
|
||||
|
||||
export const fetchBundleInfoFromMarketPlace = async ({
|
||||
org,
|
||||
name,
|
||||
version,
|
||||
}: Record<string, string>) => {
|
||||
return getMarketplace<{ data: { version: { dependencies: Dependency[] } } }>(`/bundles/${org}/${name}/${version}`)
|
||||
}
|
||||
|
||||
export const fetchMarketplaceCollections: Fetcher<MarketplaceCollectionsResponse, { url: string; }> = ({ url }) => {
|
||||
|
|
|
|||
|
|
@ -24,16 +24,17 @@ import {
|
|||
useQuery,
|
||||
useQueryClient,
|
||||
} from '@tanstack/react-query'
|
||||
import { useStore as usePluginDependencyStore } from '@/app/components/workflow/plugin-dependency/store'
|
||||
import { useInvalidateAllBuiltInTools } from './use-tools'
|
||||
|
||||
const NAME_SPACE = 'plugins'
|
||||
|
||||
const useInstalledPluginListKey = [NAME_SPACE, 'installedPluginList']
|
||||
export const useInstalledPluginList = () => {
|
||||
export const useInstalledPluginList = (disable?: boolean) => {
|
||||
return useQuery<InstalledPluginListResponse>({
|
||||
queryKey: useInstalledPluginListKey,
|
||||
queryFn: () => get<InstalledPluginListResponse>('/workspaces/current/plugin/list'),
|
||||
enabled: !disable,
|
||||
initialData: !disable ? undefined : { plugins: [] },
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -110,6 +111,7 @@ export const useUploadGitHub = (payload: {
|
|||
queryFn: () => post<uploadGitHubResponse>('/workspaces/current/plugin/upload/github', {
|
||||
body: payload,
|
||||
}),
|
||||
retry: 0,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -225,6 +227,7 @@ export const useMutationPluginsFromMarketplace = () => {
|
|||
sortOrder,
|
||||
category,
|
||||
tags,
|
||||
exclude,
|
||||
} = pluginsSearchParams
|
||||
return postMarketplace<{ data: PluginsFromMarketplaceResponse }>('/plugins/search/basic', {
|
||||
body: {
|
||||
|
|
@ -235,6 +238,7 @@ export const useMutationPluginsFromMarketplace = () => {
|
|||
sort_order: sortOrder,
|
||||
category: category !== 'all' ? category : '',
|
||||
tags,
|
||||
exclude,
|
||||
},
|
||||
})
|
||||
},
|
||||
|
|
@ -323,36 +327,6 @@ export const useMutationClearAllTaskPlugin = () => {
|
|||
})
|
||||
}
|
||||
|
||||
export const useMutationCheckDependenciesBeforeImportDSL = () => {
|
||||
const mutation = useMutation({
|
||||
mutationFn: ({ dslString, url }: { dslString?: string, url?: string }) => {
|
||||
if (url) {
|
||||
return post<{ leaked: Dependency[] }>(
|
||||
'/apps/import/url/dependencies/check',
|
||||
{
|
||||
body: {
|
||||
url,
|
||||
},
|
||||
},
|
||||
)
|
||||
}
|
||||
return post<{ leaked: Dependency[] }>(
|
||||
'/apps/import/dependencies/check',
|
||||
{
|
||||
body: {
|
||||
data: dslString,
|
||||
},
|
||||
})
|
||||
},
|
||||
onSuccess: (data) => {
|
||||
const { setDependencies } = usePluginDependencyStore.getState()
|
||||
setDependencies(data.leaked || [])
|
||||
},
|
||||
})
|
||||
|
||||
return mutation
|
||||
}
|
||||
|
||||
export const useDownloadPlugin = (info: { organization: string; pluginName: string; version: string }, needDownload: boolean) => {
|
||||
return useQuery({
|
||||
queryKey: [NAME_SPACE, 'downloadPlugin', info],
|
||||
|
|
|
|||
Loading…
Reference in New Issue