From 89bed479e40382e7ff9f5b39d26f3b1dd3604279 Mon Sep 17 00:00:00 2001 From: hjlarry Date: Tue, 16 Sep 2025 17:25:51 +0800 Subject: [PATCH] improve comment panel --- api/fields/workflow_comment_fields.py | 31 ++-- .../workflow/panel/comments-panel/index.tsx | 138 +++++++++++------- 2 files changed, 99 insertions(+), 70 deletions(-) diff --git a/api/fields/workflow_comment_fields.py b/api/fields/workflow_comment_fields.py index d1530b5c5f..c25c7adc5d 100644 --- a/api/fields/workflow_comment_fields.py +++ b/api/fields/workflow_comment_fields.py @@ -2,13 +2,18 @@ from flask_restful import fields from libs.helper import AvatarUrlField, TimestampField -# Basic account fields for comment creators/resolvers -comment_account_fields = {"id": fields.String, "name": fields.String, "email": fields.String} +# basic account fields for comments +account_fields = { + "id": fields.String, + "name": fields.String, + "email": fields.String, + "avatar_url": AvatarUrlField, +} # Comment mention fields workflow_comment_mention_fields = { "mentioned_user_id": fields.String, - "mentioned_user_account": fields.Nested(comment_account_fields, allow_null=True), + "mentioned_user_account": fields.Nested(account_fields, allow_null=True), "reply_id": fields.String, } @@ -17,18 +22,10 @@ workflow_comment_reply_fields = { "id": fields.String, "content": fields.String, "created_by": fields.String, - "created_by_account": fields.Nested(comment_account_fields, allow_null=True), + "created_by_account": fields.Nested(account_fields, allow_null=True), "created_at": TimestampField, } -# Participant info for showing avatars -workflow_comment_participant_fields = { - "id": fields.String, - "name": fields.String, - "email": fields.String, - "avatar_url": AvatarUrlField, -} - # Basic comment fields (for list views) workflow_comment_basic_fields = { "id": fields.String, @@ -36,16 +33,16 @@ workflow_comment_basic_fields = { "position_y": fields.Float, "content": fields.String, "created_by": fields.String, - "created_by_account": fields.Nested(comment_account_fields, allow_null=True), + "created_by_account": fields.Nested(account_fields, allow_null=True), "created_at": TimestampField, "updated_at": TimestampField, "resolved": fields.Boolean, "resolved_at": TimestampField, "resolved_by": fields.String, - "resolved_by_account": fields.Nested(comment_account_fields, allow_null=True), + "resolved_by_account": fields.Nested(account_fields, allow_null=True), "reply_count": fields.Integer, "mention_count": fields.Integer, - "participants": fields.List(fields.Nested(workflow_comment_participant_fields)), + "participants": fields.List(fields.Nested(account_fields)), } # Detailed comment fields (for single comment view) @@ -55,13 +52,13 @@ workflow_comment_detail_fields = { "position_y": fields.Float, "content": fields.String, "created_by": fields.String, - "created_by_account": fields.Nested(comment_account_fields, allow_null=True), + "created_by_account": fields.Nested(account_fields, allow_null=True), "created_at": TimestampField, "updated_at": TimestampField, "resolved": fields.Boolean, "resolved_at": TimestampField, "resolved_by": fields.String, - "resolved_by_account": fields.Nested(comment_account_fields, allow_null=True), + "resolved_by_account": fields.Nested(account_fields, allow_null=True), "replies": fields.List(fields.Nested(workflow_comment_reply_fields)), "mentions": fields.List(fields.Nested(workflow_comment_mention_fields)), } diff --git a/web/app/components/workflow/panel/comments-panel/index.tsx b/web/app/components/workflow/panel/comments-panel/index.tsx index 4154b772cd..c2fbc1e903 100644 --- a/web/app/components/workflow/panel/comments-panel/index.tsx +++ b/web/app/components/workflow/panel/comments-panel/index.tsx @@ -1,6 +1,6 @@ import { memo, useCallback, useMemo, useState } from 'react' import { useReactFlow } from 'reactflow' -import { RiCheckboxCircleFill, RiCheckboxCircleLine, RiCloseLine } from '@remixicon/react' +import { RiCheckLine, RiCheckboxCircleFill, RiCheckboxCircleLine, RiCloseLine, RiFilter3Line } from '@remixicon/react' import { useStore } from '@/app/components/workflow/store' import type { WorkflowCommentList } from '@/service/workflow-comment' import { useWorkflowComment } from '@/app/components/workflow/hooks/use-workflow-comment' @@ -10,6 +10,7 @@ import { ControlMode } from '@/app/components/workflow/types' import { resolveWorkflowComment } from '@/service/workflow-comment' import { useParams } from 'next/navigation' import { useFormatTimeFromNow } from '@/app/components/workflow/hooks' +import { useAppContext } from '@/context/app-context' const CommentsPanel = () => { const activeCommentId = useStore(s => s.activeCommentId) @@ -21,7 +22,8 @@ const CommentsPanel = () => { const appId = params.appId as string const { formatTimeFromNow } = useFormatTimeFromNow() - const [filter, setFilter] = useState<'all' | 'unresolved'>('all') + const [filter, setFilter] = useState<'all' | 'unresolved' | 'mine'>('all') + const [showFilter, setShowFilter] = useState(false) const handleSelect = useCallback((comment: WorkflowCommentList) => { // center viewport on the comment position and activate it @@ -29,12 +31,16 @@ const CommentsPanel = () => { setActiveCommentId(comment.id) }, [reactFlow, setActiveCommentId]) + const { userProfile } = useAppContext() + const filteredSorted = useMemo(() => { let data = comments if (filter === 'unresolved') data = data.filter(c => !c.resolved) + else if (filter === 'mine') + data = data.filter(c => c.created_by === userProfile?.id) return data - }, [comments, filter]) + }, [comments, filter, userProfile?.id]) const handleResolve = useCallback(async (comment: WorkflowCommentList) => { if (comment.resolved) return @@ -49,24 +55,48 @@ const CommentsPanel = () => { } }, [appId, loadComments, setActiveCommentId]) + const handleFilterChange = useCallback((value: 'all' | 'unresolved' | 'mine') => { + setFilter(value) + setShowFilter(false) + }, []) + return ( -
+
Comments
-
-
+ - -
+ + + {showFilter && ( +
+ + + +
+ )}
{ @@ -78,13 +108,13 @@ const CommentsPanel = () => {
-
+
{filteredSorted.map((c) => { const isActive = activeCommentId === c.id return (
handleSelect(c)} >
@@ -103,50 +133,52 @@ const CommentsPanel = () => { const visibleUsers = all.slice(0, maxVisible) const remainingCount = all.length - maxVisible return ( -
- {visibleUsers.map((p, index) => ( -
- +
+ {visibleUsers.map((p, index) => ( +
+ +
+ ))} + {remainingCount > 0 && ( +
+ +{remainingCount} +
+ )} +
+
+ {c.resolved ? ( + + ) : ( + handleResolve(c)} /> -
- ))} - {remainingCount > 0 && ( -
- +{remainingCount} -
- )} + )} +
) })()} - {/* Header row: creator + time + right-top status/action icons */} -
+ {/* Header row: creator + time */} +
{c.created_by_account.name}
{formatTimeFromNow(c.updated_at * 1000)}
-
- {c.resolved ? ( - - ) : ( - { handleResolve(c) }} - /> - )} -
{/* Content */}
{c.content}