mirror of
https://github.com/langgenius/dify.git
synced 2026-05-05 01:48:04 +08:00
fix: adding a restore API for version control on workflow draft (#33582)
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
115
web/app/components/workflow/panel/__tests__/index.spec.tsx
Normal file
115
web/app/components/workflow/panel/__tests__/index.spec.tsx
Normal file
@ -0,0 +1,115 @@
|
||||
import type { PanelProps } from '../index'
|
||||
import { screen } from '@testing-library/react'
|
||||
import { createNode } from '../../__tests__/fixtures'
|
||||
import { resetReactFlowMockState, rfState } from '../../__tests__/reactflow-mock-state'
|
||||
import { renderWorkflowComponent } from '../../__tests__/workflow-test-env'
|
||||
import Panel from '../index'
|
||||
|
||||
const mockVersionHistoryPanel = vi.hoisted(() => vi.fn())
|
||||
|
||||
class MockResizeObserver implements ResizeObserver {
|
||||
observe = vi.fn()
|
||||
unobserve = vi.fn()
|
||||
disconnect = vi.fn()
|
||||
|
||||
constructor(_callback: ResizeObserverCallback) {}
|
||||
}
|
||||
|
||||
vi.mock('@/next/dynamic', () => ({
|
||||
default: () => (props: { latestVersionId?: string }) => {
|
||||
mockVersionHistoryPanel(props)
|
||||
return <div data-testid="version-history-panel">{props.latestVersionId}</div>
|
||||
},
|
||||
}))
|
||||
|
||||
vi.mock('reactflow', async () => {
|
||||
const mod = await import('../../__tests__/reactflow-mock-state')
|
||||
const base = mod.createReactFlowModuleMock()
|
||||
|
||||
return {
|
||||
...base,
|
||||
useStore: vi.fn(selector => selector({
|
||||
getNodes: () => mod.rfState.nodes,
|
||||
})),
|
||||
}
|
||||
})
|
||||
|
||||
vi.mock('../env-panel', () => ({
|
||||
default: () => <div data-testid="env-panel" />,
|
||||
}))
|
||||
|
||||
vi.mock('../../nodes', () => ({
|
||||
Panel: ({ id }: { id: string }) => <div data-testid="node-panel">{id}</div>,
|
||||
}))
|
||||
|
||||
const versionHistoryPanelProps = {
|
||||
latestVersionId: 'version-1',
|
||||
restoreVersionUrl: (versionId: string) => `/workflows/${versionId}/restore`,
|
||||
} satisfies NonNullable<PanelProps['versionHistoryPanelProps']>
|
||||
|
||||
describe('Panel', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
resetReactFlowMockState()
|
||||
vi.stubGlobal('ResizeObserver', MockResizeObserver)
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
vi.unstubAllGlobals()
|
||||
})
|
||||
|
||||
describe('Version History Panel', () => {
|
||||
it('should render the version history panel when the panel is open and props are provided', () => {
|
||||
renderWorkflowComponent(
|
||||
<Panel versionHistoryPanelProps={versionHistoryPanelProps} />,
|
||||
{
|
||||
initialStoreState: {
|
||||
showWorkflowVersionHistoryPanel: true,
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
expect(screen.getByTestId('version-history-panel')).toHaveTextContent('version-1')
|
||||
expect(mockVersionHistoryPanel).toHaveBeenCalledWith(expect.objectContaining({
|
||||
latestVersionId: 'version-1',
|
||||
}))
|
||||
})
|
||||
|
||||
it('should not render the version history panel when the panel is open but props are missing', () => {
|
||||
renderWorkflowComponent(
|
||||
<Panel />,
|
||||
{
|
||||
initialStoreState: {
|
||||
showWorkflowVersionHistoryPanel: true,
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
expect(screen.queryByTestId('version-history-panel')).not.toBeInTheDocument()
|
||||
expect(mockVersionHistoryPanel).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('should not render the version history panel when the panel is closed', () => {
|
||||
rfState.nodes = [
|
||||
createNode({
|
||||
id: 'selected-node',
|
||||
data: {
|
||||
selected: true,
|
||||
},
|
||||
}),
|
||||
] as typeof rfState.nodes
|
||||
|
||||
renderWorkflowComponent(
|
||||
<Panel versionHistoryPanelProps={versionHistoryPanelProps} />,
|
||||
{
|
||||
initialStoreState: {
|
||||
showWorkflowVersionHistoryPanel: false,
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
expect(screen.queryByTestId('version-history-panel')).not.toBeInTheDocument()
|
||||
expect(screen.getByTestId('node-panel')).toHaveTextContent('selected-node')
|
||||
})
|
||||
})
|
||||
})
|
||||
@ -140,7 +140,7 @@ const Panel: FC<PanelProps> = ({
|
||||
components?.right
|
||||
}
|
||||
{
|
||||
showWorkflowVersionHistoryPanel && (
|
||||
showWorkflowVersionHistoryPanel && versionHistoryPanelProps && (
|
||||
<VersionHistoryPanel {...versionHistoryPanelProps} />
|
||||
)
|
||||
}
|
||||
|
||||
@ -1,14 +1,55 @@
|
||||
import { fireEvent, render, screen } from '@testing-library/react'
|
||||
import { WorkflowVersion } from '../../../types'
|
||||
import type { Shape } from '../../../store'
|
||||
import type { VersionHistory } from '@/types/workflow'
|
||||
import { fireEvent, render, screen, waitFor } from '@testing-library/react'
|
||||
import { useEffect } from 'react'
|
||||
import { VersionHistoryContextMenuOptions, WorkflowVersion } from '../../../types'
|
||||
|
||||
const mockHandleRestoreFromPublishedWorkflow = vi.fn()
|
||||
const mockHandleLoadBackupDraft = vi.fn()
|
||||
const mockHandleRefreshWorkflowDraft = vi.fn()
|
||||
const mockRestoreWorkflow = vi.fn()
|
||||
const mockSetCurrentVersion = vi.fn()
|
||||
const mockSetShowWorkflowVersionHistoryPanel = vi.fn()
|
||||
const mockWorkflowStoreSetState = vi.fn()
|
||||
|
||||
type MockWorkflowStoreState = {
|
||||
setShowWorkflowVersionHistoryPanel: ReturnType<typeof vi.fn>
|
||||
currentVersion: null
|
||||
setCurrentVersion: typeof mockSetCurrentVersion
|
||||
const createVersionHistory = (overrides: Partial<VersionHistory> = {}): VersionHistory => ({
|
||||
id: 'version-id',
|
||||
version: WorkflowVersion.Draft,
|
||||
graph: { nodes: [], edges: [] },
|
||||
features: {
|
||||
opening_statement: '',
|
||||
suggested_questions: [],
|
||||
suggested_questions_after_answer: { enabled: false },
|
||||
text_to_speech: { enabled: false },
|
||||
speech_to_text: { enabled: false },
|
||||
retriever_resource: { enabled: false },
|
||||
sensitive_word_avoidance: { enabled: false },
|
||||
file_upload: { image: { enabled: false } },
|
||||
},
|
||||
created_at: Date.now() / 1000,
|
||||
created_by: { id: 'user-1', name: 'User 1', email: 'user-1@example.com' },
|
||||
hash: 'test-hash',
|
||||
updated_at: Date.now() / 1000,
|
||||
updated_by: { id: 'user-1', name: 'User 1', email: 'user-1@example.com' },
|
||||
tool_published: false,
|
||||
environment_variables: [],
|
||||
marked_name: '',
|
||||
marked_comment: '',
|
||||
...overrides,
|
||||
})
|
||||
|
||||
let mockCurrentVersion: VersionHistory | null = null
|
||||
|
||||
type MockVersionStoreState = Pick<Shape, 'currentVersion' | 'setCurrentVersion' | 'setShowWorkflowVersionHistoryPanel'>
|
||||
type MockRestoreConfirmModalProps = {
|
||||
isOpen: boolean
|
||||
versionInfo: VersionHistory
|
||||
onRestore: (item: VersionHistory) => void
|
||||
}
|
||||
type MockVersionHistoryItemProps = {
|
||||
item: VersionHistory
|
||||
onClick: (item: VersionHistory) => void
|
||||
handleClickMenuItem: (operation: VersionHistoryContextMenuOptions) => void
|
||||
}
|
||||
|
||||
vi.mock('@/context/app-context', () => ({
|
||||
@ -19,52 +60,23 @@ vi.mock('@/service/use-workflow', () => ({
|
||||
useDeleteWorkflow: () => ({ mutateAsync: vi.fn() }),
|
||||
useInvalidAllLastRun: () => vi.fn(),
|
||||
useResetWorkflowVersionHistory: () => vi.fn(),
|
||||
useRestoreWorkflow: () => ({ mutateAsync: mockRestoreWorkflow }),
|
||||
useUpdateWorkflow: () => ({ mutateAsync: vi.fn() }),
|
||||
useWorkflowVersionHistory: () => ({
|
||||
data: {
|
||||
pages: [
|
||||
{
|
||||
items: [
|
||||
{
|
||||
createVersionHistory({
|
||||
id: 'draft-version-id',
|
||||
version: WorkflowVersion.Draft,
|
||||
graph: { nodes: [], edges: [], viewport: null },
|
||||
features: {
|
||||
opening_statement: '',
|
||||
suggested_questions: [],
|
||||
suggested_questions_after_answer: { enabled: false },
|
||||
text_to_speech: { enabled: false },
|
||||
speech_to_text: { enabled: false },
|
||||
retriever_resource: { enabled: false },
|
||||
sensitive_word_avoidance: { enabled: false },
|
||||
file_upload: { image: { enabled: false } },
|
||||
},
|
||||
created_at: Date.now() / 1000,
|
||||
created_by: { id: 'user-1', name: 'User 1' },
|
||||
environment_variables: [],
|
||||
marked_name: '',
|
||||
marked_comment: '',
|
||||
},
|
||||
{
|
||||
}),
|
||||
createVersionHistory({
|
||||
id: 'published-version-id',
|
||||
version: '2024-01-01T00:00:00Z',
|
||||
graph: { nodes: [], edges: [], viewport: null },
|
||||
features: {
|
||||
opening_statement: '',
|
||||
suggested_questions: [],
|
||||
suggested_questions_after_answer: { enabled: false },
|
||||
text_to_speech: { enabled: false },
|
||||
speech_to_text: { enabled: false },
|
||||
retriever_resource: { enabled: false },
|
||||
sensitive_word_avoidance: { enabled: false },
|
||||
file_upload: { image: { enabled: false } },
|
||||
},
|
||||
created_at: Date.now() / 1000,
|
||||
created_by: { id: 'user-1', name: 'User 1' },
|
||||
environment_variables: [],
|
||||
marked_name: 'v1.0',
|
||||
marked_comment: 'First release',
|
||||
},
|
||||
}),
|
||||
],
|
||||
},
|
||||
],
|
||||
@ -77,7 +89,7 @@ vi.mock('@/service/use-workflow', () => ({
|
||||
|
||||
vi.mock('../../../hooks', () => ({
|
||||
useDSL: () => ({ handleExportDSL: vi.fn() }),
|
||||
useNodesSyncDraft: () => ({ handleSyncWorkflowDraft: vi.fn() }),
|
||||
useWorkflowRefreshDraft: () => ({ handleRefreshWorkflowDraft: mockHandleRefreshWorkflowDraft }),
|
||||
useWorkflowRun: () => ({
|
||||
handleRestoreFromPublishedWorkflow: mockHandleRestoreFromPublishedWorkflow,
|
||||
handleLoadBackupDraft: mockHandleLoadBackupDraft,
|
||||
@ -92,10 +104,10 @@ vi.mock('../../../hooks-store', () => ({
|
||||
}))
|
||||
|
||||
vi.mock('../../../store', () => ({
|
||||
useStore: <T,>(selector: (state: MockWorkflowStoreState) => T) => {
|
||||
const state: MockWorkflowStoreState = {
|
||||
setShowWorkflowVersionHistoryPanel: vi.fn(),
|
||||
currentVersion: null,
|
||||
useStore: <T,>(selector: (state: MockVersionStoreState) => T) => {
|
||||
const state: MockVersionStoreState = {
|
||||
setShowWorkflowVersionHistoryPanel: mockSetShowWorkflowVersionHistoryPanel,
|
||||
currentVersion: mockCurrentVersion,
|
||||
setCurrentVersion: mockSetCurrentVersion,
|
||||
}
|
||||
return selector(state)
|
||||
@ -103,10 +115,10 @@ vi.mock('../../../store', () => ({
|
||||
useWorkflowStore: () => ({
|
||||
getState: () => ({
|
||||
deleteAllInspectVars: vi.fn(),
|
||||
setShowWorkflowVersionHistoryPanel: vi.fn(),
|
||||
setShowWorkflowVersionHistoryPanel: mockSetShowWorkflowVersionHistoryPanel,
|
||||
setCurrentVersion: mockSetCurrentVersion,
|
||||
}),
|
||||
setState: vi.fn(),
|
||||
setState: mockWorkflowStoreSetState,
|
||||
}),
|
||||
}))
|
||||
|
||||
@ -115,16 +127,54 @@ vi.mock('../delete-confirm-modal', () => ({
|
||||
}))
|
||||
|
||||
vi.mock('../restore-confirm-modal', () => ({
|
||||
default: () => null,
|
||||
default: (props: MockRestoreConfirmModalProps) => {
|
||||
const MockRestoreConfirmModal = () => {
|
||||
const { isOpen, versionInfo, onRestore } = props
|
||||
|
||||
if (!isOpen)
|
||||
return null
|
||||
|
||||
return <button onClick={() => onRestore(versionInfo)}>confirm restore</button>
|
||||
}
|
||||
|
||||
return <MockRestoreConfirmModal />
|
||||
},
|
||||
}))
|
||||
|
||||
vi.mock('@/app/components/app/app-publisher/version-info-modal', () => ({
|
||||
default: () => null,
|
||||
}))
|
||||
|
||||
vi.mock('../version-history-item', () => ({
|
||||
default: (props: MockVersionHistoryItemProps) => {
|
||||
const MockVersionHistoryItem = () => {
|
||||
const { item, onClick, handleClickMenuItem } = props
|
||||
|
||||
useEffect(() => {
|
||||
if (item.version === WorkflowVersion.Draft)
|
||||
onClick(item)
|
||||
}, [item, onClick])
|
||||
|
||||
return (
|
||||
<div>
|
||||
<button onClick={() => onClick(item)}>{item.marked_name || item.version}</button>
|
||||
{item.version !== WorkflowVersion.Draft && (
|
||||
<button onClick={() => handleClickMenuItem(VersionHistoryContextMenuOptions.restore)}>
|
||||
{`restore-${item.id}`}
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
return <MockVersionHistoryItem />
|
||||
},
|
||||
}))
|
||||
|
||||
describe('VersionHistoryPanel', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
mockCurrentVersion = null
|
||||
})
|
||||
|
||||
describe('Version Click Behavior', () => {
|
||||
@ -134,10 +184,10 @@ describe('VersionHistoryPanel', () => {
|
||||
render(
|
||||
<VersionHistoryPanel
|
||||
latestVersionId="published-version-id"
|
||||
restoreVersionUrl={versionId => `/apps/app-1/workflows/${versionId}/restore`}
|
||||
/>,
|
||||
)
|
||||
|
||||
// Draft version auto-clicks on mount via useEffect in VersionHistoryItem
|
||||
expect(mockHandleLoadBackupDraft).toHaveBeenCalled()
|
||||
expect(mockHandleRestoreFromPublishedWorkflow).not.toHaveBeenCalled()
|
||||
})
|
||||
@ -148,17 +198,72 @@ describe('VersionHistoryPanel', () => {
|
||||
render(
|
||||
<VersionHistoryPanel
|
||||
latestVersionId="published-version-id"
|
||||
restoreVersionUrl={versionId => `/apps/app-1/workflows/${versionId}/restore`}
|
||||
/>,
|
||||
)
|
||||
|
||||
// Clear mocks after initial render (draft version auto-clicks on mount)
|
||||
vi.clearAllMocks()
|
||||
|
||||
const publishedItem = screen.getByText('v1.0')
|
||||
fireEvent.click(publishedItem)
|
||||
fireEvent.click(screen.getByText('v1.0'))
|
||||
|
||||
expect(mockHandleRestoreFromPublishedWorkflow).toHaveBeenCalled()
|
||||
expect(mockHandleLoadBackupDraft).not.toHaveBeenCalled()
|
||||
})
|
||||
})
|
||||
|
||||
it('should set current version before confirming restore from context menu', async () => {
|
||||
const { VersionHistoryPanel } = await import('../index')
|
||||
|
||||
render(
|
||||
<VersionHistoryPanel
|
||||
latestVersionId="published-version-id"
|
||||
restoreVersionUrl={versionId => `/apps/app-1/workflows/${versionId}/restore`}
|
||||
/>,
|
||||
)
|
||||
|
||||
vi.clearAllMocks()
|
||||
|
||||
fireEvent.click(screen.getByText('restore-published-version-id'))
|
||||
fireEvent.click(screen.getByText('confirm restore'))
|
||||
|
||||
await waitFor(() => {
|
||||
expect(mockSetCurrentVersion).toHaveBeenCalledWith(expect.objectContaining({
|
||||
id: 'published-version-id',
|
||||
}))
|
||||
expect(mockRestoreWorkflow).toHaveBeenCalledWith('/apps/app-1/workflows/published-version-id/restore')
|
||||
expect(mockWorkflowStoreSetState).toHaveBeenCalledWith({ isRestoring: false })
|
||||
expect(mockWorkflowStoreSetState).toHaveBeenCalledWith({ backupDraft: undefined })
|
||||
expect(mockHandleRefreshWorkflowDraft).toHaveBeenCalled()
|
||||
})
|
||||
})
|
||||
|
||||
it('should keep restore mode backup state when restore request fails', async () => {
|
||||
const { VersionHistoryPanel } = await import('../index')
|
||||
mockRestoreWorkflow.mockRejectedValueOnce(new Error('restore failed'))
|
||||
mockCurrentVersion = createVersionHistory({
|
||||
id: 'draft-version-id',
|
||||
version: WorkflowVersion.Draft,
|
||||
})
|
||||
|
||||
render(
|
||||
<VersionHistoryPanel
|
||||
latestVersionId="published-version-id"
|
||||
restoreVersionUrl={versionId => `/apps/app-1/workflows/${versionId}/restore`}
|
||||
/>,
|
||||
)
|
||||
|
||||
vi.clearAllMocks()
|
||||
|
||||
fireEvent.click(screen.getByText('restore-published-version-id'))
|
||||
fireEvent.click(screen.getByText('confirm restore'))
|
||||
|
||||
await waitFor(() => {
|
||||
expect(mockRestoreWorkflow).toHaveBeenCalledWith('/apps/app-1/workflows/published-version-id/restore')
|
||||
})
|
||||
|
||||
expect(mockWorkflowStoreSetState).not.toHaveBeenCalledWith({ isRestoring: false })
|
||||
expect(mockWorkflowStoreSetState).not.toHaveBeenCalledWith({ backupDraft: undefined })
|
||||
expect(mockSetCurrentVersion).not.toHaveBeenCalled()
|
||||
expect(mockHandleRefreshWorkflowDraft).not.toHaveBeenCalled()
|
||||
})
|
||||
})
|
||||
|
||||
@ -9,8 +9,8 @@ import VersionInfoModal from '@/app/components/app/app-publisher/version-info-mo
|
||||
import Divider from '@/app/components/base/divider'
|
||||
import { toast } from '@/app/components/base/ui/toast'
|
||||
import { useSelector as useAppContextSelector } from '@/context/app-context'
|
||||
import { useDeleteWorkflow, useInvalidAllLastRun, useResetWorkflowVersionHistory, useUpdateWorkflow, useWorkflowVersionHistory } from '@/service/use-workflow'
|
||||
import { useDSL, useNodesSyncDraft, useWorkflowRun } from '../../hooks'
|
||||
import { useDeleteWorkflow, useInvalidAllLastRun, useResetWorkflowVersionHistory, useRestoreWorkflow, useUpdateWorkflow, useWorkflowVersionHistory } from '@/service/use-workflow'
|
||||
import { useDSL, useWorkflowRefreshDraft, useWorkflowRun } from '../../hooks'
|
||||
import { useHooksStore } from '../../hooks-store'
|
||||
import { useStore, useWorkflowStore } from '../../store'
|
||||
import { VersionHistoryContextMenuOptions, WorkflowVersion, WorkflowVersionFilterOptions } from '../../types'
|
||||
@ -27,12 +27,14 @@ const INITIAL_PAGE = 1
|
||||
export type VersionHistoryPanelProps = {
|
||||
getVersionListUrl?: string
|
||||
deleteVersionUrl?: (versionId: string) => string
|
||||
restoreVersionUrl: (versionId: string) => string
|
||||
updateVersionUrl?: (versionId: string) => string
|
||||
latestVersionId?: string
|
||||
}
|
||||
export const VersionHistoryPanel = ({
|
||||
getVersionListUrl,
|
||||
deleteVersionUrl,
|
||||
restoreVersionUrl,
|
||||
updateVersionUrl,
|
||||
latestVersionId,
|
||||
}: VersionHistoryPanelProps) => {
|
||||
@ -43,8 +45,8 @@ export const VersionHistoryPanel = ({
|
||||
const [deleteConfirmOpen, setDeleteConfirmOpen] = useState(false)
|
||||
const [editModalOpen, setEditModalOpen] = useState(false)
|
||||
const workflowStore = useWorkflowStore()
|
||||
const { handleSyncWorkflowDraft } = useNodesSyncDraft()
|
||||
const { handleRestoreFromPublishedWorkflow, handleLoadBackupDraft } = useWorkflowRun()
|
||||
const { handleRefreshWorkflowDraft } = useWorkflowRefreshDraft()
|
||||
const { handleExportDSL } = useDSL()
|
||||
const setShowWorkflowVersionHistoryPanel = useStore(s => s.setShowWorkflowVersionHistoryPanel)
|
||||
const currentVersion = useStore(s => s.currentVersion)
|
||||
@ -144,32 +146,33 @@ export const VersionHistoryPanel = ({
|
||||
}, [])
|
||||
|
||||
const resetWorkflowVersionHistory = useResetWorkflowVersionHistory()
|
||||
const { mutateAsync: restoreWorkflow } = useRestoreWorkflow()
|
||||
|
||||
const handleRestore = useCallback((item: VersionHistory) => {
|
||||
const handleRestore = useCallback(async (item: VersionHistory) => {
|
||||
setShowWorkflowVersionHistoryPanel(false)
|
||||
handleRestoreFromPublishedWorkflow(item)
|
||||
workflowStore.setState({ isRestoring: false })
|
||||
workflowStore.setState({ backupDraft: undefined })
|
||||
handleSyncWorkflowDraft(true, false, {
|
||||
onSuccess: () => {
|
||||
toast.add({
|
||||
type: 'success',
|
||||
title: t('versionHistory.action.restoreSuccess', { ns: 'workflow' }),
|
||||
})
|
||||
deleteAllInspectVars()
|
||||
invalidAllLastRun()
|
||||
},
|
||||
onError: () => {
|
||||
toast.add({
|
||||
type: 'error',
|
||||
title: t('versionHistory.action.restoreFailure', { ns: 'workflow' }),
|
||||
})
|
||||
},
|
||||
onSettled: () => {
|
||||
resetWorkflowVersionHistory()
|
||||
},
|
||||
})
|
||||
}, [setShowWorkflowVersionHistoryPanel, handleRestoreFromPublishedWorkflow, workflowStore, handleSyncWorkflowDraft, deleteAllInspectVars, invalidAllLastRun, t, resetWorkflowVersionHistory])
|
||||
try {
|
||||
await restoreWorkflow(restoreVersionUrl(item.id))
|
||||
setCurrentVersion(item)
|
||||
workflowStore.setState({ isRestoring: false })
|
||||
workflowStore.setState({ backupDraft: undefined })
|
||||
handleRefreshWorkflowDraft()
|
||||
toast.add({
|
||||
type: 'success',
|
||||
title: t('versionHistory.action.restoreSuccess', { ns: 'workflow' }),
|
||||
})
|
||||
deleteAllInspectVars()
|
||||
invalidAllLastRun()
|
||||
}
|
||||
catch {
|
||||
toast.add({
|
||||
type: 'error',
|
||||
title: t('versionHistory.action.restoreFailure', { ns: 'workflow' }),
|
||||
})
|
||||
}
|
||||
finally {
|
||||
resetWorkflowVersionHistory()
|
||||
}
|
||||
}, [setShowWorkflowVersionHistoryPanel, setCurrentVersion, workflowStore, restoreWorkflow, restoreVersionUrl, handleRefreshWorkflowDraft, deleteAllInspectVars, invalidAllLastRun, t, resetWorkflowVersionHistory])
|
||||
|
||||
const { mutateAsync: deleteWorkflow } = useDeleteWorkflow()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user