From a83aa31df7723f7d0eebbd2a3f5b71ec775cedba Mon Sep 17 00:00:00 2001 From: ValueOn AG Date: Thu, 12 Feb 2026 00:42:09 +0100 Subject: [PATCH] fixed 3 issues --- .../Messages/ChatMessages/ChatMessage.tsx | 78 +++++++++++++-- .../UiComponents/Messages/Messages.module.css | 96 ++++++++++++++++++- .../UiComponents/Messages/Messages.tsx | 6 +- .../UiComponents/Messages/MessagesTypes.ts | 6 ++ src/pages/workflows/PlaygroundPage.tsx | 4 + 5 files changed, 179 insertions(+), 11 deletions(-) diff --git a/src/components/UiComponents/Messages/ChatMessages/ChatMessage.tsx b/src/components/UiComponents/Messages/ChatMessages/ChatMessage.tsx index f62aef4..10b11cf 100644 --- a/src/components/UiComponents/Messages/ChatMessages/ChatMessage.tsx +++ b/src/components/UiComponents/Messages/ChatMessages/ChatMessage.tsx @@ -1,7 +1,8 @@ -import React from 'react'; +import React, { useState, useMemo } from 'react'; import ReactMarkdown from 'react-markdown'; import remarkGfm from 'remark-gfm'; import { FaExclamationTriangle } from 'react-icons/fa'; +import { IoIosTrash, IoIosCheckmark, IoIosClose } from 'react-icons/io'; import { Message } from '../MessagesTypes'; import { formatTimestamp } from '../MessageUtils'; import { DocumentItem, ActionInfo } from '../MessageParts'; @@ -21,6 +22,8 @@ export interface ChatMessageProps { removingFiles?: Set; downloadingFiles?: Set; workflowId?: string; + onMessageDelete?: (messageId: string) => Promise; + deletingMessages?: Set; } /** @@ -38,12 +41,36 @@ export const ChatMessage: React.FC = ({ previewingFiles, removingFiles, downloadingFiles, - workflowId + workflowId, + onMessageDelete, + deletingMessages }) => { const isUser = message.role?.toLowerCase() === 'user'; const isError = message.actionProgress === 'fail' || message.actionProgress === 'error'; const messageClass = isUser ? styles.messageUser : styles.messageAssistant; const errorClass = isError ? styles.messageError : ''; + const isDeleting = deletingMessages?.has(message.id) || false; + + // Message delete 2-click confirmation state + const [isConfirmingDelete, setIsConfirmingDelete] = useState(false); + + const handleDeleteClick = (e: React.MouseEvent) => { + e.stopPropagation(); + setIsConfirmingDelete(true); + }; + + const handleConfirmDelete = async (e: React.MouseEvent) => { + e.stopPropagation(); + setIsConfirmingDelete(false); + if (onMessageDelete && message.id) { + await onMessageDelete(message.id); + } + }; + + const handleCancelDelete = (e: React.MouseEvent) => { + e.stopPropagation(); + setIsConfirmingDelete(false); + }; return (
@@ -158,12 +185,47 @@ export const ChatMessage: React.FC = ({ {/* Action information (shown only for assistant messages) */} {!isUser && } - {/* Timestamp */} - {message.publishedAt && ( -
- {formatTimestamp(message.publishedAt)} -
- )} + {/* Timestamp and message actions */} +
+ {message.publishedAt && ( +
+ {formatTimestamp(message.publishedAt)} +
+ )} + {onMessageDelete && message.id && ( +
+ {isConfirmingDelete ? ( +
+ + +
+ ) : ( + + )} +
+ )} +
); diff --git a/src/components/UiComponents/Messages/Messages.module.css b/src/components/UiComponents/Messages/Messages.module.css index 620e4ac..6bb72c1 100644 --- a/src/components/UiComponents/Messages/Messages.module.css +++ b/src/components/UiComponents/Messages/Messages.module.css @@ -512,11 +512,17 @@ border-top-color: var(--color-gray-disabled); } +.messageFooter { + display: flex; + align-items: center; + justify-content: space-between; + margin-top: 4px; + gap: 8px; +} + .messageTimestamp { font-size: 11px; opacity: 0.7; - margin-top: 4px; - align-self: flex-end; } .messageUser .messageTimestamp { @@ -527,6 +533,92 @@ color: var(--color-gray); } +/* Message action buttons (delete) */ +.messageActions { + display: flex; + align-items: center; + opacity: 0; + transition: opacity 0.15s ease; +} + +.message:hover .messageActions { + opacity: 1; +} + +.messageDeleteBtn { + display: flex; + align-items: center; + justify-content: center; + background: none; + border: none; + cursor: pointer; + padding: 2px; + border-radius: 4px; + font-size: 14px; + color: var(--color-gray); + transition: all 0.15s ease; +} + +.messageDeleteBtn:hover { + color: var(--color-danger, #dc3545); + background: rgba(220, 53, 69, 0.1); +} + +.messageDeleteBtn:disabled { + opacity: 0.4; + cursor: not-allowed; +} + +.messageUser .messageDeleteBtn { + color: rgba(255, 255, 255, 0.6); +} + +.messageUser .messageDeleteBtn:hover { + color: #fff; + background: rgba(255, 255, 255, 0.2); +} + +/* Message delete confirmation */ +.messageDeleteConfirm { + display: flex; + align-items: center; + gap: 2px; + background: var(--color-secondary); + border-radius: 12px; + padding: 1px; +} + +.messageDeleteConfirmBtn, +.messageDeleteCancelBtn { + display: flex; + align-items: center; + justify-content: center; + background: transparent; + border: none; + cursor: pointer; + padding: 2px; + border-radius: 50%; + font-size: 16px; + color: white; + min-width: 22px; + min-height: 22px; + transition: background 0.15s ease; +} + +.messageDeleteConfirmBtn:hover { + background: rgba(255, 255, 255, 0.2); +} + +.messageDeleteCancelBtn:hover { + background: rgba(255, 255, 255, 0.2); +} + +.messageDeleteConfirmBtn:disabled, +.messageDeleteCancelBtn:disabled { + opacity: 0.4; + cursor: not-allowed; +} + .messageSummary { padding: 8px 12px; border-radius: var(--object-radius-small); diff --git a/src/components/UiComponents/Messages/Messages.tsx b/src/components/UiComponents/Messages/Messages.tsx index c58df80..dc11b61 100644 --- a/src/components/UiComponents/Messages/Messages.tsx +++ b/src/components/UiComponents/Messages/Messages.tsx @@ -24,7 +24,9 @@ const Messages: React.FC = ({ previewingFiles, removingFiles, downloadingFiles, - workflowId + workflowId, + onMessageDelete, + deletingMessages }) => { if (!messages || messages.length === 0) { return ( @@ -89,6 +91,8 @@ const Messages: React.FC = ({ removingFiles={removingFiles} downloadingFiles={downloadingFiles} workflowId={workflowId} + onMessageDelete={onMessageDelete} + deletingMessages={deletingMessages} /> ); })} diff --git a/src/components/UiComponents/Messages/MessagesTypes.ts b/src/components/UiComponents/Messages/MessagesTypes.ts index 29340b3..240f577 100644 --- a/src/components/UiComponents/Messages/MessagesTypes.ts +++ b/src/components/UiComponents/Messages/MessagesTypes.ts @@ -116,5 +116,11 @@ export interface MessagesProps { removingFiles?: Set; downloadingFiles?: Set; workflowId?: string; + + /** + * Message delete handler + */ + onMessageDelete?: (messageId: string) => Promise; + deletingMessages?: Set; } diff --git a/src/pages/workflows/PlaygroundPage.tsx b/src/pages/workflows/PlaygroundPage.tsx index abd0569..00c2d9f 100644 --- a/src/pages/workflows/PlaygroundPage.tsx +++ b/src/pages/workflows/PlaygroundPage.tsx @@ -58,6 +58,8 @@ export const PlaygroundPage: React.FC = () => { deletingFiles, previewingFiles, downloadingFiles, + handleMessageDelete, + deletingMessages, selectedProviders, onProvidersChange, } = hookData; @@ -349,6 +351,8 @@ export const PlaygroundPage: React.FC = () => { previewingFiles={previewingFiles} downloadingFiles={downloadingFiles} workflowId={workflowId} + onMessageDelete={handleMessageDelete} + deletingMessages={deletingMessages} emptyMessage="Keine Nachrichten" /> );