fix: app list not refresh

This commit is contained in:
Joel
2026-05-18 16:01:35 +08:00
committed by Jingyi-Dify
parent 4abe622b2e
commit b70241ad36
7 changed files with 33 additions and 3 deletions

View File

@ -12,6 +12,7 @@ const mockPush = vi.fn()
const mockToastSuccess = vi.fn()
const mockToastError = vi.fn()
const mockTrackCreateApp = vi.fn()
const mockInvalidateAppList = vi.hoisted(() => vi.fn())
let latestDebounceFn = () => {}
vi.mock('ahooks', () => ({
@ -98,6 +99,9 @@ vi.mock('@/utils/create-app-tracking', () => ({
vi.mock('@/service/apps', () => ({
importDSL: (...args: unknown[]) => mockImportDSL(...args),
}))
vi.mock('@/service/use-apps', () => ({
useInvalidateAppList: () => mockInvalidateAppList,
}))
vi.mock('@/service/explore', () => ({
fetchAppDetail: (...args: unknown[]) => mockFetchAppDetail(...args),
}))
@ -253,6 +257,7 @@ describe('Apps', () => {
expect(onSuccess).toHaveBeenCalled()
expect(mockHandleCheckPluginDependencies).toHaveBeenCalledWith('created-app-id')
expect(localStorage.getItem(NEED_REFRESH_APP_LIST_KEY)).toBe('1')
expect(mockInvalidateAppList).toHaveBeenCalledTimes(1)
expect(mockGetRedirection).toHaveBeenCalledWith(true, {
id: 'created-app-id',
mode: AppModeEnum.CHAT,

View File

@ -21,6 +21,7 @@ import { DSLImportMode } from '@/models/app'
import { useRouter } from '@/next/navigation'
import { importDSL } from '@/service/apps'
import { fetchAppDetail } from '@/service/explore'
import { useInvalidateAppList } from '@/service/use-apps'
import { useExploreAppList } from '@/service/use-explore'
import { AppModeEnum } from '@/types/app'
import { getRedirection } from '@/utils/app-redirection'
@ -45,6 +46,7 @@ const Apps = ({
const { t } = useTranslation()
const { isCurrentWorkspaceEditor } = useAppContext()
const { push } = useRouter()
const invalidateAppList = useInvalidateAppList()
const allCategoriesEn = AppCategories.RECOMMENDED
const [keywords, setKeywords] = useState('')
@ -136,6 +138,7 @@ const Apps = ({
if (app.app_id)
await handleCheckPluginDependencies(app.app_id)
localStorage.setItem(NEED_REFRESH_APP_LIST_KEY, '1')
invalidateAppList()
getRedirection(isCurrentWorkspaceEditor, { id: app.app_id!, mode }, push)
}
catch {

View File

@ -15,6 +15,7 @@ import CreateAppModal from '../index'
const ahooksMocks = vi.hoisted(() => ({
keyPressHandlers: [] as Array<() => void>,
}))
const mockInvalidateAppList = vi.hoisted(() => vi.fn())
vi.mock('ahooks', () => ({
useDebounceFn: <T extends (...args: unknown[]) => unknown>(fn: T) => {
@ -37,6 +38,9 @@ vi.mock('@/utils/create-app-tracking', () => ({
vi.mock('@/service/apps', () => ({
createApp: vi.fn(),
}))
vi.mock('@/service/use-apps', () => ({
useInvalidateAppList: () => mockInvalidateAppList,
}))
const toastMocks = vi.hoisted(() => ({
mockToastSuccess: vi.fn(),
mockToastError: vi.fn(),
@ -175,6 +179,7 @@ describe('CreateAppModal', () => {
expect(onSuccess).toHaveBeenCalled()
expect(onClose).toHaveBeenCalled()
await waitFor(() => expect(mockSetItem).toHaveBeenCalledWith(NEED_REFRESH_APP_LIST_KEY, '1'))
expect(mockInvalidateAppList).toHaveBeenCalledTimes(1)
await waitFor(() => expect(mockGetRedirection).toHaveBeenCalledWith(true, mockApp, mockPush))
})

View File

@ -21,6 +21,7 @@ import { useProviderContext } from '@/context/provider-context'
import useTheme from '@/hooks/use-theme'
import { useRouter } from '@/next/navigation'
import { createApp } from '@/service/apps'
import { useInvalidateAppList } from '@/service/use-apps'
import { AppModeEnum } from '@/types/app'
import { getRedirection } from '@/utils/app-redirection'
import { trackCreateApp } from '@/utils/create-app-tracking'
@ -54,6 +55,7 @@ function CreateApp({ onClose, onSuccess, onCreateFromTemplate, defaultAppMode }:
const { plan, enableBilling } = useProviderContext()
const isAppsFull = (enableBilling && plan.usage.buildApps >= plan.total.buildApps)
const { isCurrentWorkspaceEditor } = useAppContext()
const invalidateAppList = useInvalidateAppList()
const isCreatingRef = useRef(false)
@ -85,13 +87,14 @@ function CreateApp({ onClose, onSuccess, onCreateFromTemplate, defaultAppMode }:
onSuccess()
onClose()
localStorage.setItem(NEED_REFRESH_APP_LIST_KEY, '1')
invalidateAppList()
getRedirection(isCurrentWorkspaceEditor, app, push)
}
catch (error) {
toast.error(error instanceof Error ? error.message : t('newApp.appCreateFailed', { ns: 'app' }))
}
isCreatingRef.current = false
}, [name, t, appMode, appIcon, description, onSuccess, onClose, push, isCurrentWorkspaceEditor])
}, [name, t, appMode, appIcon, description, onSuccess, onClose, push, isCurrentWorkspaceEditor, invalidateAppList])
const { run: handleCreateApp } = useDebounceFn(onCreate, { wait: 300 })
useKeyPress(['meta.enter', 'ctrl.enter'], () => {

View File

@ -11,6 +11,7 @@ const mockImportDSLConfirm = vi.fn()
const mockTrackCreateApp = vi.fn()
const mockHandleCheckPluginDependencies = vi.fn()
const mockGetRedirection = vi.fn()
const mockInvalidateAppList = vi.hoisted(() => vi.fn())
const toastMocks = vi.hoisted(() => ({
call: vi.fn(),
success: vi.fn(),
@ -52,6 +53,9 @@ vi.mock('@/service/apps', () => ({
importDSL: (...args: unknown[]) => mockImportDSL(...args),
importDSLConfirm: (...args: unknown[]) => mockImportDSLConfirm(...args),
}))
vi.mock('@/service/use-apps', () => ({
useInvalidateAppList: () => mockInvalidateAppList,
}))
vi.mock('@/app/components/workflow/plugin-dependency/hooks', () => ({
usePluginDependencies: () => ({
@ -201,6 +205,7 @@ describe('CreateFromDSLModal', () => {
expect(handleSuccess).toHaveBeenCalledTimes(1)
expect(handleClose).toHaveBeenCalledTimes(1)
expect(localStorage.getItem(NEED_REFRESH_APP_LIST_KEY)).toBe('1')
expect(mockInvalidateAppList).toHaveBeenCalledTimes(1)
expect(mockHandleCheckPluginDependencies).toHaveBeenCalledWith('app-1')
expect(mockGetRedirection).toHaveBeenCalledWith(true, { id: 'app-1', mode: 'chat' }, mockPush)
})
@ -305,6 +310,7 @@ describe('CreateFromDSLModal', () => {
import_id: 'import-3',
})
expect(mockTrackCreateApp).toHaveBeenCalledWith({ appMode: AppModeEnum.WORKFLOW })
expect(mockInvalidateAppList).toHaveBeenCalledTimes(1)
})
it('should close the DSL mismatch modal when dialog requests close', async () => {

View File

@ -23,6 +23,7 @@ import {
importDSL,
importDSLConfirm,
} from '@/service/apps'
import { useInvalidateAppList } from '@/service/use-apps'
import { getRedirection } from '@/utils/app-redirection'
import { trackCreateApp } from '@/utils/create-app-tracking'
import ShortcutsName from '../../workflow/shortcuts-name'
@ -74,6 +75,7 @@ const CreateFromDSLModal = ({ show, onSuccess, onClose, activeTab = CreateFromDS
const { isCurrentWorkspaceEditor } = useAppContext()
const { plan, enableBilling } = useProviderContext()
const isAppsFull = (enableBilling && plan.usage.buildApps >= plan.total.buildApps)
const invalidateAppList = useInvalidateAppList()
const isCreatingRef = useRef(false)
@ -124,6 +126,7 @@ const CreateFromDSLModal = ({ show, onSuccess, onClose, activeTab = CreateFromDS
: undefined,
})
localStorage.setItem(NEED_REFRESH_APP_LIST_KEY, '1')
invalidateAppList()
if (app_id)
await handleCheckPluginDependencies(app_id)
getRedirection(isCurrentWorkspaceEditor, { id: app_id!, mode: app_mode }, push)
@ -181,6 +184,7 @@ const CreateFromDSLModal = ({ show, onSuccess, onClose, activeTab = CreateFromDS
if (app_id)
await handleCheckPluginDependencies(app_id)
localStorage.setItem(NEED_REFRESH_APP_LIST_KEY, '1')
invalidateAppList()
getRedirection(isCurrentWorkspaceEditor, { id: app_id!, mode: app_mode }, push)
}
else if (status === DSLImportStatus.FAILED) {

View File

@ -19,6 +19,7 @@ import {
importDSL,
importDSLConfirm,
} from '@/service/apps'
import { useInvalidateAppList } from '@/service/use-apps'
import { getRedirection } from '@/utils/app-redirection'
type DSLPayload = {
@ -42,6 +43,7 @@ export const useImportDSL = () => {
const { handleCheckPluginDependencies } = usePluginDependencies()
const isCurrentWorkspaceEditor = useSelector(s => s.isCurrentWorkspaceEditor)
const { push } = useRouter()
const invalidateAppList = useInvalidateAppList()
const [versions, setVersions] = useState<{ importedVersion: string, systemVersion: string }>()
const importIdRef = useRef<string>('')
@ -87,6 +89,7 @@ export const useImportDSL = () => {
toast.warning(message, { description })
onSuccess?.()
localStorage.setItem(NEED_REFRESH_APP_LIST_KEY, '1')
invalidateAppList()
await handleCheckPluginDependencies(app_id)
getRedirection(isCurrentWorkspaceEditor, { id: app_id, mode: app_mode }, push)
}
@ -110,7 +113,7 @@ export const useImportDSL = () => {
finally {
setIsFetching(false)
}
}, [t, handleCheckPluginDependencies, isCurrentWorkspaceEditor, push, isFetching])
}, [t, handleCheckPluginDependencies, isCurrentWorkspaceEditor, push, isFetching, invalidateAppList])
const handleImportDSLConfirm = useCallback(async (
{
@ -138,6 +141,7 @@ export const useImportDSL = () => {
toast.success(t('newApp.appCreated', { ns: 'app' }))
await handleCheckPluginDependencies(app_id)
localStorage.setItem(NEED_REFRESH_APP_LIST_KEY, '1')
invalidateAppList()
getRedirection(isCurrentWorkspaceEditor, { id: app_id!, mode: app_mode }, push)
}
else if (status === DSLImportStatus.FAILED) {
@ -152,7 +156,7 @@ export const useImportDSL = () => {
finally {
setIsFetching(false)
}
}, [t, handleCheckPluginDependencies, isCurrentWorkspaceEditor, push, isFetching])
}, [t, handleCheckPluginDependencies, isCurrentWorkspaceEditor, push, isFetching, invalidateAppList])
return {
handleImportDSL,