mirror of
https://github.com/langgenius/dify.git
synced 2026-05-05 18:08:07 +08:00
feat: enhance configuration and environment setup for SSH sandbox and Creators Platform; update local excludes and improve component logic in the web app
This commit is contained in:
@ -11,12 +11,14 @@ const {
|
||||
mockUploadMutateAsync,
|
||||
mockPrepareSkillUploadFile,
|
||||
mockEmitTreeUpdate,
|
||||
mockToastNotify,
|
||||
mockToastSuccess,
|
||||
mockToastError,
|
||||
} = vi.hoisted(() => ({
|
||||
mockUploadMutateAsync: vi.fn(),
|
||||
mockPrepareSkillUploadFile: vi.fn(),
|
||||
mockEmitTreeUpdate: vi.fn(),
|
||||
mockToastNotify: vi.fn(),
|
||||
mockToastSuccess: vi.fn(),
|
||||
mockToastError: vi.fn(),
|
||||
}))
|
||||
|
||||
vi.mock('@/service/use-app-asset', () => ({
|
||||
@ -34,9 +36,10 @@ vi.mock('../data/use-skill-tree-collaboration', () => ({
|
||||
useSkillTreeUpdateEmitter: () => mockEmitTreeUpdate,
|
||||
}))
|
||||
|
||||
vi.mock('@/app/components/base/toast', () => ({
|
||||
default: {
|
||||
notify: mockToastNotify,
|
||||
vi.mock('@/app/components/base/ui/toast', () => ({
|
||||
toast: {
|
||||
success: mockToastSuccess,
|
||||
error: mockToastError,
|
||||
},
|
||||
}))
|
||||
|
||||
@ -169,10 +172,7 @@ describe('useFileDrop', () => {
|
||||
|
||||
expect(mockPrepareSkillUploadFile).not.toHaveBeenCalled()
|
||||
expect(mockUploadMutateAsync).not.toHaveBeenCalled()
|
||||
expect(mockToastNotify).toHaveBeenCalledWith({
|
||||
type: 'error',
|
||||
message: 'workflow.skillSidebar.menu.folderDropNotSupported',
|
||||
})
|
||||
expect(mockToastError).toHaveBeenCalledWith('workflow.skillSidebar.menu.folderDropNotSupported')
|
||||
expect(store.getState().currentDragType).toBeNull()
|
||||
expect(store.getState().dragOverFolderId).toBeNull()
|
||||
})
|
||||
@ -201,14 +201,8 @@ describe('useFileDrop', () => {
|
||||
parentId: 'folder-mixed',
|
||||
})
|
||||
expect(mockEmitTreeUpdate).toHaveBeenCalledTimes(1)
|
||||
expect(mockToastNotify).toHaveBeenNthCalledWith(1, {
|
||||
type: 'error',
|
||||
message: 'workflow.skillSidebar.menu.folderDropNotSupported',
|
||||
})
|
||||
expect(mockToastNotify).toHaveBeenNthCalledWith(2, {
|
||||
type: 'success',
|
||||
message: 'workflow.skillSidebar.menu.filesUploaded:{"count":1}',
|
||||
})
|
||||
expect(mockToastError).toHaveBeenCalledWith('workflow.skillSidebar.menu.folderDropNotSupported')
|
||||
expect(mockToastSuccess).toHaveBeenCalledWith('workflow.skillSidebar.menu.filesUploaded:{"count":1}')
|
||||
})
|
||||
})
|
||||
|
||||
@ -245,10 +239,7 @@ describe('useFileDrop', () => {
|
||||
parentId: 'folder-9',
|
||||
})
|
||||
expect(mockEmitTreeUpdate).toHaveBeenCalledTimes(1)
|
||||
expect(mockToastNotify).toHaveBeenCalledWith({
|
||||
type: 'success',
|
||||
message: 'workflow.skillSidebar.menu.filesUploaded:{"count":2}',
|
||||
})
|
||||
expect(mockToastSuccess).toHaveBeenCalledWith('workflow.skillSidebar.menu.filesUploaded:{"count":2}')
|
||||
})
|
||||
})
|
||||
|
||||
@ -269,10 +260,7 @@ describe('useFileDrop', () => {
|
||||
|
||||
expect(mockUploadMutateAsync).toHaveBeenCalledTimes(1)
|
||||
expect(mockEmitTreeUpdate).not.toHaveBeenCalled()
|
||||
expect(mockToastNotify).toHaveBeenCalledWith({
|
||||
type: 'error',
|
||||
message: 'workflow.skillSidebar.menu.uploadError',
|
||||
})
|
||||
expect(mockToastError).toHaveBeenCalledWith('workflow.skillSidebar.menu.uploadError')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@ -31,11 +31,13 @@ const createDeferred = <T,>(): Deferred<T> => {
|
||||
const {
|
||||
mockGetFileDownloadUrl,
|
||||
mockDownloadUrl,
|
||||
mockToastNotify,
|
||||
mockToastSuccess,
|
||||
mockToastError,
|
||||
} = vi.hoisted(() => ({
|
||||
mockGetFileDownloadUrl: vi.fn<(request: DownloadRequest) => Promise<DownloadResponse>>(),
|
||||
mockDownloadUrl: vi.fn<(payload: { url: string, fileName?: string }) => void>(),
|
||||
mockToastNotify: vi.fn<(payload: { type: string, message: string }) => void>(),
|
||||
mockToastSuccess: vi.fn(),
|
||||
mockToastError: vi.fn(),
|
||||
}))
|
||||
|
||||
vi.mock('@/service/client', () => ({
|
||||
@ -50,9 +52,10 @@ vi.mock('@/utils/download', () => ({
|
||||
downloadUrl: mockDownloadUrl,
|
||||
}))
|
||||
|
||||
vi.mock('@/app/components/base/toast', () => ({
|
||||
default: {
|
||||
notify: mockToastNotify,
|
||||
vi.mock('@/app/components/base/ui/toast', () => ({
|
||||
toast: {
|
||||
success: mockToastSuccess,
|
||||
error: mockToastError,
|
||||
},
|
||||
}))
|
||||
|
||||
@ -109,7 +112,8 @@ describe('useDownloadOperation', () => {
|
||||
url: 'https://example.com/file.txt',
|
||||
fileName: 'notes.md',
|
||||
})
|
||||
expect(mockToastNotify).not.toHaveBeenCalled()
|
||||
expect(mockToastSuccess).not.toHaveBeenCalled()
|
||||
expect(mockToastError).not.toHaveBeenCalled()
|
||||
expect(result.current.isDownloading).toBe(false)
|
||||
})
|
||||
|
||||
@ -163,10 +167,8 @@ describe('useDownloadOperation', () => {
|
||||
|
||||
expect(onClose).toHaveBeenCalledTimes(1)
|
||||
expect(mockDownloadUrl).not.toHaveBeenCalled()
|
||||
expect(mockToastNotify).toHaveBeenCalledWith({
|
||||
type: 'error',
|
||||
message: 'workflow.skillSidebar.menu.downloadError',
|
||||
})
|
||||
expect(mockToastError).toHaveBeenCalledWith('workflow.skillSidebar.menu.downloadError')
|
||||
expect(mockToastSuccess).not.toHaveBeenCalled()
|
||||
expect(result.current.isDownloading).toBe(false)
|
||||
})
|
||||
})
|
||||
|
||||
@ -16,7 +16,8 @@ const mocks = vi.hoisted(() => ({
|
||||
deletePending: false,
|
||||
deleteMutateAsync: vi.fn<(payload: DeleteMutationPayload) => Promise<void>>(),
|
||||
emitTreeUpdate: vi.fn<() => void>(),
|
||||
toastNotify: vi.fn<(payload: { type: string, message: string }) => void>(),
|
||||
toastSuccess: vi.fn<(message: string) => void>(),
|
||||
toastError: vi.fn<(message: string) => void>(),
|
||||
getAllDescendantFileIds: vi.fn<(nodeId: string, nodes: TreeNodeData[]) => string[]>(),
|
||||
}))
|
||||
|
||||
@ -35,9 +36,10 @@ vi.mock('../../../utils/tree-utils', () => ({
|
||||
getAllDescendantFileIds: mocks.getAllDescendantFileIds,
|
||||
}))
|
||||
|
||||
vi.mock('@/app/components/base/toast', () => ({
|
||||
default: {
|
||||
notify: mocks.toastNotify,
|
||||
vi.mock('@/app/components/base/ui/toast', () => ({
|
||||
toast: {
|
||||
success: mocks.toastSuccess,
|
||||
error: mocks.toastError,
|
||||
},
|
||||
}))
|
||||
|
||||
@ -234,10 +236,7 @@ describe('useModifyOperations', () => {
|
||||
expect(clearDraftContent).toHaveBeenNthCalledWith(2, 'desc-2')
|
||||
expect(clearDraftContent).toHaveBeenNthCalledWith(3, 'file-7')
|
||||
|
||||
expect(mocks.toastNotify).toHaveBeenCalledWith({
|
||||
type: 'success',
|
||||
message: 'workflow.skillSidebar.menu.fileDeleted',
|
||||
})
|
||||
expect(mocks.toastSuccess).toHaveBeenCalledWith('workflow.skillSidebar.menu.fileDeleted')
|
||||
expect(result.current.showDeleteConfirm).toBe(false)
|
||||
expect(onClose).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
@ -269,10 +268,7 @@ describe('useModifyOperations', () => {
|
||||
expect(clearDraftContent).toHaveBeenCalledWith('file-in-folder')
|
||||
expect(closeTab).not.toHaveBeenCalledWith('folder-9')
|
||||
expect(clearDraftContent).not.toHaveBeenCalledWith('folder-9')
|
||||
expect(mocks.toastNotify).toHaveBeenCalledWith({
|
||||
type: 'success',
|
||||
message: 'workflow.skillSidebar.menu.deleted',
|
||||
})
|
||||
expect(mocks.toastSuccess).toHaveBeenCalledWith('workflow.skillSidebar.menu.deleted')
|
||||
})
|
||||
})
|
||||
|
||||
@ -303,10 +299,7 @@ describe('useModifyOperations', () => {
|
||||
expect(mocks.emitTreeUpdate).not.toHaveBeenCalled()
|
||||
expect(closeTab).not.toHaveBeenCalled()
|
||||
expect(clearDraftContent).not.toHaveBeenCalled()
|
||||
expect(mocks.toastNotify).toHaveBeenCalledWith({
|
||||
type: 'error',
|
||||
message: 'workflow.skillSidebar.menu.deleteError',
|
||||
})
|
||||
expect(mocks.toastError).toHaveBeenCalledWith('workflow.skillSidebar.menu.deleteError')
|
||||
expect(result.current.showDeleteConfirm).toBe(false)
|
||||
expect(onClose).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
@ -329,10 +322,7 @@ describe('useModifyOperations', () => {
|
||||
})
|
||||
|
||||
expect(mocks.getAllDescendantFileIds).not.toHaveBeenCalled()
|
||||
expect(mocks.toastNotify).toHaveBeenCalledWith({
|
||||
type: 'error',
|
||||
message: 'workflow.skillSidebar.menu.fileDeleteError',
|
||||
})
|
||||
expect(mocks.toastError).toHaveBeenCalledWith('workflow.skillSidebar.menu.fileDeleteError')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@ -22,7 +22,8 @@ const mocks = vi.hoisted(() => ({
|
||||
movePending: false,
|
||||
moveMutateAsync: vi.fn<(payload: MoveMutationPayload) => Promise<void>>(),
|
||||
emitTreeUpdate: vi.fn<() => void>(),
|
||||
toastNotify: vi.fn<(payload: { type: string, message: string }) => void>(),
|
||||
toastSuccess: vi.fn<(message: string) => void>(),
|
||||
toastError: vi.fn<(message: string) => void>(),
|
||||
toApiParentId: vi.fn<(folderId: string | null | undefined) => string | null>(),
|
||||
}))
|
||||
|
||||
@ -45,9 +46,10 @@ vi.mock('../../../utils/tree-utils', () => ({
|
||||
toApiParentId: mocks.toApiParentId,
|
||||
}))
|
||||
|
||||
vi.mock('@/app/components/base/toast', () => ({
|
||||
default: {
|
||||
notify: mocks.toastNotify,
|
||||
vi.mock('@/app/components/base/ui/toast', () => ({
|
||||
toast: {
|
||||
success: mocks.toastSuccess,
|
||||
error: mocks.toastError,
|
||||
},
|
||||
}))
|
||||
|
||||
@ -90,10 +92,7 @@ describe('useNodeMove', () => {
|
||||
},
|
||||
})
|
||||
expect(mocks.emitTreeUpdate).toHaveBeenCalledTimes(1)
|
||||
expect(mocks.toastNotify).toHaveBeenCalledWith({
|
||||
type: 'success',
|
||||
message: 'workflow.skillSidebar.menu.moved',
|
||||
})
|
||||
expect(mocks.toastSuccess).toHaveBeenCalledWith('workflow.skillSidebar.menu.moved')
|
||||
})
|
||||
|
||||
it('should use empty appId when app detail is unavailable', async () => {
|
||||
@ -126,10 +125,7 @@ describe('useNodeMove', () => {
|
||||
})
|
||||
|
||||
expect(mocks.emitTreeUpdate).not.toHaveBeenCalled()
|
||||
expect(mocks.toastNotify).toHaveBeenCalledWith({
|
||||
type: 'error',
|
||||
message: 'workflow.skillSidebar.menu.moveError',
|
||||
})
|
||||
expect(mocks.toastError).toHaveBeenCalledWith('workflow.skillSidebar.menu.moveError')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@ -22,7 +22,8 @@ const mocks = vi.hoisted(() => ({
|
||||
reorderPending: false,
|
||||
reorderMutateAsync: vi.fn<(payload: ReorderMutationPayload) => Promise<void>>(),
|
||||
emitTreeUpdate: vi.fn<() => void>(),
|
||||
toastNotify: vi.fn<(payload: { type: string, message: string }) => void>(),
|
||||
toastSuccess: vi.fn<(message: string) => void>(),
|
||||
toastError: vi.fn<(message: string) => void>(),
|
||||
}))
|
||||
|
||||
vi.mock('@/app/components/app/store', () => ({
|
||||
@ -40,9 +41,10 @@ vi.mock('../data/use-skill-tree-collaboration', () => ({
|
||||
useSkillTreeUpdateEmitter: () => mocks.emitTreeUpdate,
|
||||
}))
|
||||
|
||||
vi.mock('@/app/components/base/toast', () => ({
|
||||
default: {
|
||||
notify: mocks.toastNotify,
|
||||
vi.mock('@/app/components/base/ui/toast', () => ({
|
||||
toast: {
|
||||
success: mocks.toastSuccess,
|
||||
error: mocks.toastError,
|
||||
},
|
||||
}))
|
||||
|
||||
@ -82,10 +84,7 @@ describe('useNodeReorder', () => {
|
||||
},
|
||||
})
|
||||
expect(mocks.emitTreeUpdate).toHaveBeenCalledTimes(1)
|
||||
expect(mocks.toastNotify).toHaveBeenCalledWith({
|
||||
type: 'success',
|
||||
message: 'workflow.skillSidebar.menu.moved',
|
||||
})
|
||||
expect(mocks.toastSuccess).toHaveBeenCalledWith('workflow.skillSidebar.menu.moved')
|
||||
})
|
||||
|
||||
it('should use empty appId when app detail is missing', async () => {
|
||||
@ -117,10 +116,7 @@ describe('useNodeReorder', () => {
|
||||
})
|
||||
|
||||
expect(mocks.emitTreeUpdate).not.toHaveBeenCalled()
|
||||
expect(mocks.toastNotify).toHaveBeenCalledWith({
|
||||
type: 'error',
|
||||
message: 'workflow.skillSidebar.menu.moveError',
|
||||
})
|
||||
expect(mocks.toastError).toHaveBeenCalledWith('workflow.skillSidebar.menu.moveError')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@ -56,7 +56,8 @@ const mocks = vi.hoisted(() => ({
|
||||
movePending: false,
|
||||
moveMutateAsync: vi.fn<(payload: MoveMutationPayload) => Promise<void>>(),
|
||||
emitTreeUpdate: vi.fn<() => void>(),
|
||||
toastNotify: vi.fn<(payload: { type: string, message: string }) => void>(),
|
||||
toastSuccess: vi.fn<(message: string) => void>(),
|
||||
toastError: vi.fn<(message: string) => void>(),
|
||||
getTargetFolderIdFromSelection: vi.fn<(selectedId: string | null, nodes: TreeNodeData[]) => string>(),
|
||||
toApiParentId: vi.fn<(folderId: string | null | undefined) => string | null>(),
|
||||
findNodeById: vi.fn<(nodes: TreeNodeData[], nodeId: string) => TreeNodeData | null>(),
|
||||
@ -89,9 +90,10 @@ vi.mock('../../../utils/tree-utils', () => ({
|
||||
findNodeById: mocks.findNodeById,
|
||||
}))
|
||||
|
||||
vi.mock('@/app/components/base/toast', () => ({
|
||||
default: {
|
||||
notify: mocks.toastNotify,
|
||||
vi.mock('@/app/components/base/ui/toast', () => ({
|
||||
toast: {
|
||||
success: mocks.toastSuccess,
|
||||
error: mocks.toastError,
|
||||
},
|
||||
}))
|
||||
|
||||
@ -151,7 +153,8 @@ describe('usePasteOperation', () => {
|
||||
|
||||
expect(mocks.getTargetFolderIdFromSelection).not.toHaveBeenCalled()
|
||||
expect(mocks.moveMutateAsync).not.toHaveBeenCalled()
|
||||
expect(mocks.toastNotify).not.toHaveBeenCalled()
|
||||
expect(mocks.toastSuccess).not.toHaveBeenCalled()
|
||||
expect(mocks.toastError).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('should no-op when clipboard has no node ids', async () => {
|
||||
@ -188,10 +191,7 @@ describe('usePasteOperation', () => {
|
||||
})
|
||||
|
||||
expect(mocks.moveMutateAsync).not.toHaveBeenCalled()
|
||||
expect(mocks.toastNotify).toHaveBeenCalledWith({
|
||||
type: 'error',
|
||||
message: 'workflow.skillSidebar.menu.cannotMoveToSelf',
|
||||
})
|
||||
expect(mocks.toastError).toHaveBeenCalledWith('workflow.skillSidebar.menu.cannotMoveToSelf')
|
||||
})
|
||||
})
|
||||
|
||||
@ -232,10 +232,7 @@ describe('usePasteOperation', () => {
|
||||
})
|
||||
expect(mocks.workflowState.clearClipboard).toHaveBeenCalledTimes(1)
|
||||
expect(mocks.emitTreeUpdate).toHaveBeenCalledTimes(1)
|
||||
expect(mocks.toastNotify).toHaveBeenCalledWith({
|
||||
type: 'success',
|
||||
message: 'workflow.skillSidebar.menu.moved',
|
||||
})
|
||||
expect(mocks.toastSuccess).toHaveBeenCalledWith('workflow.skillSidebar.menu.moved')
|
||||
})
|
||||
|
||||
it('should fallback to selectedTreeNodeId when tree has no selected node', async () => {
|
||||
@ -280,10 +277,7 @@ describe('usePasteOperation', () => {
|
||||
|
||||
expect(mocks.workflowState.clearClipboard).not.toHaveBeenCalled()
|
||||
expect(mocks.emitTreeUpdate).not.toHaveBeenCalled()
|
||||
expect(mocks.toastNotify).toHaveBeenCalledWith({
|
||||
type: 'error',
|
||||
message: 'workflow.skillSidebar.menu.moveError',
|
||||
})
|
||||
expect(mocks.toastError).toHaveBeenCalledWith('workflow.skillSidebar.menu.moveError')
|
||||
})
|
||||
|
||||
it('should prevent re-entrant paste while a paste is in progress', async () => {
|
||||
|
||||
@ -8,9 +8,10 @@ import { START_TAB_ID } from '../constants'
|
||||
import { useSkillSaveManager } from './skill-save-context'
|
||||
import { SkillSaveProvider } from './use-skill-save-manager'
|
||||
|
||||
const { mockMutateAsync, mockToastNotify } = vi.hoisted(() => ({
|
||||
const { mockMutateAsync, mockToastSuccess, mockToastError } = vi.hoisted(() => ({
|
||||
mockMutateAsync: vi.fn(),
|
||||
mockToastNotify: vi.fn(),
|
||||
mockToastSuccess: vi.fn(),
|
||||
mockToastError: vi.fn(),
|
||||
}))
|
||||
|
||||
vi.mock('@/service/use-app-asset', () => ({
|
||||
@ -19,9 +20,10 @@ vi.mock('@/service/use-app-asset', () => ({
|
||||
}),
|
||||
}))
|
||||
|
||||
vi.mock('@/app/components/base/toast', () => ({
|
||||
default: {
|
||||
notify: mockToastNotify,
|
||||
vi.mock('@/app/components/base/ui/toast', () => ({
|
||||
toast: {
|
||||
success: mockToastSuccess,
|
||||
error: mockToastError,
|
||||
},
|
||||
}))
|
||||
|
||||
@ -507,11 +509,9 @@ describe('useSkillSaveManager', () => {
|
||||
|
||||
// Assert
|
||||
await waitFor(() => {
|
||||
expect(mockToastNotify).toHaveBeenCalledWith({
|
||||
type: 'success',
|
||||
message: 'common.api.saved',
|
||||
})
|
||||
expect(mockToastSuccess).toHaveBeenCalledWith('common.api.saved')
|
||||
})
|
||||
expect(mockToastError).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('should show error toast when save fails', async () => {
|
||||
@ -531,11 +531,9 @@ describe('useSkillSaveManager', () => {
|
||||
|
||||
// Assert
|
||||
await waitFor(() => {
|
||||
expect(mockToastNotify).toHaveBeenCalledWith({
|
||||
type: 'error',
|
||||
message: 'Network error',
|
||||
})
|
||||
expect(mockToastError).toHaveBeenCalledWith('Network error')
|
||||
})
|
||||
expect(mockToastSuccess).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('should use registered fallback content for keyboard save', async () => {
|
||||
|
||||
Reference in New Issue
Block a user