From 9d93fda471435a5e41214f1290d0dc040c26afa7 Mon Sep 17 00:00:00 2001 From: lyzno1 Date: Sat, 11 Oct 2025 14:34:35 +0800 Subject: [PATCH] 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 --- web/app/components/workflow/comment/thread.tsx | 17 +++++++++++++---- .../workflow/hooks/use-workflow-comment.ts | 18 ++++++++++++------ web/app/components/workflow/index.tsx | 4 ++++ .../workflow/store/workflow/comment-slice.ts | 8 ++++++++ 4 files changed, 37 insertions(+), 10 deletions(-) diff --git a/web/app/components/workflow/comment/thread.tsx b/web/app/components/workflow/comment/thread.tsx index 61d783c2fd..9094e554c6 100644 --- a/web/app/components/workflow/comment/thread.tsx +++ b/web/app/components/workflow/comment/thread.tsx @@ -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 = memo(({ comment, loading = false, + replySubmitting = false, + replyUpdating = false, onClose, onDelete, onResolve, @@ -159,7 +163,7 @@ export const CommentThread: FC = 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 = 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 = 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 = memo(({ )} + {loading && ( +
+ {t('workflow.comments.loading')} +
+ )} {onReply && (
@@ -436,7 +445,7 @@ export const CommentThread: FC = memo(({ onSubmit={handleReplySubmit} placeholder={t('workflow.comments.placeholder.reply')} disabled={loading} - loading={loading} + loading={replySubmitting} />
diff --git a/web/app/components/workflow/hooks/use-workflow-comment.ts b/web/app/components/workflow/hooks/use-workflow-comment.ts index aa717252a8..4c2ea7548b 100644 --- a/web/app/components/workflow/hooks/use-workflow-comment.ts +++ b/web/app/components/workflow/hooks/use-workflow-comment.ts @@ -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>(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, diff --git a/web/app/components/workflow/index.tsx b/web/app/components/workflow/index.tsx index 560fa87cd2..708c9a5c1d 100644 --- a/web/app/components/workflow/index.tsx +++ b/web/app/components/workflow/index.tsx @@ -188,6 +188,8 @@ export const Workflow: FC = memo(({ pendingComment, activeComment, activeCommentLoading, + replySubmitting, + replyUpdating, handleCommentSubmit, handleCommentCancel, handleCommentIconClick, @@ -468,6 +470,8 @@ export const Workflow: FC = memo(({ key={`${comment.id}-thread`} comment={activeComment} loading={activeCommentLoading} + replySubmitting={replySubmitting} + replyUpdating={replyUpdating} onClose={handleActiveCommentClose} onResolve={() => handleCommentResolve(comment.id)} onDelete={() => handleCommentDeleteClick(comment.id)} diff --git a/web/app/components/workflow/store/workflow/comment-slice.ts b/web/app/components/workflow/store/workflow/comment-slice.ts index c0e9a7a0c0..01bc0dad29 100644 --- a/web/app/components/workflow/store/workflow/comment-slice.ts +++ b/web/app/components/workflow/store/workflow/comment-slice.ts @@ -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 setCommentDetailCache: (cache: Record) => void mentionableUsersCache: Record @@ -27,6 +31,10 @@ export const createCommentSlice: StateCreator = 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: {},