chore: workflow syncing modal (#5108)
This commit is contained in:
parent
0ce97e6315
commit
95443bd551
@ -10,6 +10,7 @@ const EditingTitle = () => {
|
|||||||
const { formatTimeFromNow } = useWorkflow()
|
const { formatTimeFromNow } = useWorkflow()
|
||||||
const draftUpdatedAt = useStore(state => state.draftUpdatedAt)
|
const draftUpdatedAt = useStore(state => state.draftUpdatedAt)
|
||||||
const publishedAt = useStore(state => state.publishedAt)
|
const publishedAt = useStore(state => state.publishedAt)
|
||||||
|
const isSyncingWorkflowDraft = useStore(s => s.isSyncingWorkflowDraft)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='flex items-center h-[18px] text-xs text-gray-500'>
|
<div className='flex items-center h-[18px] text-xs text-gray-500'>
|
||||||
@ -26,6 +27,14 @@ const EditingTitle = () => {
|
|||||||
? `${t('workflow.common.published')} ${formatTimeFromNow(publishedAt)}`
|
? `${t('workflow.common.published')} ${formatTimeFromNow(publishedAt)}`
|
||||||
: t('workflow.common.unpublished')
|
: t('workflow.common.unpublished')
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
isSyncingWorkflowDraft && (
|
||||||
|
<>
|
||||||
|
<span className='flex items-center mx-1'>·</span>
|
||||||
|
{t('workflow.common.syncingData')}
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -57,11 +57,13 @@ export const useWorkflowUpdate = () => {
|
|||||||
const {
|
const {
|
||||||
appId,
|
appId,
|
||||||
setSyncWorkflowDraftHash,
|
setSyncWorkflowDraftHash,
|
||||||
|
setIsSyncingWorkflowDraft,
|
||||||
} = workflowStore.getState()
|
} = workflowStore.getState()
|
||||||
|
setIsSyncingWorkflowDraft(true)
|
||||||
fetchWorkflowDraft(`/apps/${appId}/workflows/draft`).then((response) => {
|
fetchWorkflowDraft(`/apps/${appId}/workflows/draft`).then((response) => {
|
||||||
handleUpdateWorkflowCanvas(response.graph as WorkflowDataUpdator)
|
handleUpdateWorkflowCanvas(response.graph as WorkflowDataUpdator)
|
||||||
setSyncWorkflowDraftHash(response.hash)
|
setSyncWorkflowDraftHash(response.hash)
|
||||||
})
|
}).finally(() => setIsSyncingWorkflowDraft(false))
|
||||||
}, [handleUpdateWorkflowCanvas, workflowStore])
|
}, [handleUpdateWorkflowCanvas, workflowStore])
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -55,6 +55,7 @@ import HelpLine from './help-line'
|
|||||||
import CandidateNode from './candidate-node'
|
import CandidateNode from './candidate-node'
|
||||||
import PanelContextmenu from './panel-contextmenu'
|
import PanelContextmenu from './panel-contextmenu'
|
||||||
import NodeContextmenu from './node-contextmenu'
|
import NodeContextmenu from './node-contextmenu'
|
||||||
|
import SyncingDataModal from './syncing-data-modal'
|
||||||
import {
|
import {
|
||||||
useStore,
|
useStore,
|
||||||
useWorkflowStore,
|
useWorkflowStore,
|
||||||
@ -99,7 +100,10 @@ const Workflow: FC<WorkflowProps> = memo(({
|
|||||||
const controlMode = useStore(s => s.controlMode)
|
const controlMode = useStore(s => s.controlMode)
|
||||||
const nodeAnimation = useStore(s => s.nodeAnimation)
|
const nodeAnimation = useStore(s => s.nodeAnimation)
|
||||||
const showConfirm = useStore(s => s.showConfirm)
|
const showConfirm = useStore(s => s.showConfirm)
|
||||||
const { setShowConfirm } = workflowStore.getState()
|
const {
|
||||||
|
setShowConfirm,
|
||||||
|
setControlPromptEditorRerenderKey,
|
||||||
|
} = workflowStore.getState()
|
||||||
const {
|
const {
|
||||||
handleSyncWorkflowDraft,
|
handleSyncWorkflowDraft,
|
||||||
syncWorkflowDraftWhenPageClose,
|
syncWorkflowDraftWhenPageClose,
|
||||||
@ -113,6 +117,7 @@ const Workflow: FC<WorkflowProps> = memo(({
|
|||||||
if (v.type === WORKFLOW_DATA_UPDATE) {
|
if (v.type === WORKFLOW_DATA_UPDATE) {
|
||||||
setNodes(v.payload.nodes)
|
setNodes(v.payload.nodes)
|
||||||
setEdges(v.payload.edges)
|
setEdges(v.payload.edges)
|
||||||
|
setTimeout(() => setControlPromptEditorRerenderKey(Date.now()))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -135,7 +140,7 @@ const Workflow: FC<WorkflowProps> = memo(({
|
|||||||
if (document.visibilityState === 'hidden')
|
if (document.visibilityState === 'hidden')
|
||||||
syncWorkflowDraftWhenPageClose()
|
syncWorkflowDraftWhenPageClose()
|
||||||
else if (document.visibilityState === 'visible')
|
else if (document.visibilityState === 'visible')
|
||||||
handleRefreshWorkflowDraft()
|
setTimeout(() => handleRefreshWorkflowDraft(), 500)
|
||||||
}, [syncWorkflowDraftWhenPageClose, handleRefreshWorkflowDraft])
|
}, [syncWorkflowDraftWhenPageClose, handleRefreshWorkflowDraft])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -223,6 +228,7 @@ const Workflow: FC<WorkflowProps> = memo(({
|
|||||||
`}
|
`}
|
||||||
ref={workflowContainerRef}
|
ref={workflowContainerRef}
|
||||||
>
|
>
|
||||||
|
<SyncingDataModal />
|
||||||
<CandidateNode />
|
<CandidateNode />
|
||||||
<Header />
|
<Header />
|
||||||
<Panel />
|
<Panel />
|
||||||
|
@ -27,6 +27,7 @@ import TooltipPlus from '@/app/components/base/tooltip-plus'
|
|||||||
import CodeEditor from '@/app/components/workflow/nodes/_base/components/editor/code-editor/editor-support-vars'
|
import CodeEditor from '@/app/components/workflow/nodes/_base/components/editor/code-editor/editor-support-vars'
|
||||||
import Switch from '@/app/components/base/switch'
|
import Switch from '@/app/components/base/switch'
|
||||||
import { Jinja } from '@/app/components/base/icons/src/vender/workflow'
|
import { Jinja } from '@/app/components/base/icons/src/vender/workflow'
|
||||||
|
import { useStore } from '@/app/components/workflow/store'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
className?: string
|
className?: string
|
||||||
@ -82,6 +83,7 @@ const Editor: FC<Props> = ({
|
|||||||
}) => {
|
}) => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const { eventEmitter } = useEventEmitterContextContext()
|
const { eventEmitter } = useEventEmitterContextContext()
|
||||||
|
const controlPromptEditorRerenderKey = useStore(s => s.controlPromptEditorRerenderKey)
|
||||||
|
|
||||||
const isShowHistory = !isChatModel && isChatApp
|
const isShowHistory = !isChatModel && isChatApp
|
||||||
|
|
||||||
@ -173,6 +175,7 @@ const Editor: FC<Props> = ({
|
|||||||
? (
|
? (
|
||||||
<div className={cn(isExpand ? 'grow' : 'max-h-[536px]', 'relative px-3 min-h-[56px] overflow-y-auto')}>
|
<div className={cn(isExpand ? 'grow' : 'max-h-[536px]', 'relative px-3 min-h-[56px] overflow-y-auto')}>
|
||||||
<PromptEditor
|
<PromptEditor
|
||||||
|
key={controlPromptEditorRerenderKey}
|
||||||
instanceId={instanceId}
|
instanceId={instanceId}
|
||||||
compact
|
compact
|
||||||
className='min-h-[56px]'
|
className='min-h-[56px]'
|
||||||
|
@ -125,6 +125,10 @@ type Shape = {
|
|||||||
nodeData: VariableAssignerNodeType
|
nodeData: VariableAssignerNodeType
|
||||||
}
|
}
|
||||||
setEnteringNodePayload: (enteringNodePayload?: Shape['enteringNodePayload']) => void
|
setEnteringNodePayload: (enteringNodePayload?: Shape['enteringNodePayload']) => void
|
||||||
|
isSyncingWorkflowDraft: boolean
|
||||||
|
setIsSyncingWorkflowDraft: (isSyncingWorkflowDraft: boolean) => void
|
||||||
|
controlPromptEditorRerenderKey: number
|
||||||
|
setControlPromptEditorRerenderKey: (controlPromptEditorRerenderKey: number) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
export const createWorkflowStore = () => {
|
export const createWorkflowStore = () => {
|
||||||
@ -209,6 +213,10 @@ export const createWorkflowStore = () => {
|
|||||||
setConnectingNodePayload: connectingNodePayload => set(() => ({ connectingNodePayload })),
|
setConnectingNodePayload: connectingNodePayload => set(() => ({ connectingNodePayload })),
|
||||||
enteringNodePayload: undefined,
|
enteringNodePayload: undefined,
|
||||||
setEnteringNodePayload: enteringNodePayload => set(() => ({ enteringNodePayload })),
|
setEnteringNodePayload: enteringNodePayload => set(() => ({ enteringNodePayload })),
|
||||||
|
isSyncingWorkflowDraft: false,
|
||||||
|
setIsSyncingWorkflowDraft: isSyncingWorkflowDraft => set(() => ({ isSyncingWorkflowDraft })),
|
||||||
|
controlPromptEditorRerenderKey: 0,
|
||||||
|
setControlPromptEditorRerenderKey: controlPromptEditorRerenderKey => set(() => ({ controlPromptEditorRerenderKey })),
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
15
web/app/components/workflow/syncing-data-modal.tsx
Normal file
15
web/app/components/workflow/syncing-data-modal.tsx
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
import { useStore } from './store'
|
||||||
|
|
||||||
|
const SyncingDataModal = () => {
|
||||||
|
const isSyncingWorkflowDraft = useStore(s => s.isSyncingWorkflowDraft)
|
||||||
|
|
||||||
|
if (!isSyncingWorkflowDraft)
|
||||||
|
return null
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className='absolute inset-0 z-[9999]'>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default SyncingDataModal
|
@ -67,6 +67,7 @@ const translation = {
|
|||||||
manageInTools: 'Manage in Tools',
|
manageInTools: 'Manage in Tools',
|
||||||
workflowAsToolTip: 'Tool reconfiguration is required after the workflow update.',
|
workflowAsToolTip: 'Tool reconfiguration is required after the workflow update.',
|
||||||
viewDetailInTracingPanel: 'View details',
|
viewDetailInTracingPanel: 'View details',
|
||||||
|
syncingData: 'Syncing data, just a few seconds.',
|
||||||
},
|
},
|
||||||
errorMsg: {
|
errorMsg: {
|
||||||
fieldRequired: '{{field}} is required',
|
fieldRequired: '{{field}} is required',
|
||||||
|
@ -67,6 +67,7 @@ const translation = {
|
|||||||
manageInTools: '访问工具页',
|
manageInTools: '访问工具页',
|
||||||
workflowAsToolTip: '工作流更新后需要重新配置工具参数',
|
workflowAsToolTip: '工作流更新后需要重新配置工具参数',
|
||||||
viewDetailInTracingPanel: '查看详细信息',
|
viewDetailInTracingPanel: '查看详细信息',
|
||||||
|
syncingData: '同步数据中,只需几秒钟。',
|
||||||
},
|
},
|
||||||
errorMsg: {
|
errorMsg: {
|
||||||
fieldRequired: '{{field}} 不能为空',
|
fieldRequired: '{{field}} 不能为空',
|
||||||
|
Loading…
Reference in New Issue
Block a user