mirror of
https://github.com/langgenius/dify.git
synced 2026-03-26 16:50:14 +08:00
Made-with: Cursor # Conflicts: # api/core/agent/cot_chat_agent_runner.py # api/core/agent/fc_agent_runner.py # api/core/memory/token_buffer_memory.py # api/core/variables/segments.py # api/core/workflow/file/file_manager.py # api/core/workflow/nodes/agent/agent_node.py # api/core/workflow/nodes/llm/llm_utils.py # api/core/workflow/nodes/parameter_extractor/parameter_extractor_node.py # api/core/workflow/workflow_entry.py # api/factories/variable_factory.py # api/pyproject.toml # api/services/variable_truncator.py # api/uv.lock # web/app/components/app/app-publisher/index.tsx # web/app/components/app/overview/settings/index.tsx # web/app/components/apps/app-card.tsx # web/app/components/apps/index.tsx # web/app/components/apps/list.tsx # web/app/components/base/chat/chat-with-history/header-in-mobile.tsx # web/app/components/base/features/new-feature-panel/conversation-opener/modal.tsx # web/app/components/base/features/new-feature-panel/file-upload/setting-content.tsx # web/app/components/base/features/new-feature-panel/moderation/moderation-setting-modal.tsx # web/app/components/base/features/new-feature-panel/text-to-speech/param-config-content.tsx # web/app/components/base/message-log-modal/index.tsx # web/app/components/base/switch/index.tsx # web/app/components/base/tab-slider-plain/index.tsx # web/app/components/explore/try-app/app-info/index.tsx # web/app/components/plugins/plugin-detail-panel/tool-selector/components/reasoning-config-form.tsx # web/app/components/workflow/nodes/llm/components/json-schema-config-modal/visual-editor/edit-card/required-switch.tsx # web/app/components/workflow/nodes/llm/panel.tsx # web/contract/router.ts # web/eslint-suppressions.json # web/i18n/fa-IR/workflow.json
201 lines
6.4 KiB
TypeScript
201 lines
6.4 KiB
TypeScript
'use client'
|
|
import type { CreateAppModalProps } from '../explore/create-app-modal'
|
|
import type { MarketplaceTemplate } from '@/service/marketplace-templates'
|
|
import type { TryAppSelection } from '@/types/try-app'
|
|
import dynamic from 'next/dynamic'
|
|
import { useRouter, useSearchParams } from 'next/navigation'
|
|
import { useCallback, useRef, useState } from 'react'
|
|
import { useTranslation } from 'react-i18next'
|
|
import { useEducationInit } from '@/app/education-apply/hooks'
|
|
import AppListContext from '@/context/app-list-context'
|
|
import useDocumentTitle from '@/hooks/use-document-title'
|
|
import { useImportDSL } from '@/hooks/use-import-dsl'
|
|
import { DSLImportMode } from '@/models/app'
|
|
import { fetchAppDetail } from '@/service/explore'
|
|
import DSLConfirmModal from '../app/create-from-dsl-modal/dsl-confirm-modal'
|
|
import CreateAppModal from '../explore/create-app-modal'
|
|
import TryApp from '../explore/try-app'
|
|
import List from './list'
|
|
|
|
const ImportFromMarketplaceTemplateModal = dynamic(
|
|
() => import('./import-from-marketplace-template-modal'),
|
|
{ ssr: false },
|
|
)
|
|
|
|
const Apps = () => {
|
|
const { t } = useTranslation()
|
|
const searchParams = useSearchParams()
|
|
const { replace } = useRouter()
|
|
|
|
useDocumentTitle(t('menus.apps', { ns: 'common' }))
|
|
useEducationInit()
|
|
|
|
const [currentTryAppParams, setCurrentTryAppParams] = useState<TryAppSelection | undefined>(undefined)
|
|
const currApp = currentTryAppParams?.app
|
|
const [isShowTryAppPanel, setIsShowTryAppPanel] = useState(false)
|
|
const hideTryAppPanel = useCallback(() => {
|
|
setIsShowTryAppPanel(false)
|
|
}, [])
|
|
const setShowTryAppPanel = (showTryAppPanel: boolean, params?: TryAppSelection) => {
|
|
if (showTryAppPanel)
|
|
setCurrentTryAppParams(params)
|
|
else
|
|
setCurrentTryAppParams(undefined)
|
|
setIsShowTryAppPanel(showTryAppPanel)
|
|
}
|
|
const [isShowCreateModal, setIsShowCreateModal] = useState(false)
|
|
|
|
const handleShowFromTryApp = useCallback(() => {
|
|
setIsShowCreateModal(true)
|
|
}, [])
|
|
|
|
const [controlRefreshList, setControlRefreshList] = useState(0)
|
|
const [controlHideCreateFromTemplatePanel, setControlHideCreateFromTemplatePanel] = useState(0)
|
|
const onSuccess = useCallback(() => {
|
|
setControlRefreshList(prev => prev + 1)
|
|
setControlHideCreateFromTemplatePanel(prev => prev + 1)
|
|
}, [])
|
|
|
|
const [showDSLConfirmModal, setShowDSLConfirmModal] = useState(false)
|
|
|
|
const {
|
|
handleImportDSL,
|
|
handleImportDSLConfirm,
|
|
versions,
|
|
isFetching,
|
|
} = useImportDSL()
|
|
|
|
const onConfirmDSL = useCallback(async () => {
|
|
await handleImportDSLConfirm({
|
|
onSuccess,
|
|
})
|
|
}, [handleImportDSLConfirm, onSuccess])
|
|
|
|
const onCreate: CreateAppModalProps['onConfirm'] = async ({
|
|
name,
|
|
icon_type,
|
|
icon,
|
|
icon_background,
|
|
description,
|
|
}) => {
|
|
hideTryAppPanel()
|
|
|
|
const { export_data } = await fetchAppDetail(
|
|
currApp?.app.id as string,
|
|
)
|
|
const payload = {
|
|
mode: DSLImportMode.YAML_CONTENT,
|
|
yaml_content: export_data,
|
|
name,
|
|
icon_type,
|
|
icon,
|
|
icon_background,
|
|
description,
|
|
}
|
|
await handleImportDSL(payload, {
|
|
onSuccess: () => {
|
|
setIsShowCreateModal(false)
|
|
},
|
|
onPending: () => {
|
|
setShowDSLConfirmModal(true)
|
|
},
|
|
})
|
|
}
|
|
|
|
// Marketplace template import via URL param
|
|
const marketplaceTemplateId = searchParams.get('template-id') || undefined
|
|
const dismissedTemplateIdRef = useRef<string | undefined>(undefined)
|
|
const showMarketplaceModal = !!marketplaceTemplateId && dismissedTemplateIdRef.current !== marketplaceTemplateId
|
|
|
|
const handleCloseMarketplaceModal = useCallback(() => {
|
|
dismissedTemplateIdRef.current = marketplaceTemplateId
|
|
// Remove template-id from URL without full navigation
|
|
const params = new URLSearchParams(searchParams.toString())
|
|
params.delete('template-id')
|
|
const newQuery = params.toString()
|
|
replace(newQuery ? `/apps?${newQuery}` : '/apps')
|
|
}, [searchParams, replace, marketplaceTemplateId])
|
|
|
|
const handleMarketplaceTemplateConfirm = useCallback(async (
|
|
yamlContent: string,
|
|
template: MarketplaceTemplate,
|
|
) => {
|
|
const payload = {
|
|
mode: DSLImportMode.YAML_CONTENT,
|
|
yaml_content: yamlContent,
|
|
name: template.template_name,
|
|
icon: template.icon || undefined,
|
|
icon_background: template.icon_background || undefined,
|
|
}
|
|
await handleImportDSL(payload, {
|
|
onSuccess: () => {
|
|
handleCloseMarketplaceModal()
|
|
onSuccess()
|
|
},
|
|
onPending: () => {
|
|
handleCloseMarketplaceModal()
|
|
setShowDSLConfirmModal(true)
|
|
},
|
|
})
|
|
}, [handleImportDSL, onSuccess, handleCloseMarketplaceModal])
|
|
|
|
return (
|
|
<AppListContext.Provider value={{
|
|
currentApp: currentTryAppParams,
|
|
isShowTryAppPanel,
|
|
setShowTryAppPanel,
|
|
controlHideCreateFromTemplatePanel,
|
|
}}
|
|
>
|
|
<div className="relative flex h-0 shrink-0 grow flex-col overflow-y-auto bg-background-body">
|
|
<List controlRefreshList={controlRefreshList} />
|
|
{isShowTryAppPanel && (
|
|
<TryApp
|
|
appId={currentTryAppParams?.appId || ''}
|
|
app={currentTryAppParams?.app}
|
|
category={currentTryAppParams?.app?.category}
|
|
onClose={hideTryAppPanel}
|
|
onCreate={handleShowFromTryApp}
|
|
/>
|
|
)}
|
|
|
|
{
|
|
showDSLConfirmModal && (
|
|
<DSLConfirmModal
|
|
versions={versions}
|
|
onCancel={() => setShowDSLConfirmModal(false)}
|
|
onConfirm={onConfirmDSL}
|
|
confirmDisabled={isFetching}
|
|
/>
|
|
)
|
|
}
|
|
|
|
{isShowCreateModal && (
|
|
<CreateAppModal
|
|
appIconType={currApp?.app.icon_type || 'emoji'}
|
|
appIcon={currApp?.app.icon || ''}
|
|
appIconBackground={currApp?.app.icon_background || ''}
|
|
appIconUrl={currApp?.app.icon_url}
|
|
appName={currApp?.app.name || ''}
|
|
appDescription={currApp?.app.description || ''}
|
|
show
|
|
onConfirm={onCreate}
|
|
confirmDisabled={isFetching}
|
|
onHide={() => setIsShowCreateModal(false)}
|
|
/>
|
|
)}
|
|
|
|
{showMarketplaceModal && marketplaceTemplateId && (
|
|
<ImportFromMarketplaceTemplateModal
|
|
templateId={marketplaceTemplateId}
|
|
onConfirm={handleMarketplaceTemplateConfirm}
|
|
onClose={handleCloseMarketplaceModal}
|
|
/>
|
|
)}
|
|
</div>
|
|
</AppListContext.Provider>
|
|
)
|
|
}
|
|
|
|
export default Apps
|