From e105dc6289326e173b5be494280a97fa5d133c3b Mon Sep 17 00:00:00 2001 From: hjlarry Date: Fri, 23 Jan 2026 14:22:58 +0800 Subject: [PATCH] new restore --- .../core/collaboration-manager.ts | 66 +++++++ .../collaboration/types/collaboration.ts | 35 +++- .../workflow/header/header-in-restoring.tsx | 42 +++-- web/app/components/workflow/hooks/index.ts | 1 + .../workflow/hooks/use-leader-restore.ts | 168 ++++++++++++++++++ .../workflow/hooks/use-nodes-sync-draft.ts | 7 + web/app/components/workflow/index.tsx | 5 +- .../version-history-panel/index.spec.tsx | 4 +- .../panel/version-history-panel/index.tsx | 29 ++- web/i18n/ar-TN/workflow.json | 1 + web/i18n/de-DE/workflow.json | 1 + web/i18n/en-US/workflow.json | 1 + web/i18n/es-ES/workflow.json | 1 + web/i18n/fa-IR/workflow.json | 1 + web/i18n/fr-FR/workflow.json | 1 + web/i18n/hi-IN/workflow.json | 1 + web/i18n/id-ID/workflow.json | 1 + web/i18n/it-IT/workflow.json | 1 + web/i18n/ja-JP/workflow.json | 1 + web/i18n/ko-KR/workflow.json | 1 + web/i18n/pl-PL/workflow.json | 1 + web/i18n/pt-BR/workflow.json | 1 + web/i18n/ro-RO/workflow.json | 1 + web/i18n/ru-RU/workflow.json | 1 + web/i18n/sl-SI/workflow.json | 1 + web/i18n/th-TH/workflow.json | 1 + web/i18n/tr-TR/workflow.json | 1 + web/i18n/uk-UA/workflow.json | 1 + web/i18n/vi-VN/workflow.json | 1 + web/i18n/zh-Hans/workflow.json | 1 + web/i18n/zh-Hant/workflow.json | 1 + 31 files changed, 361 insertions(+), 18 deletions(-) create mode 100644 web/app/components/workflow/hooks/use-leader-restore.ts diff --git a/web/app/components/workflow/collaboration/core/collaboration-manager.ts b/web/app/components/workflow/collaboration/core/collaboration-manager.ts index 10333b5bc4..e6a32ee68c 100644 --- a/web/app/components/workflow/collaboration/core/collaboration-manager.ts +++ b/web/app/components/workflow/collaboration/core/collaboration-manager.ts @@ -12,6 +12,9 @@ import type { NodePanelPresenceMap, NodePanelPresenceUser, OnlineUser, + RestoreCompleteData, + RestoreIntentData, + RestoreRequestData, } from '../types/collaboration' import { cloneDeep } from 'es-toolkit/object' import { isEqual } from 'es-toolkit/predicate' @@ -658,6 +661,51 @@ export class CollaborationManager { return this.eventEmitter.on('undoRedoStateChange', callback) } + emitRestoreRequest(data: RestoreRequestData): void { + if (!this.currentAppId || !webSocketClient.isConnected(this.currentAppId)) + return + + this.sendCollaborationEvent({ + type: 'workflow_restore_request', + data: data as unknown as Record, + timestamp: Date.now(), + }) + } + + emitRestoreIntent(data: RestoreIntentData): void { + if (!this.currentAppId || !webSocketClient.isConnected(this.currentAppId)) + return + + this.sendCollaborationEvent({ + type: 'workflow_restore_intent', + data: data as unknown as Record, + timestamp: Date.now(), + }) + } + + emitRestoreComplete(data: RestoreCompleteData): void { + if (!this.currentAppId || !webSocketClient.isConnected(this.currentAppId)) + return + + this.sendCollaborationEvent({ + type: 'workflow_restore_complete', + data: data as unknown as Record, + timestamp: Date.now(), + }) + } + + onRestoreRequest(callback: (data: RestoreRequestData) => void): () => void { + return this.eventEmitter.on('restoreRequest', callback) + } + + onRestoreIntent(callback: (data: RestoreIntentData) => void): () => void { + return this.eventEmitter.on('restoreIntent', callback) + } + + onRestoreComplete(callback: (data: RestoreCompleteData) => void): () => void { + return this.eventEmitter.on('restoreComplete', callback) + } + getLeaderId(): string | null { return this.leaderId } @@ -898,6 +946,14 @@ export class CollaborationManager { }) } + refreshGraphSynchronously(): void { + const mergedNodes = this.mergeLocalNodeState(this.getNodes()) + this.eventEmitter.emit('graphImport', { + nodes: mergedNodes, + edges: this.getEdges(), + }) + } + private mergeLocalNodeState(nodes: Node[]): Node[] { const reactFlowStore = this.reactFlowStore const state = reactFlowStore?.getState() @@ -979,6 +1035,16 @@ export class CollaborationManager { if (this.isLeader) this.broadcastCurrentGraph() } + else if (update.type === 'workflow_restore_request') { + if (this.isLeader) + this.eventEmitter.emit('restoreRequest', update.data as RestoreRequestData) + } + else if (update.type === 'workflow_restore_intent') { + this.eventEmitter.emit('restoreIntent', update.data as RestoreIntentData) + } + else if (update.type === 'workflow_restore_complete') { + this.eventEmitter.emit('restoreComplete', update.data as RestoreCompleteData) + } }) socket.on('online_users', (data: { users: OnlineUser[], leader?: string }) => { diff --git a/web/app/components/workflow/collaboration/types/collaboration.ts b/web/app/components/workflow/collaboration/types/collaboration.ts index f117fc3e07..d94ad25759 100644 --- a/web/app/components/workflow/collaboration/types/collaboration.ts +++ b/web/app/components/workflow/collaboration/types/collaboration.ts @@ -1,4 +1,6 @@ -import type { Edge, Node } from '../../types' +import type { Viewport } from 'reactflow' +import type { ConversationVariable, Edge, EnvironmentVariable, Node } from '../../types' +import type { Features } from '@/app/components/base/features/types' export type OnlineUser = { user_id: string @@ -61,6 +63,9 @@ export type CollaborationEventType | 'node_panel_presence' | 'app_publish_update' | 'graph_resync_request' + | 'workflow_restore_request' + | 'workflow_restore_intent' + | 'workflow_restore_complete' export type CollaborationUpdate = { type: CollaborationEventType @@ -68,3 +73,31 @@ export type CollaborationUpdate = { data: Record timestamp: number } + +export type RestoreRequestData = { + versionId: string + versionName?: string + initiatorUserId: string + initiatorName: string + graphData: { + nodes: Node[] + edges: Edge[] + viewport?: Viewport + } + features?: Features + environmentVariables?: EnvironmentVariable[] + conversationVariables?: ConversationVariable[] +} + +export type RestoreIntentData = { + versionId: string + versionName?: string + initiatorUserId: string + initiatorName: string +} + +export type RestoreCompleteData = { + versionId: string + success: boolean + error?: string +} diff --git a/web/app/components/workflow/header/header-in-restoring.tsx b/web/app/components/workflow/header/header-in-restoring.tsx index 5b4ffe08fd..63d9f991bd 100644 --- a/web/app/components/workflow/header/header-in-restoring.tsx +++ b/web/app/components/workflow/header/header-in-restoring.tsx @@ -3,15 +3,15 @@ import { useCallback, } from 'react' import { useTranslation } from 'react-i18next' -import { useStore as useAppStore } from '@/app/components/app/store' import Button from '@/app/components/base/button' +import { useFeaturesStore } from '@/app/components/base/features/hooks' +import { useSelector as useAppContextSelector } from '@/context/app-context' import useTheme from '@/hooks/use-theme' import { useInvalidAllLastRun } from '@/service/use-workflow' import { cn } from '@/utils/classnames' import Toast from '../../base/toast' -import { collaborationManager } from '../collaboration/core/collaboration-manager' import { - useNodesSyncDraft, + useLeaderRestore, useWorkflowRun, } from '../hooks' import { useHooksStore } from '../hooks-store' @@ -33,7 +33,8 @@ const HeaderInRestoring = ({ const { t } = useTranslation() const { theme } = useTheme() const workflowStore = useWorkflowStore() - const appDetail = useAppStore.getState().appDetail + const userProfile = useAppContextSelector(s => s.userProfile) + const featuresStore = useFeaturesStore() const configsMap = useHooksStore(s => s.configsMap) const invalidAllLastRun = useInvalidAllLastRun(configsMap?.flowType, configsMap?.flowId) const { @@ -45,7 +46,7 @@ const HeaderInRestoring = ({ const { handleLoadBackupDraft, } = useWorkflowRun() - const { handleSyncWorkflowDraft } = useNodesSyncDraft() + const { requestRestore } = useLeaderRestore() const handleCancelRestore = useCallback(() => { handleLoadBackupDraft() @@ -54,18 +55,37 @@ const HeaderInRestoring = ({ }, [workflowStore, handleLoadBackupDraft, setShowWorkflowVersionHistoryPanel]) const handleRestore = useCallback(() => { + if (!currentVersion) + return + setShowWorkflowVersionHistoryPanel(false) workflowStore.setState({ isRestoring: false }) workflowStore.setState({ backupDraft: undefined }) - handleSyncWorkflowDraft(true, false, { + + const { graph } = currentVersion + const features = featuresStore?.getState().features + const environmentVariables = currentVersion.environment_variables || [] + const conversationVariables = currentVersion.conversation_variables || [] + + requestRestore({ + versionId: currentVersion.id, + versionName: currentVersion.marked_name, + initiatorUserId: userProfile.id, + initiatorName: userProfile.name, + graphData: { + nodes: graph.nodes, + edges: graph.edges, + viewport: graph.viewport, + }, + features, + environmentVariables, + conversationVariables, + }, { onSuccess: () => { Toast.notify({ type: 'success', message: t('versionHistory.action.restoreSuccess', { ns: 'workflow' }), }) - // Notify other collaboration clients about the workflow restore - if (appDetail) - collaborationManager.emitWorkflowUpdate(appDetail.id) }, onError: () => { Toast.notify({ @@ -76,10 +96,10 @@ const HeaderInRestoring = ({ onSettled: () => { onRestoreSettled?.() }, - }, true) // Enable forceUpload for restore operation + }) deleteAllInspectVars() invalidAllLastRun() - }, [setShowWorkflowVersionHistoryPanel, workflowStore, handleSyncWorkflowDraft, deleteAllInspectVars, invalidAllLastRun, t, onRestoreSettled, appDetail]) + }, [currentVersion, featuresStore, setShowWorkflowVersionHistoryPanel, workflowStore, requestRestore, userProfile, deleteAllInspectVars, invalidAllLastRun, t, onRestoreSettled]) return ( <> diff --git a/web/app/components/workflow/hooks/index.ts b/web/app/components/workflow/hooks/index.ts index fa2f1a98d4..f57a44269e 100644 --- a/web/app/components/workflow/hooks/index.ts +++ b/web/app/components/workflow/hooks/index.ts @@ -5,6 +5,7 @@ export * from './use-checklist' export * from './use-DSL' export * from './use-edges-interactions' export * from './use-inspect-vars-crud' +export * from './use-leader-restore' export * from './use-node-data-update' export * from './use-nodes-interactions' export * from './use-nodes-layout' diff --git a/web/app/components/workflow/hooks/use-leader-restore.ts b/web/app/components/workflow/hooks/use-leader-restore.ts new file mode 100644 index 0000000000..8e73bbf52c --- /dev/null +++ b/web/app/components/workflow/hooks/use-leader-restore.ts @@ -0,0 +1,168 @@ +import type { RestoreCompleteData, RestoreIntentData, RestoreRequestData } from '../collaboration/types/collaboration' +import type { SyncCallback } from './use-nodes-sync-draft' +import { useCallback, useEffect, useRef } from 'react' +import { useTranslation } from 'react-i18next' +import { useReactFlow } from 'reactflow' +import { useStore as useAppStore } from '@/app/components/app/store' +import { useFeaturesStore } from '@/app/components/base/features/hooks' +import Toast from '@/app/components/base/toast' +import { useGlobalPublicStore } from '@/context/global-public-context' +import { collaborationManager } from '../collaboration/core/collaboration-manager' +import { useWorkflowStore } from '../store' +import { useNodesSyncDraft } from './use-nodes-sync-draft' + +type RestoreCallbacks = SyncCallback + +export const usePerformRestore = () => { + const { doSyncWorkflowDraft } = useNodesSyncDraft() + const appDetail = useAppStore.getState().appDetail + const featuresStore = useFeaturesStore() + const workflowStore = useWorkflowStore() + const reactflow = useReactFlow() + + return useCallback((data: RestoreRequestData, callbacks?: RestoreCallbacks) => { + collaborationManager.emitRestoreIntent({ + versionId: data.versionId, + versionName: data.versionName, + initiatorUserId: data.initiatorUserId, + initiatorName: data.initiatorName, + }) + + if (data.features && featuresStore) { + const { setFeatures } = featuresStore.getState() + setFeatures(data.features) + } + + if (data.environmentVariables) { + workflowStore.getState().setEnvironmentVariables(data.environmentVariables) + } + + if (data.conversationVariables) { + workflowStore.getState().setConversationVariables(data.conversationVariables) + } + + const { nodes, edges, viewport } = data.graphData + const currentNodes = collaborationManager.getNodes() + const currentEdges = collaborationManager.getEdges() + + collaborationManager.setNodes(currentNodes, nodes) + collaborationManager.setEdges(currentEdges, edges) + collaborationManager.refreshGraphSynchronously() + + if (viewport) + reactflow.setViewport(viewport) + + doSyncWorkflowDraft(false, { + onSuccess: () => { + collaborationManager.emitRestoreComplete({ + versionId: data.versionId, + success: true, + }) + + if (appDetail) + collaborationManager.emitWorkflowUpdate(appDetail.id) + + callbacks?.onSuccess?.() + }, + onError: () => { + collaborationManager.emitRestoreComplete({ + versionId: data.versionId, + success: false, + error: 'Failed to sync restore to server', + }) + callbacks?.onError?.() + }, + onSettled: () => { + callbacks?.onSettled?.() + }, + }) + }, [appDetail, doSyncWorkflowDraft, featuresStore, reactflow, workflowStore]) +} + +export const useLeaderRestoreListener = () => { + const { t } = useTranslation() + const performRestore = usePerformRestore() + + useEffect(() => { + const unsubscribe = collaborationManager.onRestoreRequest((data: RestoreRequestData) => { + Toast.notify({ + type: 'info', + message: t('versionHistory.action.restoreInProgress', { + ns: 'workflow', + userName: data.initiatorName, + versionName: data.versionName || data.versionId, + }), + duration: 3000, + }) + performRestore(data) + }) + + return unsubscribe + }, [performRestore, t]) + + useEffect(() => { + const unsubscribe = collaborationManager.onRestoreIntent((data: RestoreIntentData) => { + Toast.notify({ + type: 'info', + message: t('versionHistory.action.restoreInProgress', { + ns: 'workflow', + userName: data.initiatorName, + versionName: data.versionName || data.versionId, + }), + duration: 3000, + }) + }) + + return unsubscribe + }, [t]) +} + +export const useLeaderRestore = () => { + const performRestore = usePerformRestore() + const pendingCallbacksRef = useRef<{ + versionId: string + callbacks: RestoreCallbacks | null + } | null>(null) + const isCollaborationEnabled = useGlobalPublicStore(s => s.systemFeatures.enable_collaboration_mode) + + const requestRestore = useCallback((data: RestoreRequestData, callbacks?: RestoreCallbacks) => { + if (!isCollaborationEnabled || !collaborationManager.isConnected() || collaborationManager.getIsLeader()) { + performRestore(data, callbacks) + return + } + + pendingCallbacksRef.current = { + versionId: data.versionId, + callbacks: callbacks || null, + } + collaborationManager.emitRestoreRequest(data) + }, [isCollaborationEnabled, performRestore]) + + useEffect(() => { + const unsubscribe = collaborationManager.onRestoreComplete((data: RestoreCompleteData) => { + const pending = pendingCallbacksRef.current + if (!pending || pending.versionId !== data.versionId) + return + + const callbacks = pending.callbacks + if (!callbacks) { + pendingCallbacksRef.current = null + return + } + + if (data.success) + callbacks.onSuccess?.() + else + callbacks.onError?.() + + callbacks.onSettled?.() + pendingCallbacksRef.current = null + }) + + return unsubscribe + }, []) + + return { + requestRestore, + } +} diff --git a/web/app/components/workflow/hooks/use-nodes-sync-draft.ts b/web/app/components/workflow/hooks/use-nodes-sync-draft.ts index 31fad3bdf4..4ac4d3f7c4 100644 --- a/web/app/components/workflow/hooks/use-nodes-sync-draft.ts +++ b/web/app/components/workflow/hooks/use-nodes-sync-draft.ts @@ -1,5 +1,6 @@ import { useCallback } from 'react' import { useHooksStore } from '@/app/components/workflow/hooks-store' +import { collaborationManager } from '../collaboration/core/collaboration-manager' import { useStore } from '../store' import { useNodesReadOnly } from './use-workflow' @@ -28,6 +29,12 @@ export const useNodesSyncDraft = () => { if (getNodesReadOnly()) return + if (collaborationManager.isConnected() && !collaborationManager.getIsLeader()) { + if (sync) + collaborationManager.emitSyncRequest() + return + } + if (sync) doSyncWorkflowDraft(notRefreshWhenSyncError, callback, forceUpload) else diff --git a/web/app/components/workflow/index.tsx b/web/app/components/workflow/index.tsx index 4a98523923..c8d5f63d3a 100644 --- a/web/app/components/workflow/index.tsx +++ b/web/app/components/workflow/index.tsx @@ -68,6 +68,7 @@ import DatasetsDetailProvider from './datasets-detail-store/provider' import HelpLine from './help-line' import { useEdgesInteractions, + useLeaderRestoreListener, useNodesInteractions, useNodesReadOnly, useNodesSyncDraft, @@ -333,7 +334,7 @@ export const Workflow: FC = memo(({ else if (document.visibilityState === 'visible') setTimeout(() => handleRefreshWorkflowDraft(), 500) - }, [syncWorkflowDraftWhenPageClose, handleRefreshWorkflowDraft, workflowStore]) + }, [syncWorkflowDraftWhenPageClose, handleRefreshWorkflowDraft]) // Also add beforeunload handler as additional safety net for tab close const handleBeforeUnload = useCallback(() => { @@ -478,6 +479,8 @@ export const Workflow: FC = memo(({ // Initialize workflow node search functionality useWorkflowSearch() + useLeaderRestoreListener() + // Set up scroll to node event listener using the utility function useEffect(() => { return setupScrollToNodeListener(nodes, reactflow) diff --git a/web/app/components/workflow/panel/version-history-panel/index.spec.tsx b/web/app/components/workflow/panel/version-history-panel/index.spec.tsx index 1765459bcb..62f45adc61 100644 --- a/web/app/components/workflow/panel/version-history-panel/index.spec.tsx +++ b/web/app/components/workflow/panel/version-history-panel/index.spec.tsx @@ -71,11 +71,13 @@ vi.mock('@/service/use-workflow', () => ({ vi.mock('../../hooks', () => ({ useDSL: () => ({ handleExportDSL: vi.fn() }), - useNodesSyncDraft: () => ({ handleSyncWorkflowDraft: vi.fn() }), useWorkflowRun: () => ({ handleRestoreFromPublishedWorkflow: mockHandleRestoreFromPublishedWorkflow, handleLoadBackupDraft: mockHandleLoadBackupDraft, }), + useLeaderRestore: () => ({ + requestRestore: vi.fn(), + }), })) vi.mock('../../hooks-store', () => ({ diff --git a/web/app/components/workflow/panel/version-history-panel/index.tsx b/web/app/components/workflow/panel/version-history-panel/index.tsx index 0ad3ef0549..04cfc4c3b8 100644 --- a/web/app/components/workflow/panel/version-history-panel/index.tsx +++ b/web/app/components/workflow/panel/version-history-panel/index.tsx @@ -7,10 +7,11 @@ import { useCallback, useState } from 'react' import { useTranslation } from 'react-i18next' import VersionInfoModal from '@/app/components/app/app-publisher/version-info-modal' import Divider from '@/app/components/base/divider' +import { useFeaturesStore } from '@/app/components/base/features/hooks' import Toast from '@/app/components/base/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 { useDSL, useLeaderRestore, useWorkflowRun } from '../../hooks' import { useHooksStore } from '../../hooks-store' import { useStore, useWorkflowStore } from '../../store' import { VersionHistoryContextMenuOptions, WorkflowVersion, WorkflowVersionFilterOptions } from '../../types' @@ -43,8 +44,9 @@ export const VersionHistoryPanel = ({ const [deleteConfirmOpen, setDeleteConfirmOpen] = useState(false) const [editModalOpen, setEditModalOpen] = useState(false) const workflowStore = useWorkflowStore() - const { handleSyncWorkflowDraft } = useNodesSyncDraft() const { handleRestoreFromPublishedWorkflow, handleLoadBackupDraft } = useWorkflowRun() + const { requestRestore } = useLeaderRestore() + const featuresStore = useFeaturesStore() const { handleExportDSL } = useDSL() const setShowWorkflowVersionHistoryPanel = useStore(s => s.setShowWorkflowVersionHistoryPanel) const currentVersion = useStore(s => s.currentVersion) @@ -150,7 +152,26 @@ export const VersionHistoryPanel = ({ handleRestoreFromPublishedWorkflow(item) workflowStore.setState({ isRestoring: false }) workflowStore.setState({ backupDraft: undefined }) - handleSyncWorkflowDraft(true, false, { + + const { graph } = item + const features = featuresStore?.getState().features + const environmentVariables = item.environment_variables || [] + const conversationVariables = item.conversation_variables || [] + + requestRestore({ + versionId: item.id, + versionName: item.marked_name, + initiatorUserId: userProfile.id, + initiatorName: userProfile.name, + graphData: { + nodes: graph.nodes, + edges: graph.edges, + viewport: graph.viewport, + }, + features, + environmentVariables, + conversationVariables, + }, { onSuccess: () => { Toast.notify({ type: 'success', @@ -169,7 +190,7 @@ export const VersionHistoryPanel = ({ resetWorkflowVersionHistory() }, }) - }, [setShowWorkflowVersionHistoryPanel, handleRestoreFromPublishedWorkflow, workflowStore, handleSyncWorkflowDraft, deleteAllInspectVars, invalidAllLastRun, t, resetWorkflowVersionHistory]) + }, [setShowWorkflowVersionHistoryPanel, handleRestoreFromPublishedWorkflow, workflowStore, featuresStore, requestRestore, userProfile, deleteAllInspectVars, invalidAllLastRun, t, resetWorkflowVersionHistory]) const { mutateAsync: deleteWorkflow } = useDeleteWorkflow() diff --git a/web/i18n/ar-TN/workflow.json b/web/i18n/ar-TN/workflow.json index 1d2e20a006..fc1832a528 100644 --- a/web/i18n/ar-TN/workflow.json +++ b/web/i18n/ar-TN/workflow.json @@ -1050,6 +1050,7 @@ "versionHistory.action.deleteFailure": "فشل حذف الإصدار", "versionHistory.action.deleteSuccess": "تم حذف الإصدار", "versionHistory.action.restoreFailure": "فشل استعادة الإصدار", + "versionHistory.action.restoreInProgress": "{{userName}} is restoring to version {{versionName}}...", "versionHistory.action.restoreSuccess": "تم استعادة الإصدار", "versionHistory.action.updateFailure": "فشل تحديث الإصدار", "versionHistory.action.updateSuccess": "تم تحديث الإصدار", diff --git a/web/i18n/de-DE/workflow.json b/web/i18n/de-DE/workflow.json index 0289bc7b0d..eca5f4d9e8 100644 --- a/web/i18n/de-DE/workflow.json +++ b/web/i18n/de-DE/workflow.json @@ -1050,6 +1050,7 @@ "versionHistory.action.deleteFailure": "Version löschen fehlgeschlagen", "versionHistory.action.deleteSuccess": "Version gelöscht", "versionHistory.action.restoreFailure": "Wiederherstellung der Version fehlgeschlagen", + "versionHistory.action.restoreInProgress": "{{userName}} is restoring to version {{versionName}}...", "versionHistory.action.restoreSuccess": "Version wiederhergestellt", "versionHistory.action.updateFailure": "Aktualisierung der Version fehlgeschlagen", "versionHistory.action.updateSuccess": "Version aktualisiert", diff --git a/web/i18n/en-US/workflow.json b/web/i18n/en-US/workflow.json index cbed37392a..d0fe8f666c 100644 --- a/web/i18n/en-US/workflow.json +++ b/web/i18n/en-US/workflow.json @@ -1050,6 +1050,7 @@ "versionHistory.action.deleteFailure": "Failed to delete version", "versionHistory.action.deleteSuccess": "Version deleted", "versionHistory.action.restoreFailure": "Failed to restore version", + "versionHistory.action.restoreInProgress": "{{userName}} is restoring to version {{versionName}}...", "versionHistory.action.restoreSuccess": "Version restored", "versionHistory.action.updateFailure": "Failed to update version", "versionHistory.action.updateSuccess": "Version updated", diff --git a/web/i18n/es-ES/workflow.json b/web/i18n/es-ES/workflow.json index 2bc67a39af..e57a5afb3d 100644 --- a/web/i18n/es-ES/workflow.json +++ b/web/i18n/es-ES/workflow.json @@ -1050,6 +1050,7 @@ "versionHistory.action.deleteFailure": "Error al eliminar la versión", "versionHistory.action.deleteSuccess": "Versión eliminada", "versionHistory.action.restoreFailure": "Error al restaurar la versión", + "versionHistory.action.restoreInProgress": "{{userName}} is restoring to version {{versionName}}...", "versionHistory.action.restoreSuccess": "Versión restaurada", "versionHistory.action.updateFailure": "Error al actualizar la versión", "versionHistory.action.updateSuccess": "Versión actualizada", diff --git a/web/i18n/fa-IR/workflow.json b/web/i18n/fa-IR/workflow.json index 3f4f222d17..35adc60583 100644 --- a/web/i18n/fa-IR/workflow.json +++ b/web/i18n/fa-IR/workflow.json @@ -1050,6 +1050,7 @@ "versionHistory.action.deleteFailure": "حذف نسخه موفق نبود", "versionHistory.action.deleteSuccess": "نسخه حذف شد", "versionHistory.action.restoreFailure": "بازگرداندن نسخه ناموفق بود", + "versionHistory.action.restoreInProgress": "{{userName}} is restoring to version {{versionName}}...", "versionHistory.action.restoreSuccess": "نسخه بازگردانی شده", "versionHistory.action.updateFailure": "به‌روزرسانی نسخه ناموفق بود", "versionHistory.action.updateSuccess": "نسخه به‌روزرسانی شد", diff --git a/web/i18n/fr-FR/workflow.json b/web/i18n/fr-FR/workflow.json index c3ae53c5bc..2d5fec18dc 100644 --- a/web/i18n/fr-FR/workflow.json +++ b/web/i18n/fr-FR/workflow.json @@ -1050,6 +1050,7 @@ "versionHistory.action.deleteFailure": "Échec de la suppression de la version", "versionHistory.action.deleteSuccess": "Version supprimée", "versionHistory.action.restoreFailure": "Échec de la restauration de la version", + "versionHistory.action.restoreInProgress": "{{userName}} is restoring to version {{versionName}}...", "versionHistory.action.restoreSuccess": "Version restaurée", "versionHistory.action.updateFailure": "Échec de la mise à jour de la version", "versionHistory.action.updateSuccess": "Version mise à jour", diff --git a/web/i18n/hi-IN/workflow.json b/web/i18n/hi-IN/workflow.json index 99d9d966bd..3e8bbba292 100644 --- a/web/i18n/hi-IN/workflow.json +++ b/web/i18n/hi-IN/workflow.json @@ -1050,6 +1050,7 @@ "versionHistory.action.deleteFailure": "संस्करण को हटाने में विफल", "versionHistory.action.deleteSuccess": "संस्करण हटाया गया", "versionHistory.action.restoreFailure": "संस्करण को पुनर्स्थापित करने में विफल", + "versionHistory.action.restoreInProgress": "{{userName}} is restoring to version {{versionName}}...", "versionHistory.action.restoreSuccess": "संस्करण पुनर्स्थापित किया गया", "versionHistory.action.updateFailure": "संस्करण अपडेट करने में विफल", "versionHistory.action.updateSuccess": "संस्करण अपडेट किया गया", diff --git a/web/i18n/id-ID/workflow.json b/web/i18n/id-ID/workflow.json index fe67017d62..24b4050dad 100644 --- a/web/i18n/id-ID/workflow.json +++ b/web/i18n/id-ID/workflow.json @@ -1050,6 +1050,7 @@ "versionHistory.action.deleteFailure": "Gagal menghapus versi", "versionHistory.action.deleteSuccess": "Versi dihapus", "versionHistory.action.restoreFailure": "Gagal memulihkan versi", + "versionHistory.action.restoreInProgress": "{{userName}} is restoring to version {{versionName}}...", "versionHistory.action.restoreSuccess": "Versi dipulihkan", "versionHistory.action.updateFailure": "Gagal memperbarui versi", "versionHistory.action.updateSuccess": "Versi diperbarui", diff --git a/web/i18n/it-IT/workflow.json b/web/i18n/it-IT/workflow.json index 93e335ea9a..fa94852d04 100644 --- a/web/i18n/it-IT/workflow.json +++ b/web/i18n/it-IT/workflow.json @@ -1050,6 +1050,7 @@ "versionHistory.action.deleteFailure": "Impossibile eliminare la versione", "versionHistory.action.deleteSuccess": "Versione eliminata", "versionHistory.action.restoreFailure": "Impossibile ripristinare la versione", + "versionHistory.action.restoreInProgress": "{{userName}} is restoring to version {{versionName}}...", "versionHistory.action.restoreSuccess": "Versione ripristinata", "versionHistory.action.updateFailure": "Impossibile aggiornare la versione", "versionHistory.action.updateSuccess": "Versione aggiornata", diff --git a/web/i18n/ja-JP/workflow.json b/web/i18n/ja-JP/workflow.json index e1f6cd6598..2afef0f98f 100644 --- a/web/i18n/ja-JP/workflow.json +++ b/web/i18n/ja-JP/workflow.json @@ -1050,6 +1050,7 @@ "versionHistory.action.deleteFailure": "削除に失敗しました", "versionHistory.action.deleteSuccess": "削除が完了しました", "versionHistory.action.restoreFailure": "復元に失敗しました", + "versionHistory.action.restoreInProgress": "{{userName}} is restoring to version {{versionName}}...", "versionHistory.action.restoreSuccess": "復元が完了しました", "versionHistory.action.updateFailure": "更新に失敗しました", "versionHistory.action.updateSuccess": "更新が完了しました", diff --git a/web/i18n/ko-KR/workflow.json b/web/i18n/ko-KR/workflow.json index a8b9e1f30b..d163858dab 100644 --- a/web/i18n/ko-KR/workflow.json +++ b/web/i18n/ko-KR/workflow.json @@ -1050,6 +1050,7 @@ "versionHistory.action.deleteFailure": "버전을 삭제하지 못했습니다.", "versionHistory.action.deleteSuccess": "버전 삭제됨", "versionHistory.action.restoreFailure": "버전을 복원하지 못했습니다.", + "versionHistory.action.restoreInProgress": "{{userName}} is restoring to version {{versionName}}...", "versionHistory.action.restoreSuccess": "복원된 버전", "versionHistory.action.updateFailure": "버전 업데이트에 실패했습니다.", "versionHistory.action.updateSuccess": "버전이 업데이트되었습니다.", diff --git a/web/i18n/pl-PL/workflow.json b/web/i18n/pl-PL/workflow.json index 783bc1bbaa..9651d6388d 100644 --- a/web/i18n/pl-PL/workflow.json +++ b/web/i18n/pl-PL/workflow.json @@ -1050,6 +1050,7 @@ "versionHistory.action.deleteFailure": "Nie udało się usunąć wersji", "versionHistory.action.deleteSuccess": "Wersja usunięta", "versionHistory.action.restoreFailure": "Nie udało się przywrócić wersji", + "versionHistory.action.restoreInProgress": "{{userName}} is restoring to version {{versionName}}...", "versionHistory.action.restoreSuccess": "Wersja przywrócona", "versionHistory.action.updateFailure": "Nie udało się zaktualizować wersji", "versionHistory.action.updateSuccess": "Wersja zaktualizowana", diff --git a/web/i18n/pt-BR/workflow.json b/web/i18n/pt-BR/workflow.json index eff78be5cd..9ceef58ed9 100644 --- a/web/i18n/pt-BR/workflow.json +++ b/web/i18n/pt-BR/workflow.json @@ -1050,6 +1050,7 @@ "versionHistory.action.deleteFailure": "Falha ao deletar versão", "versionHistory.action.deleteSuccess": "Versão excluída", "versionHistory.action.restoreFailure": "Falha ao restaurar versão", + "versionHistory.action.restoreInProgress": "{{userName}} is restoring to version {{versionName}}...", "versionHistory.action.restoreSuccess": "Versão restaurada", "versionHistory.action.updateFailure": "Falha ao atualizar a versão", "versionHistory.action.updateSuccess": "Versão atualizada", diff --git a/web/i18n/ro-RO/workflow.json b/web/i18n/ro-RO/workflow.json index 7cbe6f66ac..baa403b883 100644 --- a/web/i18n/ro-RO/workflow.json +++ b/web/i18n/ro-RO/workflow.json @@ -1050,6 +1050,7 @@ "versionHistory.action.deleteFailure": "Ștergerea versiunii a eșuat", "versionHistory.action.deleteSuccess": "Versiune ștearsă", "versionHistory.action.restoreFailure": "Restaurarea versiunii a eșuat", + "versionHistory.action.restoreInProgress": "{{userName}} is restoring to version {{versionName}}...", "versionHistory.action.restoreSuccess": "Versiune restaurată", "versionHistory.action.updateFailure": "Actualizarea versiunii a eșuat", "versionHistory.action.updateSuccess": "Versiune actualizată", diff --git a/web/i18n/ru-RU/workflow.json b/web/i18n/ru-RU/workflow.json index cc7827b370..f7884a47e2 100644 --- a/web/i18n/ru-RU/workflow.json +++ b/web/i18n/ru-RU/workflow.json @@ -1050,6 +1050,7 @@ "versionHistory.action.deleteFailure": "Не удалось удалить версию", "versionHistory.action.deleteSuccess": "Версия удалена", "versionHistory.action.restoreFailure": "Не удалось восстановить версию", + "versionHistory.action.restoreInProgress": "{{userName}} is restoring to version {{versionName}}...", "versionHistory.action.restoreSuccess": "Версия восстановлена", "versionHistory.action.updateFailure": "Не удалось обновить версию", "versionHistory.action.updateSuccess": "Версия обновлена", diff --git a/web/i18n/sl-SI/workflow.json b/web/i18n/sl-SI/workflow.json index e25e7bbbc4..156ccfae21 100644 --- a/web/i18n/sl-SI/workflow.json +++ b/web/i18n/sl-SI/workflow.json @@ -1050,6 +1050,7 @@ "versionHistory.action.deleteFailure": "Brisanje različice ni uspelo", "versionHistory.action.deleteSuccess": "Različica izbrisana", "versionHistory.action.restoreFailure": "Obnavljanje različice ni uspelo", + "versionHistory.action.restoreInProgress": "{{userName}} is restoring to version {{versionName}}...", "versionHistory.action.restoreSuccess": "Obnovljena različica", "versionHistory.action.updateFailure": "Posodobitev različice ni uspela", "versionHistory.action.updateSuccess": "Različica posodobljena", diff --git a/web/i18n/th-TH/workflow.json b/web/i18n/th-TH/workflow.json index dd4e2750f8..24d65e5081 100644 --- a/web/i18n/th-TH/workflow.json +++ b/web/i18n/th-TH/workflow.json @@ -1050,6 +1050,7 @@ "versionHistory.action.deleteFailure": "ลบเวอร์ชันไม่สำเร็จ", "versionHistory.action.deleteSuccess": "เวอร์ชันถูกลบ", "versionHistory.action.restoreFailure": "ไม่สามารถกู้คืนเวอร์ชันได้", + "versionHistory.action.restoreInProgress": "{{userName}} is restoring to version {{versionName}}...", "versionHistory.action.restoreSuccess": "เวอร์ชันที่กู้คืน", "versionHistory.action.updateFailure": "ไม่สามารถอัปเดตเวอร์ชันได้", "versionHistory.action.updateSuccess": "อัปเดตเวอร์ชัน", diff --git a/web/i18n/tr-TR/workflow.json b/web/i18n/tr-TR/workflow.json index 371fab87e3..6ffa9e419b 100644 --- a/web/i18n/tr-TR/workflow.json +++ b/web/i18n/tr-TR/workflow.json @@ -1050,6 +1050,7 @@ "versionHistory.action.deleteFailure": "Versiyonu silme işlemi başarısız oldu", "versionHistory.action.deleteSuccess": "Sürüm silindi", "versionHistory.action.restoreFailure": "Sürümü geri yüklemekte başarısız olundu", + "versionHistory.action.restoreInProgress": "{{userName}} is restoring to version {{versionName}}...", "versionHistory.action.restoreSuccess": "Sürüm geri yüklendi", "versionHistory.action.updateFailure": "Sürüm güncellenemedi", "versionHistory.action.updateSuccess": "Sürüm güncellendi", diff --git a/web/i18n/uk-UA/workflow.json b/web/i18n/uk-UA/workflow.json index f738318546..bf2a7bb8c1 100644 --- a/web/i18n/uk-UA/workflow.json +++ b/web/i18n/uk-UA/workflow.json @@ -1050,6 +1050,7 @@ "versionHistory.action.deleteFailure": "Не вдалося видалити версію", "versionHistory.action.deleteSuccess": "Версія видалена", "versionHistory.action.restoreFailure": "Не вдалося відновити версію", + "versionHistory.action.restoreInProgress": "{{userName}} is restoring to version {{versionName}}...", "versionHistory.action.restoreSuccess": "Версія відновлена", "versionHistory.action.updateFailure": "Не вдалося оновити версію", "versionHistory.action.updateSuccess": "Версія оновлена", diff --git a/web/i18n/vi-VN/workflow.json b/web/i18n/vi-VN/workflow.json index 54625e50f8..3952e4b4a8 100644 --- a/web/i18n/vi-VN/workflow.json +++ b/web/i18n/vi-VN/workflow.json @@ -1050,6 +1050,7 @@ "versionHistory.action.deleteFailure": "Xóa phiên bản thất bại", "versionHistory.action.deleteSuccess": "Phiên bản đã bị xóa", "versionHistory.action.restoreFailure": "Không thể khôi phục phiên bản", + "versionHistory.action.restoreInProgress": "{{userName}} is restoring to version {{versionName}}...", "versionHistory.action.restoreSuccess": "Phiên bản đã được khôi phục", "versionHistory.action.updateFailure": "Cập nhật phiên bản không thành công", "versionHistory.action.updateSuccess": "Phiên bản đã được cập nhật", diff --git a/web/i18n/zh-Hans/workflow.json b/web/i18n/zh-Hans/workflow.json index e76b73150e..a2cf6aa86b 100644 --- a/web/i18n/zh-Hans/workflow.json +++ b/web/i18n/zh-Hans/workflow.json @@ -1050,6 +1050,7 @@ "versionHistory.action.deleteFailure": "删除失败", "versionHistory.action.deleteSuccess": "版本已删除", "versionHistory.action.restoreFailure": "回滚失败", + "versionHistory.action.restoreInProgress": "{{userName}} 正在回滚到版本 {{versionName}}...", "versionHistory.action.restoreSuccess": "回滚成功", "versionHistory.action.updateFailure": "更新失败", "versionHistory.action.updateSuccess": "版本信息已更新", diff --git a/web/i18n/zh-Hant/workflow.json b/web/i18n/zh-Hant/workflow.json index f0b7ddd910..1b394d7bfd 100644 --- a/web/i18n/zh-Hant/workflow.json +++ b/web/i18n/zh-Hant/workflow.json @@ -1050,6 +1050,7 @@ "versionHistory.action.deleteFailure": "無法刪除版本", "versionHistory.action.deleteSuccess": "版本已刪除", "versionHistory.action.restoreFailure": "無法恢復版本", + "versionHistory.action.restoreInProgress": "{{userName}} is restoring to version {{versionName}}...", "versionHistory.action.restoreSuccess": "恢復版本", "versionHistory.action.updateFailure": "更新版本失敗", "versionHistory.action.updateSuccess": "版本已更新",