mirror of
https://github.com/langgenius/dify.git
synced 2026-05-04 08:26:27 +08:00
feat: use inline delete confirm for comment reply deletion(second time)
This commit is contained in:
parent
44be7d4c51
commit
0632557d91
@ -8,6 +8,7 @@ import { RiArrowDownSLine, RiArrowUpSLine, RiCheckboxCircleFill, RiCheckboxCircl
|
|||||||
import Avatar from '@/app/components/base/avatar'
|
import Avatar from '@/app/components/base/avatar'
|
||||||
import Divider from '@/app/components/base/divider'
|
import Divider from '@/app/components/base/divider'
|
||||||
import Tooltip from '@/app/components/base/tooltip'
|
import Tooltip from '@/app/components/base/tooltip'
|
||||||
|
import InlineDeleteConfirm from '@/app/components/base/inline-delete-confirm'
|
||||||
import { PortalToFollowElem, PortalToFollowElemContent, PortalToFollowElemTrigger } from '@/app/components/base/portal-to-follow-elem'
|
import { PortalToFollowElem, PortalToFollowElemContent, PortalToFollowElemTrigger } from '@/app/components/base/portal-to-follow-elem'
|
||||||
import cn from '@/utils/classnames'
|
import cn from '@/utils/classnames'
|
||||||
import { useFormatTimeFromNow } from '@/hooks/use-format-time-from-now'
|
import { useFormatTimeFromNow } from '@/hooks/use-format-time-from-now'
|
||||||
@ -31,6 +32,7 @@ type CommentThreadProps = {
|
|||||||
onReply?: (content: string, mentionedUserIds?: string[]) => Promise<void> | void
|
onReply?: (content: string, mentionedUserIds?: string[]) => Promise<void> | void
|
||||||
onReplyEdit?: (replyId: string, content: string, mentionedUserIds?: string[]) => Promise<void> | void
|
onReplyEdit?: (replyId: string, content: string, mentionedUserIds?: string[]) => Promise<void> | void
|
||||||
onReplyDelete?: (replyId: string) => void
|
onReplyDelete?: (replyId: string) => void
|
||||||
|
onReplyDeleteDirect?: (replyId: string) => Promise<void> | void
|
||||||
}
|
}
|
||||||
|
|
||||||
const ThreadMessage: FC<{
|
const ThreadMessage: FC<{
|
||||||
@ -150,6 +152,7 @@ export const CommentThread: FC<CommentThreadProps> = memo(({
|
|||||||
onReply,
|
onReply,
|
||||||
onReplyEdit,
|
onReplyEdit,
|
||||||
onReplyDelete,
|
onReplyDelete,
|
||||||
|
onReplyDeleteDirect,
|
||||||
}) => {
|
}) => {
|
||||||
const { flowToScreenPosition } = useReactFlow()
|
const { flowToScreenPosition } = useReactFlow()
|
||||||
const viewport = useViewport()
|
const viewport = useViewport()
|
||||||
@ -158,6 +161,7 @@ export const CommentThread: FC<CommentThreadProps> = memo(({
|
|||||||
const [replyContent, setReplyContent] = useState('')
|
const [replyContent, setReplyContent] = useState('')
|
||||||
const [activeReplyMenuId, setActiveReplyMenuId] = useState<string | null>(null)
|
const [activeReplyMenuId, setActiveReplyMenuId] = useState<string | null>(null)
|
||||||
const [editingReply, setEditingReply] = useState<{ id: string; content: string }>({ id: '', content: '' })
|
const [editingReply, setEditingReply] = useState<{ id: string; content: string }>({ id: '', content: '' })
|
||||||
|
const [deletingReplyId, setDeletingReplyId] = useState<string | null>(null)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setReplyContent('')
|
setReplyContent('')
|
||||||
@ -372,6 +376,9 @@ export const CommentThread: FC<CommentThreadProps> = memo(({
|
|||||||
placement='bottom-end'
|
placement='bottom-end'
|
||||||
open={activeReplyMenuId === reply.id}
|
open={activeReplyMenuId === reply.id}
|
||||||
onOpenChange={(open) => {
|
onOpenChange={(open) => {
|
||||||
|
// Don't allow closing if we're showing delete confirm
|
||||||
|
if (!open && deletingReplyId === reply.id)
|
||||||
|
return
|
||||||
if (!open)
|
if (!open)
|
||||||
setActiveReplyMenuId(null)
|
setActiveReplyMenuId(null)
|
||||||
}}
|
}}
|
||||||
@ -389,6 +396,7 @@ export const CommentThread: FC<CommentThreadProps> = memo(({
|
|||||||
className='flex h-6 w-6 items-center justify-center rounded-md text-text-tertiary hover:bg-state-base-hover hover:text-text-secondary'
|
className='flex h-6 w-6 items-center justify-center rounded-md text-text-tertiary hover:bg-state-base-hover hover:text-text-secondary'
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
|
setDeletingReplyId(null)
|
||||||
setActiveReplyMenuId(prev => prev === reply.id ? null : reply.id)
|
setActiveReplyMenuId(prev => prev === reply.id ? null : reply.id)
|
||||||
}}
|
}}
|
||||||
aria-label={t('workflow.comments.aria.replyActions')}
|
aria-label={t('workflow.comments.aria.replyActions')}
|
||||||
@ -401,21 +409,48 @@ export const CommentThread: FC<CommentThreadProps> = memo(({
|
|||||||
className='z-[100] w-36 rounded-xl border border-components-panel-border bg-components-panel-bg-blur shadow-lg backdrop-blur-[10px]'
|
className='z-[100] w-36 rounded-xl border border-components-panel-border bg-components-panel-bg-blur shadow-lg backdrop-blur-[10px]'
|
||||||
data-reply-menu
|
data-reply-menu
|
||||||
>
|
>
|
||||||
<button
|
{deletingReplyId === reply.id ? (
|
||||||
className='flex w-full items-center justify-start rounded-t-xl px-3 py-2 text-left text-sm text-text-secondary hover:bg-state-base-hover'
|
<InlineDeleteConfirm
|
||||||
onClick={() => handleStartEdit(reply)}
|
title={t('workflow.comments.actions.deleteReply')}
|
||||||
>
|
onConfirm={() => {
|
||||||
{t('workflow.comments.actions.editReply')}
|
setDeletingReplyId(null)
|
||||||
</button>
|
setActiveReplyMenuId(null)
|
||||||
<button
|
onReplyDeleteDirect?.(reply.id)
|
||||||
className='text-negative flex w-full items-center justify-start rounded-b-xl px-3 py-2 text-left text-sm text-text-secondary hover:bg-state-base-hover'
|
}}
|
||||||
onClick={() => {
|
onCancel={() => {
|
||||||
setActiveReplyMenuId(null)
|
setDeletingReplyId(null)
|
||||||
onReplyDelete?.(reply.id)
|
setActiveReplyMenuId(null)
|
||||||
}}
|
}}
|
||||||
>
|
className='m-0 w-full border-0 shadow-none'
|
||||||
{t('workflow.comments.actions.deleteReply')}
|
/>
|
||||||
</button>
|
) : (
|
||||||
|
<>
|
||||||
|
<button
|
||||||
|
className='flex w-full items-center justify-start rounded-t-xl px-3 py-2 text-left text-sm text-text-secondary hover:bg-state-base-hover'
|
||||||
|
onClick={(e) => {
|
||||||
|
e.stopPropagation()
|
||||||
|
handleStartEdit(reply)
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{t('workflow.comments.actions.editReply')}
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
className='text-negative flex w-full items-center justify-start rounded-b-xl px-3 py-2 text-left text-sm text-text-secondary hover:bg-state-base-hover'
|
||||||
|
onClick={(e) => {
|
||||||
|
e.stopPropagation()
|
||||||
|
if (onReplyDeleteDirect) {
|
||||||
|
setDeletingReplyId(reply.id)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
setActiveReplyMenuId(null)
|
||||||
|
onReplyDelete?.(reply.id)
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{t('workflow.comments.actions.deleteReply')}
|
||||||
|
</button>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</PortalToFollowElemContent>
|
</PortalToFollowElemContent>
|
||||||
</PortalToFollowElem>
|
</PortalToFollowElem>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@ -480,6 +480,7 @@ export const Workflow: FC<WorkflowProps> = memo(({
|
|||||||
onReply={(content, ids) => handleCommentReply(comment.id, content, ids ?? [])}
|
onReply={(content, ids) => handleCommentReply(comment.id, content, ids ?? [])}
|
||||||
onReplyEdit={(replyId, content, ids) => handleCommentReplyUpdate(comment.id, replyId, content, ids ?? [])}
|
onReplyEdit={(replyId, content, ids) => handleCommentReplyUpdate(comment.id, replyId, content, ids ?? [])}
|
||||||
onReplyDelete={replyId => handleCommentReplyDeleteClick(comment.id, replyId)}
|
onReplyDelete={replyId => handleCommentReplyDeleteClick(comment.id, replyId)}
|
||||||
|
onReplyDeleteDirect={replyId => handleCommentReplyDelete(comment.id, replyId)}
|
||||||
canGoPrev={canGoPrev}
|
canGoPrev={canGoPrev}
|
||||||
canGoNext={canGoNext}
|
canGoNext={canGoNext}
|
||||||
/>
|
/>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user