mirror of https://github.com/langgenius/dify.git
refactor: separate loading states for comment operations
Separate loading states to distinguish between different operations: - activeCommentDetailLoading: loading comment details, delete/resolve operations - replySubmitting: sending new replies - replyUpdating: editing existing replies Changes: - Add replySubmitting and replyUpdating states to comment store - Restore full-screen loading overlay for comment detail loading - Use inline spinner (RiLoader2Line) in send/save buttons for reply operations - Update loading state usage in handleCommentReply and handleCommentReplyUpdate - Pass separated loading states from workflow index to CommentThread component Benefits: - UI clarity: different loading states have appropriate visual feedback - Better UX: users can still navigate while sending replies - Clear separation of concerns: each operation has its own loading state
This commit is contained in:
parent
d986659add
commit
9d93fda471
|
|
@ -18,6 +18,8 @@ import { getUserColor } from '@/app/components/workflow/collaboration/utils/user
|
|||
type CommentThreadProps = {
|
||||
comment: WorkflowCommentDetail
|
||||
loading?: boolean
|
||||
replySubmitting?: boolean
|
||||
replyUpdating?: boolean
|
||||
onClose: () => void
|
||||
onDelete?: () => void
|
||||
onResolve?: () => void
|
||||
|
|
@ -135,6 +137,8 @@ const ThreadMessage: FC<{
|
|||
export const CommentThread: FC<CommentThreadProps> = memo(({
|
||||
comment,
|
||||
loading = false,
|
||||
replySubmitting = false,
|
||||
replyUpdating = false,
|
||||
onClose,
|
||||
onDelete,
|
||||
onResolve,
|
||||
|
|
@ -159,7 +163,7 @@ export const CommentThread: FC<CommentThreadProps> = memo(({
|
|||
}, [comment.id])
|
||||
|
||||
const handleReplySubmit = useCallback(async (content: string, mentionedUserIds: string[]) => {
|
||||
if (!onReply || loading) return
|
||||
if (!onReply || replySubmitting) return
|
||||
|
||||
setReplyContent('')
|
||||
|
||||
|
|
@ -170,7 +174,7 @@ export const CommentThread: FC<CommentThreadProps> = memo(({
|
|||
console.error('Failed to send reply', error)
|
||||
setReplyContent(content)
|
||||
}
|
||||
}, [onReply, loading])
|
||||
}, [onReply, replySubmitting])
|
||||
|
||||
const screenPosition = useMemo(() => {
|
||||
return flowToScreenPosition({
|
||||
|
|
@ -398,7 +402,7 @@ export const CommentThread: FC<CommentThreadProps> = memo(({
|
|||
onCancel={handleCancelEdit}
|
||||
placeholder={t('workflow.comments.placeholder.editReply')}
|
||||
disabled={loading}
|
||||
loading={loading}
|
||||
loading={replyUpdating}
|
||||
isEditing={true}
|
||||
className="system-sm-regular"
|
||||
autoFocus
|
||||
|
|
@ -420,6 +424,11 @@ export const CommentThread: FC<CommentThreadProps> = memo(({
|
|||
</div>
|
||||
)}
|
||||
</div>
|
||||
{loading && (
|
||||
<div className='bg-components-panel-bg/70 absolute inset-0 z-30 flex items-center justify-center text-sm text-text-tertiary'>
|
||||
{t('workflow.comments.loading')}
|
||||
</div>
|
||||
)}
|
||||
{onReply && (
|
||||
<div className='border-t border-components-panel-border px-4 py-3'>
|
||||
<div className='flex items-center gap-3'>
|
||||
|
|
@ -436,7 +445,7 @@ export const CommentThread: FC<CommentThreadProps> = memo(({
|
|||
onSubmit={handleReplySubmit}
|
||||
placeholder={t('workflow.comments.placeholder.reply')}
|
||||
disabled={loading}
|
||||
loading={loading}
|
||||
loading={replySubmitting}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -25,6 +25,10 @@ export const useWorkflowComment = () => {
|
|||
const setActiveComment = useStore(s => s.setActiveCommentDetail)
|
||||
const activeCommentLoading = useStore(s => s.activeCommentDetailLoading)
|
||||
const setActiveCommentLoading = useStore(s => s.setActiveCommentDetailLoading)
|
||||
const replySubmitting = useStore(s => s.replySubmitting)
|
||||
const setReplySubmitting = useStore(s => s.setReplySubmitting)
|
||||
const replyUpdating = useStore(s => s.replyUpdating)
|
||||
const setReplyUpdating = useStore(s => s.setReplyUpdating)
|
||||
const commentDetailCache = useStore(s => s.commentDetailCache)
|
||||
const setCommentDetailCache = useStore(s => s.setCommentDetailCache)
|
||||
const commentDetailCacheRef = useRef<Record<string, WorkflowCommentDetail>>(commentDetailCache)
|
||||
|
|
@ -302,7 +306,7 @@ export const useWorkflowComment = () => {
|
|||
const trimmed = content.trim()
|
||||
if (!trimmed) return
|
||||
|
||||
setActiveCommentLoading(true)
|
||||
setReplySubmitting(true)
|
||||
try {
|
||||
await createWorkflowCommentReply(appId, commentId, { content: trimmed, mentioned_user_ids: mentionedUserIds })
|
||||
|
||||
|
|
@ -315,16 +319,16 @@ export const useWorkflowComment = () => {
|
|||
console.error('Failed to create reply:', error)
|
||||
}
|
||||
finally {
|
||||
setActiveCommentLoading(false)
|
||||
setReplySubmitting(false)
|
||||
}
|
||||
}, [appId, loadComments, refreshActiveComment, setActiveCommentLoading])
|
||||
}, [appId, loadComments, refreshActiveComment, setReplySubmitting])
|
||||
|
||||
const handleCommentReplyUpdate = useCallback(async (commentId: string, replyId: string, content: string, mentionedUserIds: string[] = []) => {
|
||||
if (!appId) return
|
||||
const trimmed = content.trim()
|
||||
if (!trimmed) return
|
||||
|
||||
setActiveCommentLoading(true)
|
||||
setReplyUpdating(true)
|
||||
try {
|
||||
await updateWorkflowCommentReply(appId, commentId, replyId, { content: trimmed, mentioned_user_ids: mentionedUserIds })
|
||||
|
||||
|
|
@ -337,9 +341,9 @@ export const useWorkflowComment = () => {
|
|||
console.error('Failed to update reply:', error)
|
||||
}
|
||||
finally {
|
||||
setActiveCommentLoading(false)
|
||||
setReplyUpdating(false)
|
||||
}
|
||||
}, [appId, loadComments, refreshActiveComment, setActiveCommentLoading])
|
||||
}, [appId, loadComments, refreshActiveComment, setReplyUpdating])
|
||||
|
||||
const handleCommentReplyDelete = useCallback(async (commentId: string, replyId: string) => {
|
||||
if (!appId) return
|
||||
|
|
@ -394,6 +398,8 @@ export const useWorkflowComment = () => {
|
|||
pendingComment,
|
||||
activeComment,
|
||||
activeCommentLoading,
|
||||
replySubmitting,
|
||||
replyUpdating,
|
||||
handleCommentSubmit,
|
||||
handleCommentCancel,
|
||||
handleCommentIconClick,
|
||||
|
|
|
|||
|
|
@ -188,6 +188,8 @@ export const Workflow: FC<WorkflowProps> = memo(({
|
|||
pendingComment,
|
||||
activeComment,
|
||||
activeCommentLoading,
|
||||
replySubmitting,
|
||||
replyUpdating,
|
||||
handleCommentSubmit,
|
||||
handleCommentCancel,
|
||||
handleCommentIconClick,
|
||||
|
|
@ -468,6 +470,8 @@ export const Workflow: FC<WorkflowProps> = memo(({
|
|||
key={`${comment.id}-thread`}
|
||||
comment={activeComment}
|
||||
loading={activeCommentLoading}
|
||||
replySubmitting={replySubmitting}
|
||||
replyUpdating={replyUpdating}
|
||||
onClose={handleActiveCommentClose}
|
||||
onResolve={() => handleCommentResolve(comment.id)}
|
||||
onDelete={() => handleCommentDeleteClick(comment.id)}
|
||||
|
|
|
|||
|
|
@ -10,6 +10,10 @@ export type CommentSliceShape = {
|
|||
setActiveCommentDetail: (comment: WorkflowCommentDetail | null) => void
|
||||
activeCommentDetailLoading: boolean
|
||||
setActiveCommentDetailLoading: (loading: boolean) => void
|
||||
replySubmitting: boolean
|
||||
setReplySubmitting: (loading: boolean) => void
|
||||
replyUpdating: boolean
|
||||
setReplyUpdating: (loading: boolean) => void
|
||||
commentDetailCache: Record<string, WorkflowCommentDetail>
|
||||
setCommentDetailCache: (cache: Record<string, WorkflowCommentDetail>) => void
|
||||
mentionableUsersCache: Record<string, UserProfile[]>
|
||||
|
|
@ -27,6 +31,10 @@ export const createCommentSlice: StateCreator<CommentSliceShape> = set => ({
|
|||
setActiveCommentDetail: activeCommentDetail => set({ activeCommentDetail }),
|
||||
activeCommentDetailLoading: false,
|
||||
setActiveCommentDetailLoading: activeCommentDetailLoading => set({ activeCommentDetailLoading }),
|
||||
replySubmitting: false,
|
||||
setReplySubmitting: replySubmitting => set({ replySubmitting }),
|
||||
replyUpdating: false,
|
||||
setReplyUpdating: replyUpdating => set({ replyUpdating }),
|
||||
commentDetailCache: {},
|
||||
setCommentDetailCache: commentDetailCache => set({ commentDetailCache }),
|
||||
mentionableUsersCache: {},
|
||||
|
|
|
|||
Loading…
Reference in New Issue